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

yizhihongxing

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

相关文章

  • C语言求连续最大子数组和的方法

    C语言求连续最大子数组和,是一个经典的算法问题,通常可以有多种不同的实现方式。下面,我将分享一种基于动态规划的解法,并且给出两个示例以帮助解释。 1. 动态规划法 动态规划是一种常用的解决优化问题的算法。对于本题,基本思路是对于前n个数,分别计算以第i个数结尾的最大子数组和,然后再取其中的最大值。 以数组nums = {1, -2, 3, 10, -4, 7…

    人工智能概览 2023年5月25日
    00
  • Node.js的Web模板引擎ejs的入门使用教程

    什么是模板引擎? 在 Node.js 开发中,我们通常需要把数据渲染到一个 HTML 页面中展示给用户,这就需要一个模板引擎。模板引擎是将数据和模板进行组合,生成的最终的 HTML 页面。ejs 是 Node.js 中最流行的一种模板引擎。 安装 ejs 在 Node.js 中安装 ejs 最简单的方法是使用 npm 包管理器,在命令行中输入以下命令安装 e…

    人工智能概览 2023年5月25日
    00
  • pytorch 批次遍历数据集打印数据的例子

    下面是“PyTorch批次遍历数据集打印数据的例子”的完整攻略。 1. 背景知识 在使用PyTorch进行深度学习任务时,数据预处理是非常重要的一步。其中一个重要操作是遍历数据集,并对每批数据进行处理。PyTorch中提供了DataLoader类来完成这个过程。 DataLoader类可以方便地加载并行处理数据集,支持多线程数据加载。同时,它还可以对数据进行…

    人工智能概论 2023年5月25日
    00
  • Python Opencv基于透视变换的图像矫正

    下面是基于透视变换的图像矫正的完整攻略。 概述 在某些情况下,图像会因为多种因素导致出现透视扭曲,这时需要对图像进行矫正。OpenCV是一款开源的计算机视觉库,在其中包含了很多图像矫正相关的函数,其中就包括基于透视变换的图像矫正。 基本原理 透视变换是指在三维空间中进行投影变换的过程。在图像中,我们可以利用四个点确定一个矩形区域,进而通过透视变换把这个区域变…

    人工智能概论 2023年5月24日
    00
  • CentOS中Git客户端的安装和基础配置教程

    下面我会为您详细讲解“CentOS中Git客户端的安装和基础配置教程”的完整攻略。 安装Git客户端 在CentOS中安装Git客户端非常简单,您只需要在终端中输入以下命令即可: sudo yum install git 等待安装完成后,您可以输入以下命令验证Git版本是否正确: git –version 如果显示Git的版本号,则表示Git客户端已经成功…

    人工智能概论 2023年5月25日
    00
  • go语言入门环境搭建及GoLand安装教程详解

    Go语言入门环境搭建及GoLand安装教程详解 概述 Go语言是Google公司推出的一种新型编程语言,具有并发,高性能等特性,因此备受开发者青睐。本文将详细讲解如何搭建Go语言的开发环境和安装GoLand等开发工具。 步骤一:安装Go语言环境 下载Go语言环境安装包 在官网(https://golang.org/dl/)下载对应操作系统的安装包,推荐下载稳…

    人工智能概论 2023年5月25日
    00
  • Python脚本简单实现打开默认浏览器登录人人和打开QQ的方法

    实现打开默认浏览器登录人人和打开QQ的方法,需要用到Python的webbrowser和selenium库。 使用webbrowser库打开默认浏览器 webbrowser库提供了一个让Python程序控制本机默认浏览器的接口。可以使用它来打开特定URL、新建标签页或者窗口等操作。 示例1:打开人人网首页 import webbrowser url = &q…

    人工智能概论 2023年5月25日
    00
  • 一键备份gitolite服务器的Shell脚本

    下面是“一键备份gitolite服务器的Shell脚本”的完整攻略: 1. 需求分析 gitolite是一款优秀的Git仓库管理工具,用于管理Git项目权限和访问。在使用gitolite时,我们需要对服务器进行备份以确保数据安全性。因此,需要编写一个Shell脚本,一键备份gitolite服务器。 2. 编写Shell脚本 2.1 确定备份目录和备份文件名称…

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