Pustaka klien diagnostik

Artikel ini berlaku untuk: ✔️ .NET Core 3.0 SDK dan versi yang lebih baru untuk aplikasi target, .NET Standard 2.0 untuk menggunakan pustaka.

Microsoft.Diagnostics.NETCore.Client (juga dikenal sebagai pustaka klien Diagnostik) adalah pustaka terkelola yang memungkinkan Anda berinteraksi dengan runtime .NET Core (CoreCLR) untuk berbagai tugas terkait diagnostik, seperti melacak melalui EventPipe, meminta cadangan, atau melampirkan ICorProfiler. Pustaka ini adalah pustaka cadangan di balik banyak alat diagnostik seperti penghitung dotnet, dotnet-trace, dotnet-gcdump, dotnet-dump, dan dotnet-monitor. Dengan menggunakan pustaka ini, Anda dapat menulis alat diagnostik Anda sendiri yang disesuaikan untuk skenario tertentu Anda.

Anda dapat memperoleh Microsoft.Diagnostics.NETCore.Client dengan menambahkan PackageReference ke proyek Anda. Paket dihosting pada NuGet.org.

Sampel di bagian berikut menunjukkan cara menggunakan pustaka Microsoft.Diagnostics.NETCore.Client. Beberapa contoh ini juga menunjukkan penguraian payload peristiwa dengan menggunakan pustaka TraceEvent .

Lampirkan ke proses dan cetak semua peristiwa GC

Cuplikan ini menunjukkan cara memulai sesi EventPipe menggunakan penyedia runtime .NET dengan kata kunci GC pada tingkat informasi. Ini juga menunjukkan cara menggunakan EventPipeEventSource kelas yang disediakan oleh pustaka TraceEvent untuk mengurai peristiwa masuk dan mencetak namanya ke konsol secara real time.

using Microsoft.Diagnostics.NETCore.Client;
using Microsoft.Diagnostics.Tracing;
using Microsoft.Diagnostics.Tracing.EventPipe;
using Microsoft.Diagnostics.Tracing.Parsers;
using System;
using System.Collections.Generic;
using System.Diagnostics.Tracing;

public class RuntimeGCEventsPrinter
{
    public static void PrintRuntimeGCEvents(int processId)
    {
        var providers = new List<EventPipeProvider>()
        {
            new EventPipeProvider("Microsoft-Windows-DotNETRuntime",
                EventLevel.Informational, (long)ClrTraceEventParser.Keywords.GC)
        };

        var client = new DiagnosticsClient(processId);
        using (EventPipeSession session = client.StartEventPipeSession(providers, false))
        {
            var source = new EventPipeEventSource(session.EventStream);

            source.Clr.All += (TraceEvent obj) => Console.WriteLine(obj.ToString());

            try
            {
                source.Process();
            }
            catch (Exception e)
            {
                Console.WriteLine("Error encountered while processing events");
                Console.WriteLine(e.ToString());
            }
        }
    }
}

Menulis cadangan inti

Sampel ini menunjukkan cara memicu pengumpulan core dump menggunakan DiagnosticsClient.

using Microsoft.Diagnostics.NETCore.Client;

public partial class Dumper
{
    public static void TriggerCoreDump(int processId)
    {
        var client = new DiagnosticsClient(processId);
        client.WriteDump(DumpType.Normal, "/tmp/minidump.dmp");
    }
}

Memicu cadangan inti saat penggunaan CPU berada di atas ambang batas

Sampel ini menunjukkan cara memantau penghitung yang cpu-usage diterbitkan oleh runtime .NET dan meminta cadangan ketika penggunaan CPU tumbuh di luar ambang tertentu.

using Microsoft.Diagnostics.NETCore.Client;
using Microsoft.Diagnostics.Tracing;
using Microsoft.Diagnostics.Tracing.EventPipe;
using Microsoft.Diagnostics.Tracing.Parsers;
using System;
using System.Collections.Generic;
using System.Diagnostics.Tracing;

public partial class Dumper
{
    public static void TriggerDumpOnCpuUsage(int processId, int threshold)
    {
        var providers = new List<EventPipeProvider>()
        {
            new EventPipeProvider(
                "System.Runtime",
                EventLevel.Informational,
                (long)ClrTraceEventParser.Keywords.None,
                new Dictionary<string, string>
                {
                    ["EventCounterIntervalSec"] = "1"
                }
            )
        };
        var client = new DiagnosticsClient(processId);
        using (var session = client.StartEventPipeSession(providers))
        {
            var source = new EventPipeEventSource(session.EventStream);
            source.Dynamic.All += (TraceEvent obj) =>
            {
                if (obj.EventName.Equals("EventCounters"))
                {
                    var payloadVal = (IDictionary<string, object>)(obj.PayloadValue(0));
                    var payloadFields = (IDictionary<string, object>)(payloadVal["Payload"]);
                    if (payloadFields["Name"].ToString().Equals("cpu-usage"))
                    {
                        double cpuUsage = Double.Parse(payloadFields["Mean"].ToString());
                        if (cpuUsage > (double)threshold)
                        {
                            client.WriteDump(DumpType.Normal, "/tmp/minidump.dmp");
                        }
                    }
                }
            };
            try
            {
                source.Process();
            }
            catch (Exception) {}
        }
    }
}

Memicu jejak CPU untuk jumlah detik tertentu

Sampel ini menunjukkan cara memicu sesi EventPipe untuk periode waktu tertentu dengan kata kunci pelacakan CLR default serta profiler sampel. Setelah itu, ia membaca aliran output dan menulis byte ke file. Pada dasarnya inilah yang dotnet-trace menggunakan secara internal untuk menulis file pelacakan.

using Microsoft.Diagnostics.Tracing;
using Microsoft.Diagnostics.Tracing.Parsers;
using Microsoft.Diagnostics.NETCore.Client;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Tracing;
using System.IO;
using System.Threading.Tasks;

public partial class Tracer
{
    public void TraceProcessForDuration(int processId, int duration, string traceName)
    {
        var cpuProviders = new List<EventPipeProvider>()
        {
            new EventPipeProvider("Microsoft-Windows-DotNETRuntime", EventLevel.Informational, (long)ClrTraceEventParser.Keywords.Default),
            new EventPipeProvider("Microsoft-DotNETCore-SampleProfiler", EventLevel.Informational, (long)ClrTraceEventParser.Keywords.None)
        };
        var client = new DiagnosticsClient(processId);
        using (var traceSession = client.StartEventPipeSession(cpuProviders))
        {
            Task copyTask = Task.Run(async () =>
            {
                using (FileStream fs = new FileStream(traceName, FileMode.Create, FileAccess.Write))
                {
                    await traceSession.EventStream.CopyToAsync(fs);
                }
            });

            Task.WhenAny(copyTask, Task.Delay(TimeSpan.FromMilliseconds(duration * 1000)));
            traceSession.Stop();
        }
    }
}

Sampel ini menunjukkan cara menggunakan DiagnosticsClient.GetPublishedProcesses API untuk mencetak nama proses .NET yang menerbitkan saluran IPC diagnostik.

using Microsoft.Diagnostics.NETCore.Client;
using System;
using System.Diagnostics;
using System.Linq;

public class ProcessTracker
{
    public static void PrintProcessStatus()
    {
        var processes = DiagnosticsClient.GetPublishedProcesses()
            .Select(Process.GetProcessById)
            .Where(process => process != null);

        foreach (var process in processes)
        {
            Console.WriteLine($"{process.ProcessName}");
        }
    }
}

Mengurai peristiwa secara real time

Sampel ini menunjukkan contoh di mana kita membuat dua tugas, satu yang mengurai peristiwa yang ditayangkan dan EventPipeEventSource yang membaca input konsol untuk input pengguna yang menandakan program berakhir. Jika aplikasi target keluar sebelum pengguna menekan enter, aplikasi akan keluar dengan baik. Jika tidak, inputTask akan mengirim perintah Stop ke pipa dan keluar dengan anggun.

using Microsoft.Diagnostics.NETCore.Client;
using Microsoft.Diagnostics.Tracing;
using Microsoft.Diagnostics.Tracing.EventPipe;
using Microsoft.Diagnostics.Tracing.Parsers;
using System;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
using System.Threading.Tasks;

public partial class Tracer
{
    public static void PrintEventsLive(int processId)
    {
        var providers = new List<EventPipeProvider>()
        {
            new EventPipeProvider("Microsoft-Windows-DotNETRuntime",
                EventLevel.Informational, (long)ClrTraceEventParser.Keywords.Default)
        };
        var client = new DiagnosticsClient(processId);
        using (var session = client.StartEventPipeSession(providers, false))
        {

            Task streamTask = Task.Run(() =>
            {
                var source = new EventPipeEventSource(session.EventStream);
                source.Clr.All += (TraceEvent obj) => Console.WriteLine(obj.EventName);
                try
                {
                    source.Process();
                }
                // NOTE: This exception does not currently exist. It is something that needs to be added to TraceEvent.
                catch (Exception e)
                {
                    Console.WriteLine("Error encountered while processing events");
                    Console.WriteLine(e.ToString());
                }
            });

            Task inputTask = Task.Run(() =>
            {
                Console.WriteLine("Press Enter to exit");
                while (Console.ReadKey().Key != ConsoleKey.Enter)
                {
                    Task.Delay(TimeSpan.FromMilliseconds(100));
                }
                session.Stop();
            });

            Task.WaitAny(streamTask, inputTask);
        }
    }
}

Melampirkan profiler ICorProfiler

Sampel ini menunjukkan cara melampirkan ICorProfiler ke proses melalui lampirkan profiler.

using System;
using Microsoft.Diagnostics.NETCore.Client;

public class Profiler
{
    public static void AttachProfiler(int processId, Guid profilerGuid, string profilerPath)
    {
        var client = new DiagnosticsClient(processId);
        client.AttachProfiler(TimeSpan.FromSeconds(10), profilerGuid, profilerPath);
    }
}