在 .NET Core 中使用 Diagnostics (Diagnostic Source) 记录跟踪信息

在 .NET Core 中,我们可以使用 Diagnostics(Diagnostic Source)来自定义记录跟踪信息。其主要原理是,在关键时刻发送一个事件,将事件传递给监听器,从而实现跟踪记录。整个流程可以分为三个步骤:

  1. 定义属性事件源

Diagnostics 中的每个事件源都需要定义一个类,在这个类中,我们可以定义多个属性来描述该事件。假设我们要在示例中记录控制器的请求信息,事件源类可能如下所示:

public class ControllerSource : DiagnosticSource 
{ 
    public static ControllerSource Log = new ControllerSource(); 

    private ControllerSource() : base("Demo-Controller") { } 

    public void RequestStart(HttpContext context) 
    { 
        if (this.IsEnabled("RequestStart")) 
        { 
            this.Write("RequestStart", context); 
        } 
    } 

    public void RequestStop(HttpContext context) 
    { 
        if (this.IsEnabled("RequestStop")) 
        { 
            this.Write("RequestStop", context); 
        } 
    } 
} 

在上面的代码中,我们定义了一个名为ControllerSource的属性事件源,它继承了DiagnosticSource类。在类的构造函数中,我们传入了该事件源的名称,它将用作日志记录器的名称。然后,我们定义了两个RequestStartRequestStop方法,它们将在日志记录器事件中被使用。IsEnabled方法用于检测事件是否可用,Write方法则用于写入日志。

  1. 确认监听器

在记录跟踪信息之前,我们需要在我们的应用程序中定义一个监听器。我们可以使用以下代码定义一个基于控制台输出的监听器:

public class ConsoleDiagnosticListener : IObserver<DiagnosticListener> 
{ 
    private IDisposable subscription; 

    public void OnCompleted() { } 

    public void OnError(Exception error) { } 

    public void OnNext(DiagnosticListener diagnosticListener) 
    { 
        if (diagnosticListener.Name == "Demo-Controller") 
        { 
            this.subscription = diagnosticListener.Subscribe(new ConsoleDiagnosticObserver()); 
        } 
    } 

    public void Dispose() => this.subscription.Dispose(); 
} 

public class ConsoleDiagnosticObserver : IObserver<KeyValuePair<string, object>> 
{ 
    public void OnCompleted() { } 

    public void OnError(Exception error) { } 

    public void OnNext(KeyValuePair<string, object> value) 
    { 
        Console.WriteLine($"[ {value.Key} ] {value.Value}"); 
    } 
} 

上述代码中,我们首先定义了一个名为ConsoleDiagnosticListener的类,它实现了接口IObserver<DiagnosticListener>,它将跟踪日志记录器的所有事件。在方法OnNext中,我们筛选了名称为Demo-Controller的日志记录器,当它被使用时,我们定了一个ConsoleDiagnosticObserver的实例,这个实例将负责把日志记录到控制台中来。

  1. 触发事件

现在,在程序运行时,我们需要触发RequestStartRequestStop事件,这将为ControllerSource创建一个新的跟踪片段,并将其发送给监听器。示例代码可能如下所示:

public class HomeController : Controller 
{ 
    private readonly ControllerSource controllerSource; 

    public HomeController() 
    { 
        this.controllerSource = ControllerSource.Log; 
    } 

    public IActionResult Index() 
    { 
        var result = this.controllerSource.RequestStart(this.HttpContext); 

        ...  //do something 

        this.controllerSource.RequestStop(this.HttpContext); 

        return View(); 
    } 
} 

在上面的代码中,我们首先注入了ControllerSource,它将用于记录跟踪的信息。然后,在请求开始时,我们调用RequestStart方法,在请求结束时调用RequestStop方法。

示例:记录 EF Core 数据库查询

另一个示例是记录 EF Core 中的数据库查询。在这个例子中,我们还将添加一个名为ActivitySource的事件源,用于处理活动跟踪 ID。

  1. 定义属性事件源

定义一个EntityFrameworkSource类,用于记录 EF Core 中的关键事件。

public class EntityFrameworkSource : DiagnosticSource 
{ 
    private EntityFrameworkSource() : base("Demo-EFCore") { } 

    public static readonly EntityFrameworkSource Instance = new EntityFrameworkSource(); 

    public Activity MapToActivity(QueryTrackingBehavior queryTrackingBehavior, Guid relatedActivityId, string commandText, IEnumerable<KeyValuePair<string, object>> parameters) 
    { 
        var activity = new Activity("EF-Query"); 
        activity.SetParentId(relatedActivityId); 
        activity.SetTag("CommandText", commandText); 
        activity.SetTag("Parameters", JsonConvert.SerializeObject(parameters)); 
        activity.Start(); 

        activity.AddTag("TrackingBehavior", queryTrackingBehavior.ToString()); 
        activity.AddEvent(new ActivityEvent("ExecuteCommand")); 

        return activity; 
    } 
} 

在上述代码中,我们定义了一个名为EntityFrameworkSource的事件源,并为其添加了MapToActivity方法。这个方法将用于将 EF Core 查询映射到活动跟踪 ID 上。

  1. 确认监听器

定义一个基于日志的监听器,也可以使用控制台监听器。示例中我们使用了基于日志的监听器。

private class EntityFrameworkDiagnosticObserver : IObserver<KeyValuePair<string, object>> 
{ 
    private readonly ILogger<EntityFrameworkDiagnosticObserver> logger; 

    public EntityFrameworkDiagnosticObserver(ILogger<EntityFrameworkDiagnosticObserver> logger) => this.logger = logger; 

    public void OnCompleted() { } 

    public void OnError(Exception error) => this.logger.LogError(error, "Error on entity framework diagnostic observer"); 

    public void OnNext(KeyValuePair<string, object> value) 
    { 
        if (value.Key == "Microsoft.EntityFrameworkCore.Database.Command.CommandExecuted") 
        { 
            Guid.TryParse(value.Value.GetType().GetProperty("ActivityId") ?.GetValue(value.Value).ToString(), out Guid activityId); 

            var command = value.Value.GetType().GetProperty("CommandText") ?.GetValue(value.Value).ToString(); 
            QueryTrackingBehavior.TryParse(value.Value.GetType().GetProperty("QueryTrackingBehavior") ?.GetValue(value.Value).ToString(), out QueryTrackingBehavior queryTrackingBehavior); 

            var parameters = new List<KeyValuePair<string, object>>(); 
            var dbParameterChoiceType = typeof(Microsoft.EntityFrameworkCore.Storage.RelationalParameter); 
            var dbParameterDictionary = (IDictionary)(value.Value.GetType().GetProperty("Parameters") ?.GetValue(value.Value)); 

            foreach (var key in dbParameterDictionary.Keys) 
            { 
                var param = dbParameterDictionary[key]; 

                parameters.Add(new KeyValuePair<string, object>( 
                    param.GetType().GetProperty("InvariantName") ?.GetValue(param).ToString(), 
                    param.GetType().GetProperty("Value") ?.GetValue(param))); 
            } 

            EntityFrameworkSource.Instance.MapToActivity(queryTrackingBehavior, activityId, command, parameters) ?.Dispose(); 
        } 
    } 
} 

private class EntityFrameworkDiagnosticListener : IObserver<DiagnosticListener> 
{ 
    private readonly ILogger<EntityFrameworkDiagnosticListener> logger; 
    private IDisposable subscription; 

    public EntityFrameworkDiagnosticListener(ILogger<EntityFrameworkDiagnosticListener> logger) => this.logger = logger; 

    public void OnCompleted() { } 

    public void OnError(Exception error) => this.logger.LogError(error, "Error on entity framework diagnostic listener"); 

    public void OnNext(DiagnosticListener listener) 
    { 
        if (listener.Name == "Microsoft.EntityFrameworkCore") 
        { 
             this.subscription = listener.Subscribe(new EntityFrameworkDiagnosticObserver(logger)); 
        } 
    } 
} 

在上述代码中,我们定义了两个类:EntityFrameworkDiagnosticObserverEntityFrameworkDiagnosticListener,用于监听 EF Core 中的数据库命令执行事件。当事件发生时,我们可以将它们转换为一个新的Activity,并将其记录到日志中。

  1. 触发事件

在 EF Core 执行数据库命令时将会触发数据库命令执行事件。

using (var scope = this.dbContext.ContextLogger.BeginScope("DB"))
{ 
    this.dbContext.Organization.Add(entity); 
    this.dbContext.SaveChanges(); 
} 

在上述代码中,我们调用了ContextLogger.BeginScope方法。这个方法将创建一个新的作用域,并将在作用域中执行所有的 EF Core 查询。我们可以在监听器中查看这些事件,并将它们映射到一个新的Activity中。

至此,我们就可以通过 Diagnostics 在 .NET Core中记录跟踪信息了。但为了在实践中更好的运用这些工具,我们还需要更多的学习和实践。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:在 .NET Core 中使用 Diagnostics (Diagnostic Source) 记录跟踪信息 - Python技术站

(0)
上一篇 2023年5月25日
下一篇 2023年5月25日

相关文章

  • Python下应用opencv 实现人脸检测功能

    Python下应用OpenCV实现人脸检测功能 前言 OpenCV是计算机视觉领域中一个非常常用且广受欢迎的开源库,它提供了丰富的算法和工具函数,可以帮助我们快速搭建计算机视觉应用。其中,人脸检测功能是一个十分实用的应用领域,可以用于人脸识别、智能安防等领域。 本篇文章将会介绍如何使用Python下的OpenCV库,通过自带的分类器实现人脸检测的功能。 安装…

    人工智能概览 2023年5月25日
    00
  • windows安装mongodb6.x并设置用户名密码的详细过程

    下面是详细讲解“Windows安装MongoDB6.x并设置用户名密码的详细过程”的完整攻略。 安装MongoDB6.x 打开MongoDB官网(https://www.mongodb.com/),在页面右上角点击“Get MongoDB”进入下载页面。 在下载页面中选择“Community Server”,根据系统版本选择下载对应的安装包。在下载过程中,需…

    人工智能概览 2023年5月25日
    00
  • 关于go-zero服务自动收集问题分析

    简介 Go-zero是一种基于Golang的微服务框架,提供很多便捷的工具和模块。其中,go-zero的服务自动收集问题分析是一种非常实用的功能,可以监控和收集服务的异常情况,支持对异常情况进行可视化展示和报警通知,对于服务的稳定运行和故障排除都有很大的帮助。 实现步骤 2.1 安装go-zero工具包和依赖包 首先需要安装go-zero工具包,并安装go-…

    人工智能概览 2023年5月25日
    00
  • Python Django模板之模板过滤器与自定义模板过滤器示例

    Python Django模板之模板过滤器与自定义模板过滤器示例 什么是模板过滤器? 模板过滤器是Django模板语言中的一种特殊的模板标签,用于对模板变量进行处理和转换。使用模板过滤器可以在模板渲染时对变量进行格式化、编码、截断等操作,从而更好的展示页面内容。 模板过滤器通常在模板变量后使用,使用竖线“|”隔开,例如:{{variable|filter}}…

    人工智能概览 2023年5月25日
    00
  • Java图像处理工具类

    Java图像处理工具类攻略 1. 前言 随着数字图像的流行,在许多行业中都需要使用图像处理技术,这也促使了许多程序员开始研究如何使用Java对数字图像进行处理。但是,处理数字图像需要大量的代码和算法,因此一个能够集成常用图像处理算法的工具类是必不可少的。在本文中,我们将探讨如何使用Java图像处理工具类来处理数字图像。 2. Java图像处理工具类 Java…

    人工智能概览 2023年5月25日
    00
  • 关于mongoose连接mongodb重复访问报错的解决办法

    下面是关于mongoose连接mongodb重复访问报错的解决办法的完整攻略。 核心问题 在使用mongoose连接MongoDB时,如果连接多次,就会出现”MongoError: Too many open connections”的错误。这个错误是由于MongoDB客户端库默认开启了最大连接数限制,当超出限制时就会报错。因此,我们需要找到一种方法来解决这…

    人工智能概论 2023年5月25日
    00
  • Django通过json格式收集主机信息

    下面就为大家详细讲解一下Django如何通过json格式收集主机信息的完整攻略: 1. 确定主机信息收集的方式 首先需要确定主机信息收集的方式。可以借助第三方工具比如ansible、saltstack等进行信息收集,也可以编写脚本通过ssh协议获取。这里以编写脚本通过ssh获取主机信息的方式进行说明。 2. 定义json格式 为了收集主机信息后方便进行存储和…

    人工智能概论 2023年5月25日
    00
  • 易语言调用接口来实现机器人聊天的功能

    下面我将详细讲解“易语言调用接口来实现机器人聊天的功能”的完整攻略。 1. 简介 在易语言中,我们可以通过调用与机器人聊天相关的接口来实现聊天功能。常用的机器人平台包括图灵机器人、茉莉机器人等。在使用之前,我们需要先在机器人平台中注册账号并获取相应的API Key。 2. 调用图灵机器人接口实现聊天功能 接下来以图灵机器人为例,介绍如何在易语言中调用接口来实…

    人工智能概论 2023年5月25日
    00
合作推广
合作推广
分享本页
返回顶部