在 .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日

相关文章

  • 使用Java进行图像处理的一些基础操作

    下面我来详细讲解“使用Java进行图像处理的一些基础操作”的完整攻略。 一、准备工作 要使用Java进行图像处理,我们需要使用一个Java提供的图形库——Java AWT(Abstract Window Toolkit)。该库提供了一些基础的图像处理功能。 我们需要在代码中引入下面的库: import java.awt.*; import java.awt.…

    人工智能概览 2023年5月25日
    00
  • python OpenCV的imread不能读取中文路径问题及解决

    首先我们需要了解一下imread函数在读取图片时的路径解析规则。在Windows平台上,OpenCV默认使用GBK编码解析文件路径,而不是UTF-8。这就导致了中文路径在使用imread函数读取时可能会出现问题。 解决方法有两种: 1. 使用raw string 将中文路径使用raw string(在字符串前加上r)的方式来解决。 import cv2 im…

    人工智能概览 2023年5月25日
    00
  • 使用MDC实现日志链路跟踪

    使用MDC(Mapped Diagnostic Context)实现日志链路跟踪可以帮助我们在多线程或分布式环境下更加方便地追踪日志,这里给出一份完整的攻略。 什么是MDC MDC是log4j日志系统中的一个特性,可以让我们通过一个类似于ThreadLocal的方式轻松地保存和传递上下文信息。在MDC中,我们可以将一个key-value的配对以map的形式保…

    人工智能概览 2023年5月25日
    00
  • OpenCV实现特征检测和特征匹配方法汇总

    OpenCV实现特征检测和特征匹配方法汇总 本文将介绍使用OpenCV实现特征检测和特征匹配的方法汇总。 特征检测 特征检测是基于图像对应的变化来寻找图像中的关键点的过程,这些关键点可以用来描述图像。OpenCV支持几种特征检测算法,包括:Harris Corner Detection、Shi-Tomasi Corner Detection、SIFT、SUR…

    人工智能概论 2023年5月25日
    00
  • Python操作MongoDB增删改查代码示例

    下面是Python操作MongoDB增删改查的完整攻略: 1. 安装pymongo 在Python中操作MongoDB,需要先安装pymongo模块。可以使用pip命令进行安装: pip install pymongo 2. 连接MongoDB 连接MongoDB需要使用pymongo.MongoClient()方法,代码示例如下: from pymongo…

    人工智能概论 2023年5月25日
    00
  • Python获取Linux系统下的本机IP地址代码分享

    下面我将为您详细讲解如何在Python中获取Linux系统下的本机IP地址。 步骤一:导入必要的模块 获取Linux系统下的本机IP地址需要使用到Python的socket模块,因此我们需要先导入该模块。在Python中,可以使用以下语句导入socket模块: import socket 步骤二:通过socket模块获取本机IP地址 有两种方法可以通过soc…

    人工智能概览 2023年5月25日
    00
  • python 生成图形验证码的方法示例

    生成图形验证码是一个较为常见的需求,Python提供了丰富的模块支持我们生成图形验证码。 下面我将详细讲解如何使用Python生成图形验证码。 1. 安装 Pillow 模块 Pillow是一个图形处理库,它支持Python 3.x。使用Pillow模块可以轻松创建和操作图片: pip install Pillow 2. 生成验证码字符串 首先需要生成验证码…

    人工智能概览 2023年5月25日
    00
  • Eclipse配置python开发环境过程图解

    下面是“Eclipse配置python开发环境过程图解”的完整攻略。 1. 下载并安装Eclipse和PyDev插件 前往Eclipse官网(https://www.eclipse.org/downloads/)下载适合你操作系统的版本,然后安装。安装完成后,启动Eclipse,进入菜单“Help” – “Eclipse MarketPlace”,搜索关键字…

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