Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Tento článek se vztahuje na: ✔️ .NET Core 3.0 SDK a novější verze
Poznámka:
Pro vývoj nových projektů .NET Microsoft doporučuje místo toho používat novější rozhraní API System.Diagnostics.Metrics . Rozhraní API System.Diagnostics.Metrics nabízejí zvýšenou funkčnost, standardizaci a integraci s širším ekosystémem nástrojů. Další informace najdete v porovnání rozhraní API metrik.
EventCounters jsou rozhraní API .NET používaná pro odlehčený, multiplatformní a téměř v reálném čase sběr metrik výkonu. EventCounters byly přidány jako multiplatformní alternativu k "čítačům výkonu" rozhraní .NET Framework ve Windows. V tomto článku se dozvíte, co jsou EventCounters, jak je implementovat a jak je využívat.
Modul runtime .NET a několik knihoven .NET publikují základní diagnostické informace pomocí eventCounterů počínaje v .NET Core 3.0. Kromě eventCounterů, které poskytuje modul runtime .NET, se můžete rozhodnout implementovat vlastní eventCounters. EventCounters lze použít ke sledování různých metrik. Další informace o nich najdete v známých eventCounters v rozhraní .NET.
EventCounters jsou součástí EventSource a automaticky se pravidelně odesílají do nástrojů pro naslouchání. Stejně jako všechny ostatní události na objektu EventSourcemohou být využity jak in-proc, tak out-of-proc prostřednictvím EventListener a EventPipe. Tento článek se zaměřuje na multiplatformní funkce EventCounters a záměrně vylučuje PerfView a ETW (Event Tracing for Windows), i když je možné je použít s EventCounters.
Přehled rozhraní EVENTCounter API
Existují dvě primární kategorie EventCounters. Některé čítače jsou určené pro hodnoty "rate", jako je celkový počet výjimek, celkový počet GCS a celkový počet požadavků. Další čítače jsou momentální hodnoty, jako jsou využití haldy, využití procesoru a velikost pracovní sady. V každé z těchto kategorií čítačů existují dva typy čítačů, které se liší podle toho, jak získávají jejich hodnotu. Čítače s dotazováním načítají svou hodnotu prostřednictvím metody zpětného volání a čítače bez dotazování nastavují své hodnoty přímo na instanci čítače.
Čítače jsou reprezentovány následujícími implementacemi:
Naslouchátko pro události určuje délku intervalů měření. Na konci každého intervalu se hodnota přenáší k posluchači pro každý čítač. Implementace čítače určují, jaká rozhraní API a výpočty se používají k vytvoření hodnoty v každém intervalu.
Zařízení EventCounter zaznamenává sadu hodnot. Metoda EventCounter.WriteMetric přidá do sady novou hodnotu. Při každém intervalu se vypočítá statistický souhrn sady, jako je minimum, maximum a průměr. Nástroj dotnet-counters vždy zobrazí střední hodnotu. Je EventCounter užitečné popsat oddělenou sadu operací. Běžné využití může zahrnovat monitorování průměrné velikosti v bajtech nedávných vstupně-výstupních operací nebo průměrnou peněžní hodnotu sady finančních transakcí.
Pro každý časový interval IncrementingEventCounter zaznamenává průběžný součet. Metoda IncrementingEventCounter.Increment sečte celkový součet. Pokud se například
Increment()volá třikrát během jednoho intervalu s hodnotami1,2, a5, pak se průběžný součet8bude hlásit jako hodnota čítače pro tento interval. Nástroj dotnet-counters zobrazí rychlost jako zaznamenaný celkový součet a čas. Je IncrementingEventCounter užitečné změřit, jak často se akce vyskytuje, například počet zpracovaných požadavků za sekundu.PollingCounter používá zpětné volání k určení hodnoty, která je hlášena. Při každém časovém intervalu se vyvolá funkce zpětného volání poskytnuté uživatelem a návratová hodnota se použije jako hodnota čítače. Lze použít PollingCounter k dotazování se na metriky z externího zdroje, například pro zjištění aktuálních volných bajtů na disku. Dá se také použít k hlášení vlastních statistik, které může aplikace vypočítat na vyžádání. Mezi příklady patří hlášení 95. percentilu latencí nedávných požadavků nebo aktuální poměr zásahů a chyb v mezipaměti.
IncrementingPollingCounter používá zpětné volání k určení hodnoty hlášeného přírůstku. Při každém časovém intervalu se vyvolá zpětné volání a potom rozdíl mezi aktuálním vyvoláním a posledním vyvoláním je hlášená hodnota. Nástroj dotnet-counters vždy zobrazí rozdíl jako rychlost, hlášenou hodnotu a čas. Tento čítač je užitečný, pokud není možné volat rozhraní API pro každý výskyt, ale je možné zadat dotaz na celkový počet výskytů. Můžete například hlásit počet bajtů zapsaných do souboru za sekundu, a to i bez oznámení při každém zápisu bajtu.
Implementace zdroje událostí
Následující kód implementuje ukázku EventSource vystavenou jako pojmenovaného "Sample.EventCounter.Minimal" zprostředkovatele. Tento zdroj obsahuje reprezentaci EventCounter doby zpracování požadavků. Takový čítač má název (tj. jeho jedinečné ID ve zdroji) a zobrazovaný název, které používají naslouchací nástroje, jako je dotnet-counters.
using System.Diagnostics.Tracing;
[EventSource(Name = "Sample.EventCounter.Minimal")]
public sealed class MinimalEventCounterSource : EventSource
{
public static readonly MinimalEventCounterSource Log = new MinimalEventCounterSource();
private EventCounter _requestCounter;
private MinimalEventCounterSource() =>
_requestCounter = new EventCounter("request-time", this)
{
DisplayName = "Request Processing Time",
DisplayUnits = "ms"
};
public void Request(string url, long elapsedMilliseconds)
{
WriteEvent(1, url, elapsedMilliseconds);
_requestCounter?.WriteMetric(elapsedMilliseconds);
}
protected override void Dispose(bool disposing)
{
_requestCounter?.Dispose();
_requestCounter = null;
base.Dispose(disposing);
}
}
Slouží dotnet-counters ps k zobrazení seznamu procesů .NET, které lze monitorovat:
dotnet-counters ps
1398652 dotnet C:\Program Files\dotnet\dotnet.exe
1399072 dotnet C:\Program Files\dotnet\dotnet.exe
1399112 dotnet C:\Program Files\dotnet\dotnet.exe
1401880 dotnet C:\Program Files\dotnet\dotnet.exe
1400180 sample-counters C:\sample-counters\bin\Debug\netcoreapp3.1\sample-counters.exe
EventSource Předat název --counters možnosti pro zahájení monitorování počítadla:
dotnet-counters monitor --process-id 1400180 --counters Sample.EventCounter.Minimal
Následující příklad ukazuje výstup monitorování:
Press p to pause, r to resume, q to quit.
Status: Running
[Samples-EventCounterDemos-Minimal]
Request Processing Time (ms) 0.445
Stisknutím klávesy q zastavte příkaz monitorování.
Podmíněné čítače
Při implementaci EventSource lze čítače, které obsahuje, podmíněně vytvořit instanci, když je metoda EventSource.OnEventCommand volána s Command hodnotou EventCommand.Enable. Chcete-li bezpečně vytvořit instanci čítače pouze v případě, že je null, použijte operátor přiřazení s hodnotou null. Kromě toho mohou vlastní metody vyhodnotit metodu IsEnabled , aby určila, jestli je aktuální zdroj událostí povolený nebo ne.
using System.Diagnostics.Tracing;
[EventSource(Name = "Sample.EventCounter.Conditional")]
public sealed class ConditionalEventCounterSource : EventSource
{
public static readonly ConditionalEventCounterSource Log = new ConditionalEventCounterSource();
private EventCounter _requestCounter;
private ConditionalEventCounterSource() { }
protected override void OnEventCommand(EventCommandEventArgs args)
{
if (args.Command == EventCommand.Enable)
{
_requestCounter ??= new EventCounter("request-time", this)
{
DisplayName = "Request Processing Time",
DisplayUnits = "ms"
};
}
}
public void Request(string url, float elapsedMilliseconds)
{
if (IsEnabled())
{
_requestCounter?.WriteMetric(elapsedMilliseconds);
}
}
protected override void Dispose(bool disposing)
{
_requestCounter?.Dispose();
_requestCounter = null;
base.Dispose(disposing);
}
}
Návod
Podmíněné čítače jsou čítače, které jsou podmíněně instancovány, což je jistou formou mikro-optimalizace. Modul runtime používá tento model pro scénáře, kdy se čítače obvykle nepoužívají, aby se ušetřil zlomek milisekundy.
Ukázkové čítače modulu runtime .NET Core
V modulu runtime .NET Core existuje mnoho skvělých ukázkových implementací. Tady je implementace modulu runtime pro čítač, který sleduje velikost pracovní sady aplikace.
var workingSetCounter = new PollingCounter(
"working-set",
this,
() => (double)(Environment.WorkingSet / 1_000_000))
{
DisplayName = "Working Set",
DisplayUnits = "MB"
};
PollingCounter hlásí aktuální množství fyzické paměti namapované na proces (pracovní sadu) aplikace, protože metriku zachycuje v daném okamžiku. Zpětné volání pro dotazování hodnoty je zadaný výraz lambda, což je jen volání System.Environment.WorkingSet rozhraní API. DisplayName a DisplayUnits jsou volitelné vlastnosti, které lze nastavit tak, aby pomohly straně příjemce čítače zobrazit hodnotu jasněji. Například dotnet-counters používá tyto vlastnosti k zobrazení popisnější verze názvů čítačů.
Důležité
Vlastnosti DisplayName nejsou lokalizované.
Pro PollingCounter a IncrementingPollingCounter není třeba nic dalšího dělat. Oba dotazují hodnoty sami v intervalu požadovaném zákazníkem.
Tady je příklad čítače modulu runtime implementovaného pomocí IncrementingPollingCounter.
var monitorContentionCounter = new IncrementingPollingCounter(
"monitor-lock-contention-count",
this,
() => Monitor.LockContentionCount
)
{
DisplayName = "Monitor Lock Contention Count",
DisplayRateTimeScale = TimeSpan.FromSeconds(1)
};
IncrementingPollingCounter používá rozhraní API Monitor.LockContentionCount k hlášení přírůstku celkového počtu kolizí uzamčení. Vlastnost DisplayRateTimeScale je nepovinná, ale při použití může poskytnout nápovědu k časovému intervalu, ve kterém se čítač nejlépe zobrazí. Například počet kolizí zámků se nejlépe zobrazí jako počet za sekundu, takže DisplayRateTimeScale je nastavený na jednu sekundu. Rychlost zobrazení lze upravit pro různé typy čítačů sazeb.
Poznámka:
DisplayRateTimeScale není používán nástrojem dotnet-counters a naslouchací procesy událostí ho nevyžadují.
Existuje více implementací čítačů, které se dají použít jako odkaz v úložišti modulu runtime .NET.
Konkurence
Návod
Rozhraní EventCounters API nezaručuje bezpečnost vláken. Když jsou instance PollingCounter nebo IncrementingPollingCounter, jimž byly předány delegáti, volány více vlákny, je vaší zodpovědností zaručit bezpečnost vláken těchto delegátů.
Představte si například následující EventSource pro sledování požadavků.
using System;
using System.Diagnostics.Tracing;
public class RequestEventSource : EventSource
{
public static readonly RequestEventSource Log = new RequestEventSource();
private IncrementingPollingCounter _requestRateCounter;
private long _requestCount = 0;
private RequestEventSource() =>
_requestRateCounter = new IncrementingPollingCounter("request-rate", this, () => _requestCount)
{
DisplayName = "Request Rate",
DisplayRateTimeScale = TimeSpan.FromSeconds(1)
};
public void AddRequest() => ++ _requestCount;
protected override void Dispose(bool disposing)
{
_requestRateCounter?.Dispose();
_requestRateCounter = null;
base.Dispose(disposing);
}
}
Metodu AddRequest() lze volat z obslužné rutiny požadavku a RequestRateCounter dotazuje hodnotu v intervalu určeném příjemcem čítače.
AddRequest() metoda nicméně může být volána více vlákny najednou, čímž vzniká závodní podmínka na _requestCount. Alternativním způsobem, jak bezpečně zvýšit _requestCount, je použití Interlocked.Increment.
public void AddRequest() => Interlocked.Increment(ref _requestCount);
Chcete-li zabránit přetrženým čtením (v 32bitových architekturách) pole long, použijte _requestCountInterlocked.Read.
_requestRateCounter = new IncrementingPollingCounter("request-rate", this, () => Interlocked.Read(ref _requestCount))
{
DisplayName = "Request Rate",
DisplayRateTimeScale = TimeSpan.FromSeconds(1)
};
Použití EventCounterů
Existují dva primární způsoby využití EventCounters: „in-proc“ a „out-of-proc“. Spotřebu EventCounters lze rozlišit na tři vrstvy podle různých technologií, které je využívají.
Přenos událostí v nezpracovaném datovém proudu prostřednictvím Trasování událostí ETW nebo EventPipe.
ETW rozhraní API se dodávají s operačním systémem Windows a EventPipe je přístupný jako rozhraní .NET API nebo diagnostický protokol IPC.
Dekódování binárního streamu událostí na události:
Knihovna TraceEvent zpracovává formáty streamu ETW i EventPipe.
Nástroje příkazového řádku a grafického uživatelského rozhraní:
Nástroje, jako je PerfView (ETW nebo EventPipe), dotnet-counters (pouze EventPipe) a dotnet-monitor (pouze EventPipe).
Spotřeba mimo proces
Využívání EventCounters mimo proces je běžný přístup. Pomocí dotnet-counters je můžete využívat napříč platformami; prostřednictvím EventPipe. Tento nástroj dotnet-counters je globální nástroj dotnet CLI, který lze použít na různých platformách k monitorování hodnot čítačů. Pokud chcete zjistit, jak používat dotnet-counters ke sledování čítačů, podívejte se na nástroj dotnet-counters nebo projděte tutoriál Jak měřit výkon pomocí EventCounters.
Azure Application Insights
Azure Monitor může spotřebovávat EventCounters, konkrétně Azure Application Insights. Čítače je možné přidávat a odebírat a můžete zadat vlastní čítače nebo dobře známé čítače. Další informace viz Přizpůsobení čítačů ke shromažďování.
dotnet-monitor
Tento dotnet-monitor nástroj usnadňuje přístup k diagnostice z procesu .NET vzdáleným a automatizovaným způsobem. Kromě trasování může monitorovat metriky, shromažďovat výpisy paměti a výpisy GC. Distribuuje se jako nástroj rozhraní příkazového řádku i image Dockeru. Zveřejňuje rozhraní REST API a kolekce diagnostických artefaktů probíhá prostřednictvím volání REST.
Další informace najdete v dotnet-monitor.
Spotřeba v rámci procesu
Hodnoty čítačů můžete získávat prostřednictvím EventListener API. Jedná se o způsob v procesu, jak využívat události vytvořené všemi instancemi EventSource ve vaší aplikaci. Další informace o tom, jak používat EventListener rozhraní API, najdete v tématu EventListener.
Nejprve je potřeba povolit EventSource, který generuje hodnotu čítače. Přepište metodu EventListener.OnEventSourceCreated, aby se zobrazilo oznámení při vytvoření EventSource, a pokud jde o správný EventSource s vašimi EventCounters, můžete na něm zavolat EventListener.EnableEvents. Tady je příklad přepisu nastavení:
protected override void OnEventSourceCreated(EventSource source)
{
if (!source.Name.Equals("System.Runtime"))
{
return;
}
EnableEvents(source, EventLevel.Verbose, EventKeywords.All, new Dictionary<string, string>()
{
["EventCounterIntervalSec"] = "1"
});
}
Ukázkový kód
Zde je ukázková EventListener třída, která vytiskne všechny názvy a hodnoty čítačů z modulu runtime EventSource.NET pro publikování interních čítačů (System.Runtime) každou sekundu.
using System;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
public class SimpleEventListener : EventListener
{
public SimpleEventListener()
{
}
protected override void OnEventSourceCreated(EventSource source)
{
if (!source.Name.Equals("System.Runtime"))
{
return;
}
EnableEvents(source, EventLevel.Verbose, EventKeywords.All, new Dictionary<string, string>()
{
["EventCounterIntervalSec"] = "1"
});
}
protected override void OnEventWritten(EventWrittenEventArgs eventData)
{
if (!eventData.EventName.Equals("EventCounters"))
{
return;
}
for (int i = 0; i < eventData.Payload.Count; ++ i)
{
if (eventData.Payload[i] is IDictionary<string, object> eventPayload)
{
var (counterName, counterValue) = GetRelevantMetric(eventPayload);
Console.WriteLine($"{counterName} : {counterValue}");
}
}
}
private static (string counterName, string counterValue) GetRelevantMetric(
IDictionary<string, object> eventPayload)
{
var counterName = "";
var counterValue = "";
if (eventPayload.TryGetValue("DisplayName", out object displayValue))
{
counterName = displayValue.ToString();
}
if (eventPayload.TryGetValue("Mean", out object value) ||
eventPayload.TryGetValue("Increment", out value))
{
counterValue = value.ToString();
}
return (counterName, counterValue);
}
}
Jak je uvedeno výše, musíte se ujistit, že je argument "EventCounterIntervalSec" nastaven v argumentu filterPayload při volání EnableEvents. Jinak čítače nebudou moct vyprázdnit hodnoty, protože neví, v jakém intervalu by se měly vyprázdnit.