热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

Asp.NetCore轻松学之利用日志监视进行服务遥测详解

这篇文章主要给大家介绍了关于Asp.NetCore轻松学之利用日志监视进行服务遥测的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起看看吧

前言

在 Net Core 2.2 中,官方文档表示,对 EventListener 这个日志监视类的内容进行了扩充,同时赋予了跟踪 CoreCLR 事件的权限;通过跟踪 CoreCLR 事件,比如通过跟踪 CoreCLR 事件,可以了解和收集到比如 GC,JIT,ThreadPool,intreop 这些运行时服务的行为;通过使用配置注入,我们将获得一种动态跟踪事件的能力。

1. EventListener 介绍

1.1 EventListener 中文直译为:事件侦听器

EventListener 位于程序集 System.Diagnostics.Tracing 中,该类提供了一组启用/禁用的方法,按照惯例,先来看一下源代码,了解一下其结构

 public abstract class EventListener : IDisposable
 {
 protected EventListener();

 public event EventHandler EventSourceCreated;
 
 public event EventHandler EventWritten;

 protected static int EventSourceIndex(EventSource eventSource);
 
 public void DisableEvents(EventSource eventSource);
 
 public virtual void Dispose();
 
 public void EnableEvents(EventSource eventSource, EventLevel level);
 
 public void EnableEvents(EventSource eventSource, EventLevel level, EventKeywords matchAnyKeyword);
 
 protected internal virtual void OnEventWritten(EventWrittenEventArgs eventData);
 }

从类结构中可以看出,EventListener 中的方法并不多,而且从名字都可以推断出其行为,
因为该类是一个抽象类,并不能直接使用,接下来我们创建一个 ReportListener 类继承它

2. 创建自定义事件侦听器

 public class ReportListener : EventListener
 {
  public ReportListener() { }

  public Dictionary Items { get; set; } = new Dictionary();
  public ReportListener(Dictionary items)
  {
   this.Items = items;
  }

  protected override void OnEventSourceCreated(EventSource eventSource)
  {
   if (Items.ContainsKey(eventSource.Name))
   {
    var item = Items[eventSource.Name];
    EnableEvents(eventSource, item.Level, item.Keywords);
   }
  }

  protected override void OnEventWritten(EventWrittenEventArgs eventData)
  {
   if (Items.ContainsKey(eventData.EventSource.Name))
   {
    Console.WriteLine($"ThreadID = {eventData.OSThreadId} ID = {eventData.EventId} Name = {eventData.EventSource.Name}.{eventData.EventName}");
    for (int i = 0; i 

ReportListener 自定义事件侦听器的代码非常简单,只是简单的继承了 EventListener 后,重写了父类的两个方法:创建事件和写入事件

同时,还定义了一个公共属性 Dictionary Items ,该属性接受一个 ListenerItem 的跟踪配置集,通过配置文件注入,动态觉得哪些事件可以被写入到侦听器中

3. 配置跟踪项目

在配置文件 appsettings.json 中增加以下内容

{
 "listener": [
 {
  "name": "HomeEventSource",
  "level": 5,
  "keywords": -1
 }
 ]
}

配置说明

上面的配置文件表示,定义一个事件源对象(EventSource),名称为 HomeEventSource,事件级别(EventLevel)为 5,关键字(EventKeywords)为 -1

关于事件级别和事件关键字的值,和系统定义的一致

3.1 事件级别定义

namespace System.Diagnostics.Tracing
{
 public enum EventLevel
 {
  LogAlways = 0,
  Critical = 1,
  Error = 2,
  Warning = 3,
  InformatiOnal= 4,
  Verbose = 5
 }
}

3.2 事件关键字定义

namespace System.Diagnostics.Tracing
{
 [Flags]
 public enum EventKeywords : long
 {
  All = -1,
  NOne= 0,
  WdiCOntext= 562949953421312,
  MicrosoftTelemetry = 562949953421312,
  WdiDiagnostic = 1125899906842624,
  Sqm = 2251799813685248,
  AuditFailure = 4503599627370496,
  CorrelatiOnHint= 4503599627370496,
  AuditSuccess = 9007199254740992,
  EventLogClassic = 36028797018963968
 }
}

3.3 配置文件完全按照系统值定义,为了更好的使用配置文件,我们定义了下面的实体类

 public class ListenerItem
 {
  public string Name { get; set; }
  public EventLevel Level { get; set; } = EventLevel.Verbose;
  public EventKeywords Keywords { get; set; } = EventKeywords.All;
 }

4. 开始使用事件侦听器

为了在应用程序中使用事件侦听器,我们需要初始化事件侦听器,你可以初始化多个事件侦听器;但是,每个事件侦听器仅需要初始化一次即可

4.1 初始化自定义事件侦听器,在 Startup.cs 文件中加入以下代码

  public void AddEventListener(IServiceCollection services)
  {
   var listeners = this.Configuration.GetSection("listener").Get>();
   Dictionary dict = new Dictionary();
   if (listeners != null)
   {
    foreach (var item in listeners)
    {
     dict.Add(item.Name, item);
    }
   }
   var report = new ReportListener(dict);
   services.AddSingleton(report);
  }

  public void ConfigureServices(IServiceCollection services)
  {
   AddEventListener(services);
   services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  }

初始化动作非常简单,仅是从配置文件中读取需要跟踪的项,然后注册到 ReportListener 内部即可,为了演示事件的注册,我们需要创建一个事件源,就像配置文件中的名称 HomeEventSource

4.2 创建自定义的事件源对象

 public class HomeEventSource : EventSource
 {
  public static HomeEventSource Instance = new HomeEventSource();

  [Event(1001)]
  public void RequestStart(string message) => WriteEvent(1001, message);

  [Event(1002)]
  public void RequestStop(string message) => WriteEvent(1002, message);
 }

自定义事件源 HomeEventSource 继承自 EventSource,我们可无需为该自定义事件源进行显式命名,因为默认将会使用 HomeEventSource 类名进行注册事件

现在,我们尝试着 HomeController 去生产一个事件,看看效果

5. 生产事件

5.1 转到 HomeController,在 HomeController 的 Get 方法中使用 HomeEventSource 生产两个事件

 [Route("api/[controller]")]
 [ApiController]
 public class HomeController : ControllerBase
 {
  [HttpGet]
  public ActionResult> Get()
  {
   HomeEventSource.Instance.RequestStart("处理业务开始");
   var arra = new string[] { "value1", "value2" };
   HomeEventSource.Instance.RequestStop("处理业务结束");
   return arra;
  }
 }

5.2 回顾一下自定义事件侦听器 ReportListener 的重写方法

  protected override void OnEventSourceCreated(EventSource eventSource)
  {
   if (Items.ContainsKey(eventSource.Name))
   {
    var item = Items[eventSource.Name];
    EnableEvents(eventSource, item.Level, item.Keywords);
   }
  }

  protected override void OnEventWritten(EventWrittenEventArgs eventData)
  {
   if (Items.ContainsKey(eventData.EventSource.Name))
   {
    Console.WriteLine($"ThreadID = {eventData.OSThreadId} ID = {eventData.EventId} Name = {eventData.EventSource.Name}.{eventData.EventName}");
    for (int i = 0; i 

由于我们做配置文件中指定了必须是 HomeEventSource 事件源才启用事件,所以上面的代码表示,当一个 HomeEventSource 事件进入的时候,将事件的内容打印到控制台,实际应用中,你可以将这些信息推送到日志订阅服务器,以方便跟踪和汇总

5.3 运行程序,看看输出结果如何

可以看到,事件生产成功,实际上,CoreCLR 内部生产了非常多的事件,下面我们尝试启用以下 3 个事件源,预期将会收到大量的事件信息

5.4 尝试更多事件源

  protected override void OnEventSourceCreated(EventSource eventSource)
  {
   if (eventSource.Name.Equals("Microsoft-Windows-DotNETRuntime"))
   {
    EnableEvents(eventSource, EventLevel.Verbose, EventKeywords.AuditFailure);
   }

   else if (eventSource.Name.Equals("System.Data.DataCommonEventSource"))
   {
    EnableEvents(eventSource, EventLevel.Verbose, EventKeywords.AuditFailure);
   }

   else if (eventSource.Name.Equals("Microsoft-AspNetCore-Server-Kestrel"))
   {
    EnableEvents(eventSource, EventLevel.Verbose, EventKeywords.AuditFailure);
   }
  }

5.5 再次运行程序,看下图输出结果

从图中可以看出,这次我们跟踪到了 Microsoft-AspNetCore-Server-Kestrel 事件源生产的开始和结束连接事件

结束语

  • 在 CoreCLR 的事件总线中,包含了千千万万的事件源生产的事件,以上的实验只是冰山一角,如果你把创建事件源的 EventKeywords 指定为 All,你将会看到天量的日志信息,但是,在这里,友情提示大家,千万不要这样做,这种做法会对服务性能带来极大损害
  • 在业务代码中,写入大量的调试日志是不可取的,但是使用事件侦听器,可以控制事件的创建和写入,当需要对某个接口进行监控的时候,通过将需要调试的事件源加入配置文件中进行监控,这将非常有用

示例代码下载:http://xiazai.jb51.net/201812/yuanma/Ron.ListenerDemo_jb51.rar

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。


推荐阅读
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文介绍了在Hibernate配置lazy=false时无法加载数据的问题,通过采用OpenSessionInView模式和修改数据库服务器版本解决了该问题。详细描述了问题的出现和解决过程,包括运行环境和数据库的配置信息。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • 在Android中解析Gson解析json数据是很方便快捷的,可以直接将json数据解析成java对象或者集合。使用Gson解析json成对象时,默认将json里对应字段的值解析到java对象里对应字段的属性里面。然而,当我们自己定义的java对象里的属性名与json里的字段名不一样时,我们可以使用@SerializedName注解来将对象里的属性跟json里字段对应值匹配起来。本文介绍了使用@SerializedName注解解析json数据的方法,并给出了具体的使用示例。 ... [详细]
  • 本文介绍了一个React Native新手在尝试将数据发布到服务器时遇到的问题,以及他的React Native代码和服务器端代码。他使用fetch方法将数据发送到服务器,但无法在服务器端读取/获取发布的数据。 ... [详细]
  • Node.js学习笔记(一)package.json及cnpm
    本文介绍了Node.js中包的概念,以及如何使用包来统一管理具有相互依赖关系的模块。同时还介绍了NPM(Node Package Manager)的基本介绍和使用方法,以及如何通过NPM下载第三方模块。 ... [详细]
  • express工程中的json调用方法
    本文介绍了在express工程中如何调用json数据,包括建立app.js文件、创建数据接口以及获取全部数据和typeid为1的数据的方法。 ... [详细]
  • SpringMVC工作流程概述
    SpringMVC工作流程概述 ... [详细]
  • ps:写的第一个,不足之处,欢迎拍砖---只是想用自己的方法一步步去实现一些框架看似高大上的小功能(比如说模型中的toArraytoJsonsetAtt ... [详细]
  • Django + Ansible 主机管理(有源码)
    本文给大家介绍如何利用DjangoAnsible进行Web项目管理。Django介绍一个可以使Web开发工作愉快并且高效的Web开发框架,能够以最小的代价构建和维护高 ... [详细]
author-avatar
包括萨u盾根本_173
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有