博客
关于我
动手实现一个适用于.NET Core 的诊断工具
阅读量:453 次
发布时间:2019-03-06

本文共 5243 字,大约阅读时间需要 17 分钟。

.NET Core 诊断工具实践指南

前言

在软件开发的日常工作中,诊断工具是开发人员不可或缺的助手。从 dotTrace 到 .NET CLI 推出的高效诊断组件(dotnet trace、dotnet sos、dotnet dump),这些工具大大提升了程序调试的效率,让开发人员从更高层次发现问题。

今天,我们尝试动手实现一个简单的诊断工具。目标是在不修改代码和配置的前提下,获取程序运行信息,包括内存、线程、垃圾回收和异常等。我们将使用 Microsoft.Diagnostics.NETCore.Client 这个友好的组件来实现。


初始化项目

首先,我们创建两个 .NET Core 项目:

  • ConsoleApp:作为我们的诊断程序。
  • WebAPI:需要对这个 API 项目进行诊断分析。
  • 在 ConsoleApp 中通过 NuGet 引入必要的诊断组件:

    Install-Package Microsoft.Diagnostics.NETCore.ClientInstall-Package Microsoft.Diagnostics.Tracing.TraceEvent

    获取正在运行的程序列表

    在无侵入情况下,我们首先获取运行的 dotnet 程序,包括进程名称和 PID。

    修改 ConsoleApp 的 Program.cs

    class Program{    static void Main(string[] args)    {        if (args.Any())        {            switch (args[0])            {                case "ps": PrintProcessStatus(); break;            }        }    }    private static void PrintProcessStatus()    {        var processes = DiagnosticsClient.GetPublishedProcesses()            .Select(Process.GetProcessById)            .Where(process => process != null);        foreach (var process in processes)        {            Console.WriteLine($"ProcessId: {process.Id}");            Console.WriteLine($"ProcessName: {process.ProcessName}");            Console.WriteLine($"StartTime: {process.StartTime}");            Console.WriteLine($"Threads: {process.Threads.Count}");            Console.WriteLine();        }    }}

    运行 dotnet run ps 查看正在运行的进程信息。


    获取 GC 信息

    创建一个 DiagnosticsClient 实例,获取 GC 信息并输出事件名称。

    修改 Program.cs

    static void Main(string[] args){    if (args.Any())    {        switch (args[0])        {            case "ps": PrintProcessStatus(); break;            case "runtime": PrintRuntime(int.Parse(args[1])); break;        }    }}private static void PrintRuntime(int processId){    var providers = new List
    { new EventPipeProvider { Name = "Microsoft-Windows-DotNETRuntime", Level = EventLevel.Informational, Keywords = (long)ClrTraceEventParser.Keywords.GC } }; var client = new DiagnosticsClient(processId); using (var session = client.StartEventPipeSession(providers, false)) { var source = new EventPipeEventSource(session.EventStream); source.Clr.All += (TraceEvent obj) => { Console.WriteLine(obj.EventName); }; try { source.Process(); } catch (Exception e) { Console.WriteLine(e.ToString()); } }}

    运行 dotnet run runtime 3832 并通过浏览器或 curl 访问 WebAPI 接口。


    获取异常信息

    在 WebAPI 中抛出异常,测试诊断工具的捕获能力。

    修改 WebAPI 的 Get 方法:

    [HttpGet]public IEnumerable
    Get(){ try { throw new Exception("error"); var rng = new Random(); return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)] }).ToArray(); } catch (Exception ex) { Console.WriteLine(ex.ToString()); }}

    在 ConsoleApp 中,修改 PrintRuntime 方法的 Keywords 为 ClrTraceEventParser.Keywords.Exception

    运行 dotnet run runtime 13600 并访问 WebAPI 接口。


    生成 dump 文件

    使用 DiagnosticsClient 生成 dump 文件,便于后续分析。

    修改 Program.cs

    static void Main(string[] args){    if (args.Any())    {        switch (args[0])        {            case "ps": PrintProcessStatus(); break;            case "runtime": PrintRuntime(int.Parse(args[1])); break;            case "dump": Dump(int.Parse(args[1])); break;        }    }}private static void Dump(int processId){    var client = new DiagnosticsClient(processId);    client.WriteDump(DumpType.Normal, @"mydump.dmp", false);}

    运行 dotnet run dump 13288 生成 dump 文件。


    生成 trace 文件

    同样使用 DiagnosticsClient 生成 trace 文件,分析 CPU 函数执行耗时。

    修改 Program.cs

    static void Main(string[] args){    if (args.Any())    {        switch (args[0])        {            case "ps": PrintProcessStatus(); break;            case "runtime": PrintRuntime(int.Parse(args[1])); break;            case "dump": Dump(int.Parse(args[1])); break;            case "trace": Trace(int.Parse(args[1])); break;        }    }}private static void Trace(int processId){    var cpuProviders = new List
    { new EventPipeProvider { Name = "Microsoft-Windows-DotNETRuntime", Level = EventLevel.Informational, Keywords = (long)ClrTraceEventParser.Keywords.Default }, new EventPipeProvider { Name = "Microsoft-DotNETCore-SampleProfiler", Level = EventLevel.Informational, Keywords = (long)ClrTraceEventParser.Keywords.None } }; var client = new DiagnosticsClient(processId); using (var traceSession = client.StartEventPipeSession(cpuProviders)) { Task.Run(async () => { using (FileStream fs = new FileStream(@"mytrace.nettrace", FileMode.Create, FileAccess.Write)) { await traceSession.EventStream.CopyToAsync(fs); } }).Wait(10 * 1000); traceSession.Stop(); }}

    运行 dotnet run trace 13288 生成 trace 文件。


    总结

    .NET Core CLI 提供了强大的诊断工具,Microsoft.Diagnostics.NETCore.Client 让我们可以从高层次操作 CLR。通过生成 dump 和 trace 文件,我们可以深入分析程序性能和异常。

    这只是一个简单的实现示例,实际应用中可以根据需要扩展功能。如有疑问欢迎留言讨论!

    转载地址:http://ngeyz.baihongyu.com/

    你可能感兴趣的文章
    Notepad ++ 安装与配置教程(非常详细)从零基础入门到精通,看完这一篇就够了
    查看>>
    Notepad++在线和离线安装JSON格式化插件
    查看>>
    notepad++最详情汇总
    查看>>
    notepad++正则表达式替换字符串详解
    查看>>
    notepad如何自动对齐_notepad++怎么自动排版
    查看>>
    Notes on Paul Irish's "Things I learned from the jQuery source" casts
    查看>>
    Notification 使用详解(很全
    查看>>
    NotImplementedError: Cannot copy out of meta tensor; no data! Please use torch.nn.Module.to_empty()
    查看>>
    NotImplementedError: Could not run torchvision::nms
    查看>>
    nova基于ubs机制扩展scheduler-filter
    查看>>
    Now trying to drop the old temporary tablespace, the session hangs.
    查看>>
    nowcoder—Beauty of Trees
    查看>>
    np.arange()和np.linspace()绘制logistic回归图像时得到不同的结果?
    查看>>
    np.power的使用
    查看>>
    NPM 2FA双重认证的设置方法
    查看>>
    npm build报错Cannot find module ‘webpack/lib/rules/BasicEffectRulePlugin‘解决方法
    查看>>
    npm build报错Cannot find module ‘webpack‘解决方法
    查看>>
    npm ERR! ERESOLVE could not resolve报错
    查看>>
    npm ERR! fatal: unable to connect to github.com:
    查看>>
    npm ERR! Unexpected end of JSON input while parsing near '...on":"0.10.3","direc to'
    查看>>