Dela via


Diagnostikklientbibliotek

Den här artikeln gäller för: ✔️ .NET Core 3.0 SDK och senare versioner för målappar, .NET Standard 2.0 för att använda biblioteket.

Microsoft.Diagnostics.NETCore.Client (även känt som diagnostikklientbiblioteket) är ett hanterat bibliotek som låter dig interagera med .NET Core-körning (CoreCLR) för olika diagnostikrelaterade uppgifter, till exempel spårning via EventPipe, begäran om en dump eller anslutning av en ICorProfiler. Det här biblioteket är stödbiblioteket bakom många diagnostikverktyg som dotnet-counters, dotnet-trace, dotnet-gcdump, dotnet-dump och dotnet-monitor. Med det här biblioteket kan du skriva egna diagnostikverktyg som är anpassade för ditt specifika scenario.

Du kan hämta Microsoft.Diagnostics.NETCore.Client genom att lägga till en PackageReference i projektet. Paketet finns på NuGet.org.

Exemplen i följande avsnitt visar hur du använder Microsoft.Diagnostics.NETCore.Client-biblioteket. Några av de här exemplen visar också parsning av händelsenyttolaster med hjälp av TraceEvent-biblioteket .

Koppla till en process och skriv ut alla GC-händelser

Det här kodfragmentet visar hur du startar en EventPipe-session med . NET-körningsprovidern med GC-nyckelordet på informationsnivå. Den visar också hur du använder klassen EventPipeEventSource som tillhandahålls av TraceEvent-biblioteket för att parsa inkommande händelser och skriva ut deras namn till konsolen i realtid.

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());
            }
        }
    }
}

Skriva en kärndumpning

Det här exemplet visar hur du utlöser samlingen av en kärndumpning med hjälp av 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");
    }
}

Utlösa en kärndumpning när CPU-användningen överskrider ett tröskelvärde

Det här exemplet visar hur du övervakar räknaren cpu-usage som publicerats av .NET-körningen och begär en dump när CPU-användningen växer över ett visst tröskelvärde.

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) {}
        }
    }
}

Utlösa en CPU-spårning för angivet antal sekunder

Det här exemplet visar hur du utlöser en EventPipe-session under en viss tidsperiod med standardnyckelordet FÖR CLR-spårning samt exempelprofileraren. Efteråt läser den utdataströmmen och skriver ut byte till en fil. Det är i princip det som dotnet-trace används internt för att skriva en spårningsfil.

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();
        }
    }
}

Det här exemplet visar hur du använder DiagnosticsClient.GetPublishedProcesses API för att skriva ut namnen på de .NET-processer som publicerade en IPC-diagnostikkanal.

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}");
        }
    }
}

Parsa händelser i realtid

Det här exemplet visar ett exempel där vi skapar två uppgifter, en som parsar händelserna som kommer in live med EventPipeEventSource och en som läser konsolens indata för en användare som signalerar att programmet ska avslutas. Om målappen avslutas innan användaren trycker på Retur avslutas appen korrekt. Annars inputTask skickar kommandot Stoppa till röret och avslutas på ett korrekt sätt.

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);
        }
    }
}

Bifoga en ICorProfiler profilerare

Det här exemplet visar hur du kopplar en ICorProfiler till en process via profilerkoppling.

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);
    }
}