傳統的.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),就可以直接利用這種方式采集所需的性能指標。