博客
关于我
动手实现一个适用于.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/

    你可能感兴趣的文章
    Netty源码—4.客户端接入流程二
    查看>>
    Netty源码—5.Pipeline和Handler一
    查看>>
    Netty源码—6.ByteBuf原理二
    查看>>
    Netty源码—7.ByteBuf原理三
    查看>>
    Netty源码—7.ByteBuf原理四
    查看>>
    Netty源码—8.编解码原理二
    查看>>
    Netty源码解读
    查看>>
    Netty的Socket编程详解-搭建服务端与客户端并进行数据传输
    查看>>
    Netty相关
    查看>>
    Network Dissection:Quantifying Interpretability of Deep Visual Representations(深层视觉表征的量化解释)
    查看>>
    Network Sniffer and Connection Analyzer
    查看>>
    NetworkX系列教程(11)-graph和其他数据格式转换
    查看>>
    Networkx读取军械调查-ITN综合传输网络?/读取GML文件
    查看>>
    Net与Flex入门
    查看>>
    net包之IPConn
    查看>>
    NFinal学习笔记 02—NFinalBuild
    查看>>
    NFS共享文件系统搭建
    查看>>
    nfs复习
    查看>>
    NFS网络文件系统
    查看>>
    nft文件传输_利用remoting实现文件传输-.NET教程,远程及网络应用
    查看>>