本文適用於: ✔️ .NET Core 3.0 SDK 和更新版本,用於目標應用程式,以及使用庫的 .NET Standard 2.0。
Microsoft.Diagnostics.NETCore.Client
(也稱為診斷用戶端程式庫)是一個管理的程式庫,可讓您與 .NET Core 執行時 (CoreCLR) 互動,從事各種診斷相關工作,例如透過 EventPipe 進行追蹤、要求生成傾印檔或附加 ICorProfiler
。 此函式庫是許多診斷工具背後的後盾,例如 dotnet-counters、dotnet-trace、dotnet-gcdump、dotnet-dump 和 dotnet-monitor。 使用此連結庫,您可以撰寫針對特定案例自定義的診斷工具。
您可以透過將新增至專案來取得PackageReference
。 套件裝載於 NuGet.org
。
下列各節中的範例示範如何使用 Microsoft.Diagnostics.NETCore.Client 連結庫。 其中一些範例也會示範使用 TraceEvent 連結庫剖析事件承載。
附加至程序並列印出所有 GC 事件
此代碼段示範如何在資訊層級使用 .NET 運行時間提供者 搭配 GC 關鍵詞來啟動 EventPipe 會話。 它也會示範如何使用 EventPipeEventSource
TraceEvent 連結庫 提供的 類別來剖析傳入事件,並將其名稱即時列印至控制台。
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());
}
}
}
}
撰寫核心傾印
此範例示範如何使用來觸發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");
}
}
當 CPU 使用量超過閾值時觸發核心轉儲
此範例示範如何監視 cpu-usage
.NET 執行階段所發佈的計數器,並在 CPU 使用量超過特定閾值時要求生成記憶體傾印文件。
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) {}
}
}
}
針對設定的秒數觸發 CPU 追蹤
此範例示範如何使用預設 CLR 追蹤關鍵詞以及範例分析工具,在一段時間內觸發 EventPipe 會話。 之後,它會讀取輸出數據流,並將位元組寫入檔案。 基本上,這是 dotnet-trace
內部用來寫入追蹤檔案的方式。
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();
}
}
}
顯示發布診斷頻道的程序名稱
此範例示範如何使用 DiagnosticsClient.GetPublishedProcesses
API 來列印發佈診斷 IPC 通道之 .NET 進程的名稱。
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}");
}
}
}
即時剖析事件
此範例示範我們建立兩個工作的範例,其中一個工作會剖析實時發生的 EventPipeEventSource
事件,另一個工作會讀取控制台輸入,供使用者輸入指示程序結束。 如果目標應用程式在使用者按下 Enter 之前結束,則應用程式會正常結束。 否則, inputTask
會將 Stop 命令傳送至管道並正常結束。
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);
}
}
}
附加 ICorProfiler 分析工具
此範例示範如何透過分析器附加將 ICorProfiler 附加到程序。
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);
}
}