.NET必知的EventCounters效能指標監視器

HueiFeng發表於2020-11-14

在.NET我們對於效能指標監控,其實常見的有兩個方法,一個是CLI工具dotnet-counters而另一個是程式碼級別的EventListener.

使用dotnet-counters

dotnet-counters是一個效能指標監視工具,用於臨時執行狀態監視和初級效能調查。它可以觀察通過 EventCounter API釋出的效能計數器值。例如,可以快速監視 CPU 使用情況或 .NET Core 應用程式中引發的異常率,以瞭解在使用 PerfViewdotnet-trace 深入調查更嚴重的效能問題之前是否有任何可疑操作。

-- 摘自 dotnet-counters

命令


安裝dotnet-counters CLI工具,可通過如下命令:

dotnet tool install --global dotnet-counters

更新命令如下所示:

dotnet tool update dotnet-counters --global

安裝完工具之後,我們可以進行檢視可監視的程式:

dotnet-counters ps
     12268 dotnet C:\Program Files\dotnet\dotnet.exe
     16324 dotnet C:\Program Files\dotnet\dotnet.exe

獲取到程式ID後,我們可以通過如下命令進行監視:

dotnet-counters monitor -p 12268

監視特定的EventSources,可以提供以一個空格分隔開的EventSources列表,如下所示:

dotnet-counters monitor -p 12268 System.Runtime MyEventSource

在預設的情況下,我們對於EventSource監視時,它捕獲的是所有的計數器。如果我們想單獨跟蹤某幾個計數器那麼可通過如下方式進行指定:

dotnet-counters monitor -p 12268 System.Runtime[cpu-usage,gc-heap-size]       

對於監視器我們可以設定重新整理頻率,可以通過--refresh-interval引數來設定:

dotnet-counters monitor -p 12268  --refresh-interval 3   System.Runtime[cpu-usage,gc-heap-size]

程式碼中的EventCounters

EventListener提供了程式內(In-Process)訂閱和消費日誌事件的方式,EventListener可以接收到來自EventSource分發的日誌事件。 這些事件內涵蓋了GC、JIT、ThreadPool和interop的行為。

建立EventListener

在下面我們進行重寫OnEventSourceCreated方法,該方法會在呼叫時接收一個EventSource物件,我們可以通過EventSource物件的Name屬性去篩選我們感興趣的日誌事件,篩選後我們需要顯示的呼叫EnableEvents方法向感興趣的日誌事件發起訂閱。

    internal sealed class MyEventListener : EventListener
    {
        protected override void OnEventSourceCreated(EventSource eventSource)
        {
            if (eventSource.Name.Equals("Microsoft-Windows-DotNETRuntime"))
            {
                EnableEvents(eventSource, EventLevel.Verbose, (EventKeywords)(-1));
            }
        }
    }

事件消費

接下來我們需要進行重寫OnEventWritten,關於日誌事件相關的資訊會被封裝成一個EventWrittenEventArgs物件,我們不僅可以通過它獲取當前日誌事件的所有資訊,而且我們還可以進行獲取到EventSource物件。Payload包含了不同屬性的值ReadOnlyCollection<object>, 而PayLoadNames ReadOnlyCollection<object>中包含了不同的屬性名稱,我們現在可以通過如下方式進行獲取這些屬性:

        protected override void OnEventWritten(EventWrittenEventArgs eventData)
        {
            Console.WriteLine($"ThreadID = {eventData.OSThreadId} ID = {eventData.EventId} Name = {eventData.EventName}");
            for (int i = 0; i < eventData.Payload.Count; i++)
            {
                string payloadString = eventData.Payload[i]?.ToString() ?? string.Empty;
                Console.WriteLine($"\tName = \"{eventData.PayloadNames[i]}\" Value = \"{payloadString}\"");
            }
            Console.WriteLine("\n");
        }

參考

https://stackoverflow.com/questions/61081063/get-total-number-of-allocations-in-c-sharp

相關文章