效能計數器在.NET Core中的新玩法
傳統的.NET Framework提供的System.Diagnostics.PerformanceCounter型別可以幫助我們收集Windows作業系統下物理機或者程序的效能指標,基於PerformanceCounter型別的效能計數API在.NET Core下被徹底放棄。但是.NET Core程式的很多核心效能指標都會採用事件的方式發出來,具體使用的就是如下所示的這個名為RuntimeEventSource的內部型別。原始碼可以從這裡檢視。
[EventSource(Guid="49592C0F-5A05-516D-AA4B-A64E02026C89", Name="System.Runtime")] internal sealed class RuntimeEventSource : EventSource { ... }
我們可以利用EventListener物件監聽由RuntimeEventSource傳送的事件,進而得到當前的效能指標。如下所示的程式碼片段就是用來獲取效能計數的PerformanceCounterListener型別的定義。在重寫的OnEventSourceCreated方法中,可以根據名稱訂閱針對RuntimeEventSource的事件。在具體呼叫EnableEvents方法時,我們提供了一個字典作為引數,引數利用一個名為EventCounterIntervalSec的元素將取樣的時間間隔設定為5秒。
public class PerformanceCounterListener: EventListener { private static HashSet<string> _keys = new HashSet<string> { "Count", "Min", "Max", "Mean", "Increment" }; private static DateTimeOffset? _lastSampleTime; protected override void OnEventSourceCreated(EventSource eventSource) { base.OnEventSourceCreated(eventSource); if (eventSource.Name == "System.Runtime") { EnableEvents(eventSource, EventLevel.Critical, (EventKeywords)(-1), new Dictionary<string, string> { ["EventCounterIntervalSec"] = "5" }); } } protected override void OnEventWritten(EventWrittenEventArgs eventData) { if (_lastSampleTime != null && DateTimeOffset.UtcNow - _lastSampleTime.Value > TimeSpan.FromSeconds(1)) { Console.WriteLine(); } _lastSampleTime = DateTimeOffset.UtcNow; var metrics = (IDictionary<string, object>)eventData.Payload[0]; var name = metrics ["Name"]; var values = metrics .Where(it=>_keys.Contains(it.Key)) .Select(it => $"{it.Key} = {it.Value}"); var timestamp = DateTimeOffset.UtcNow.ToString("yyyy-MM-dd hh:mm::ss"); Console.WriteLine($"[{timestamp}]{name, -32}: {string.Join("; ", values.ToArray())}"); } } class Program { static void Main() { _ = new PerformanceCounterListener(); Console.Read(); } }
在重寫的OnEventWritten方法中,可以得到效能計數時間的內容載荷(體現為一個字典物件),並從中提取出效能指標的名稱(Name)和相關的取樣值(Max、Min、Count、Mean和Increment)。提取出的效能指標資料連同當前時間戳經過格式化後直接輸出到控制檯上。在作為入口的Main方法中,我們直接建立了PerformanceCounterListener物件,它會以5秒的間隔收集當前的效能指標,並以下圖所示的形式輸出到控制檯上。
如上圖所示,利用PerformanceCounterListener物件幾乎可以收集到.NET Core程式所在程序以及物理機的絕大部分核心指標,其中包括CPU、記憶體、GC、執行緒池相關的指標。如果需要開發APM(Application Performance Management)框架,或者直接整合第三方APM(如我個人比較鍾愛的Elastic APM),就可以直接利用這種方式採集所需的效能指標。