Trasování s EventSource v .NETu 4.5

.NET 4.5 přinesl nový způsob, jak vytvářet trasovací události. Aplikace takové události vytváří, když se stane něco zajímavého, a ty se pak hodí zejména pro diagnostiku, ať už funkční nebo výkonnostní. Trasování pochopitelně není nová myšlenka a mnoho řešení existuje i v nižších verzích .NET frameworku (např. TraceSource). Ale nové řešení nabízí nové schopnosti, velmi snadno se používá a na rozdíl od mnoha jiných prostředků lze použít ve Windows Store aplikacích.

Související typy se nachází ve jmenném prostoru System.Diagnostics.Tracing a nejdůležitější třídou je EventSource. EventSource je to, co vyvolává události, ale nemůžete ji použít přímo – musíte vytvořit novou třídu dědící od EventSource a definovat události v ní, nicméně EventSource udělá všechnu obtížnou práci.

Toto je triviální příklad vlastního potomka EventSource:

MyOwnEventSource : EventSource
{
    public static MyOwnEventSource Log = new MyOwnEventSource();
 
    public void TaskStarted(string taskName)
    {
        // Voláme metodu EventSource.WriteEvent(), která udělá všechnu práci
        WriteEvent(1, taskName); // "1" je ID události
    }
}

Událost se pak aktivuje jednoduchým voláním, jako je toto:

MyOwnEventSource.Log.TaskStarted("myTask");

Jména metod a jména a typy parametrů jsou podstatné – příjemci událostí tyto informace dostanou a vy je uvidíte v logu událostí. Pozor na to, že podporované jsou jen některé typy parametrů: primitivní typy, řetězce, Guid a výčtové typy. Pokud byste použili jakýkoli jiný typ, trasování by nefungovalo.

Také můžete definovat závažnost události, kategorii a takové věci. To pomáhá třídit události a příjemci mohou požádat například jen o události nějaké minimální závažnosti. Jednoduše přidejte k události EventAttribute nastavte vlastnosti, jak je potřeba. Máte k dispozici například:

  • Level – závažnost jako Error, Verbose apod.
  • Message – formátovací řetězec pro konverzi události do uživatelsky přívětivého textu.
  • Keywords – klíčová slova definující skupiny, do kterých událost patří. Můžete definovat vlastní klíčová slova vytvořením vnořené třídy Keywords, která bude obsahovat konstanty typu EventKeywords (obdobný postup se používá i pro jiné vlastnosti).
  • EventId – do WriteEvent() musíte předat správné eventId a pokud žádné nenastavíte v EventAttribute, systém přiřadí ID 1 první metodě, 2 druhé atd. Pokud byste nahoru přidali metodu novou metodu, následující události by se přečíslovali a posílaly by tak do WriteEvent() špatná ID. Proto je bezpečnější přiřazovat ID explicitně v EventAttribute.
    ID události musí být unikátní v rámci jednoho zdroje událostí.

Příklad:

[Event(4, Message = "Item skipped: {0}", Level = EventLevel.Warning, Keywords = Keywords.Diagnostic]
public void ItemSkipped(string reason){ WriteEvent(4, reason); }

Všechny metody s návratovým typem void jsou považovány za události. Můžete některé metody vynechat tím, že jim přiřadíte NonEventAttribute. Takové metody mohou mít libovolné typy parametrů, takže je můžete dokonce použít jako praktická přetížení, která akceptují komplexní typy, konvertují je do primitivních a volají skutečné události.

[NonEvent]
public void ItemSkipped(Exception ex) { ItemSkipped(ex.ToString()); }

Další užitečný atribut je EventSourceAttribute – umožňuje vám zadat jméno zdroje událostí. Výchozí jméno je jméno třídy bez jmenného prostoru, což často není vyhovující.

[EventSource(Name = "Goshoom.TestApp")]
class Logger : EventSource

Můj poslední tip je, že byste měli kontrolovat, je-li zdroj událostí povolený, než začnete dělat cokoli dalšího. To minimalizuje dopad na výkon, není-li zdroj aktivní. Událost pak vypadá nějak takto:

public void ItemSkipped(string reason)
{
    if (IsEnabled())
    {
        WriteEvent(4, reason);
    }
}

Zpracování událostí

Budete potřebovat nástroj, který umí zpracovávat ETW události – můj příklad používá PerfView.

Spusťte PerfView a zvolte Collect > Collect, což vám umožní explicitě spustit a zastavit sběr dat. Mohli byste také spustit a trasovat konkrétní aplikaci pomocí Collect > Run, ale pokud pracujete s Windows Store aplikacemi, budete potřebovat Collect.

Nakonfigurujte, jaká data se mají sbírat, a přidejte svůj zdroj událostí do Additional Providers. Název musí být uvozen hvězdičkou (*). Viz příklad na obrázku.

Stiskněte tlačítko Start Collection, proveďte všechny akce, které chcete trasovat, vraťte se do PerfView a stiskněte Stop Collection.

Když je log připraven, otevřete zobrazení Events:

To zobrazuje všechny události a vy je můžete snadno filtrovat, vybrat sloupce k zobrazení, podívat se na data přidružené k události, čas události a tak dále.

Obrázek ukazuje události filtrované dle jména a detaily jedné konkrétní události. Můžete vidět, že jméno zdroje událostí je Goshoom.TestApp a jméno události je ItemSkipped. Sloupec reason byl vygenerován z parametru metody ItemSkipped().

EventSource i PerfView umí mnohem víc, než jsem zde ukázal, ale snad vám to dalo nějakou představu. Pokud chcete vědět víc, zkuste pár odkazů, které považuji za zajímavé (všechno bohužel v angličtině).

Specification for EventSource class
Vance Morrison’s Weblog
PerfView tutorial on Channel 9