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

    你可能感兴趣的文章
    php7中使用php_memcache扩展
    查看>>
    PHP7中十个需要避免的坑
    查看>>
    php7和PHP5对比的新特性和性能优化
    查看>>
    PHP7安装pdo_mysql扩展
    查看>>
    PHP7实战开发简单CMS内容管理系统(7) 后台登录架构 用户登录校验
    查看>>
    php7,从phpExcel升级到PhpSpreadsheet
    查看>>
    PHP8.1 + ThinkPHP实战指南:高效构建现代化网站的六大技巧
    查看>>
    PHP8中match新语句的操作方法
    查看>>
    PHP:第一章——PHP中常量和预定义常量
    查看>>
    PHP:第一章——PHP中的位运算
    查看>>
    phpcms
    查看>>
    phpcms 2008 product.php pagesize参数代码注射漏洞
    查看>>
    phpcms V9 自定义添加 全局变量{DIY_PATH}方法
    查看>>
    Redis五种核心数据结构的基本使用与应用场景
    查看>>
    Redis五种数据结构简介
    查看>>
    PHPCMS多文件上传和上传数量限制
    查看>>
    phpEnv的PHP集成环境
    查看>>
    PHPExcel一些基本设置总结
    查看>>
    phpexcel中文手册
    查看>>
    PHPExcel导入导出 若在thinkPHP3.2中使用(无论实例还是静态调用(如new classname或classname::function)都必须加反斜杠,因3.2就命名空间,如/c...
    查看>>