Megosztás a következőn keresztül:


System.Diagnostics.Tracing.EventSource osztály

Ez a cikk kiegészítő megjegyzéseket tartalmaz az API referenciadokumentációjához.

Az EventSource osztályt egy olyan felhasználói osztály örökli, amely az eseménykövetéshez használandó konkrét eseményeket biztosít. A EventSource.WriteEvent metódusok az események naplózására vannak meghívva.

Az alapvető funkciók EventSource a legtöbb alkalmazáshoz elegendőek. Ha jobban szeretné szabályozni a létrehozott esemény metaadatait, alkalmazhatja az EventAttribute attribútumot a metódusokra. Speciális eseményforrás-alkalmazások esetén elfoghatja a származtatott eseményforrásnak küldött parancsokat, és módosíthatja a szűrést, vagy az öröklő által végrehajtandó műveleteket (például adatstruktúra memóriaképét) okozhatja. Az eseményforrások folyamat EventListener közben aktiválhatók olyan EventPipe-alapú eszközökkel, mint például dotnet-trace az Event Tracing for Windows (ETW) vagy a PerfViewLogman. Az adatküldő programozott módon is vezérelhető és elfogható. Az EventListener osztály további funkciókat biztosít.

Szabályok

EventSourceA -származtatott osztályoknak a következő konvenciók szerint kell eljárnia:

  • A felhasználó által definiált osztályoknak egységes mintát kell implementálniuk. A singleton példány neve hagyományosan Log. A felhasználók nem hívhatnak IDisposable.Dispose manuálisan, és engedélyezhetik, hogy a futtatókörnyezet megtisztítsa a singleton példányt a felügyelt kódvégrehajtás végén.
  • A felhasználó által definiált, származtatott osztályt úgy kell megjelölni, mintha sealed nem valósítja meg a Speciális használat szakaszban tárgyalt speciális "Utility EventSource" konfigurációt.
  • Hívás IsEnabled() az esemény indításához kapcsolódó erőforrás-igényes munka végrehajtása előtt.
  • Az objektumokat implicit módon úgy hozhatja létre EventTask , hogy két eseménymetódust deklarál a következő eseményazonosítókkal, amelyek elnevezési mintájával <EventName>Start és <EventName>Stop. Ezeket az eseményeket egymás mellett kell deklarálni az osztálydefinícióban, és először a <EventName>Start metódusnak kell lennie.
  • Próbálja meg visszafelé kompatibilisen tartani EventSource az objektumokat, és megfelelően verziószámozza őket. Az esemény alapértelmezett verziója a következő 0: . A verzió a beállítással Versionmódosítható. A hasznos adatok tulajdonságainak módosításakor módosítsa az esemény verzióját. Mindig adjon hozzá új hasznos adattulajdonságokat az eseménydeklaráció végéhez. Ha ez nem lehetséges, hozzon létre egy új eseményt egy új azonosítóval a régi helyett.
  • Eseménymetelyek deklarálásakor a változó méretű tulajdonságok előtt adja meg a rögzített méretű hasznos adattulajdonságokat.
  • EventKeywords a rendszer bitmaszkként használja a szolgáltatóra való feliratkozáskor megadott események megadásához. Kulcsszavakat úgy adhat meg, ha egy public static class Keywords tagosztályt határoz meg, amelynek tagjai vannak public const EventKeywords .
  • Drága események társítása egy EventKeywords felhasználóval EventAttribute. Ez a minta lehetővé teszi a EventSource felhasználók számára, hogy kikapcsolják ezeket a drága műveleteket.

Önleíró (nyomkövetési) és jegyzékes eseményformátumok

EventSource konfigurálható két különböző módra a használt konstruktor vagy a beállított jelölők EventSourceOptionsalapján.

Korábban ez a két formátum két olyan formátumból származik, amelyeket az Event Tracing for Windows (ETW) használt. Bár ez a két mód nem befolyásolja az Eseménykövetés windowsos (ETW) vagy EventPipe-alapú figyelők általi használatát, másképpen generálják az események metaadatait.

Az alapértelmezett eseményformátum az EtwManifestEventFormat, amely be van állítva, ha nincs megadva.EventSourceSettings A jegyzékalapú EventSource objektumok létrehoznak egy XML-dokumentumot, amely az osztályban az inicializáláskor meghatározott eseményeket jelöli. Ehhez tükröznie EventSource kell magát a szolgáltató és az esemény metaadatainak létrehozásához.

Ha önleíró (nyomkövetési) eseményformátumot szeretne használni, a konstruktor, a EventSource(String, EventSourceSettings)EventSource(String) konstruktor vagy a jelölő beállításával állítsa EventSource be a EtwSelfDescribingEventFormat konstruktortEventSourceSettings. Az önleíró források minimális szolgáltatói metaadatokat hoznak létre az inicializáláskor, és csak akkor hoznak létre esemény metaadatokat, ha Write(String) meghívják őket.

A gyakorlatban ezek az eseményformátum-beállítások csak a Windows eseménykövetése (ETW) alapján befolyásolják az olvasók használatát. Ezek azonban kis hatással lehetnek az inicializálási időre és az eseményenkénti írási időkre a tükrözéshez és a metaadatok létrehozásához szükséges idő miatt.

Példák

Az alábbi példa az osztály egyszerű implementációját EventSource mutatja be.

using System.Diagnostics.Tracing;

namespace Demo1
{
    sealed class MyCompanyEventSource : EventSource
    {
        public static MyCompanyEventSource Log = new MyCompanyEventSource();

        public void Startup() { WriteEvent(1); }
        public void OpenFileStart(string fileName) { WriteEvent(2, fileName); }
        public void OpenFileStop() { WriteEvent(3); }
    }

    class Program1
    {
        static void Main(string[] args)
        {
            MyCompanyEventSource.Log.Startup();
            // ...
            MyCompanyEventSource.Log.OpenFileStart("SomeFile");
            // ...
            MyCompanyEventSource.Log.OpenFileStop();
        }
    }
}
Imports System.Diagnostics.Tracing

Class MyCompanyEventSource
    Inherits EventSource
    Public Shared Log As New MyCompanyEventSource()

    Public Sub Startup()
        WriteEvent(1)
    End Sub

    Public Sub OpenFileStart(ByVal fileName As String)
        WriteEvent(2, fileName)
    End Sub

    Public Sub OpenFileStop()
        WriteEvent(3)
    End Sub
End Class

Class Program

    Shared Sub Main(ByVal args() As String)
        MyCompanyEventSource.Log.Startup()
        ' ...
        MyCompanyEventSource.Log.OpenFileStart("SomeFile")
        ' ...
        MyCompanyEventSource.Log.OpenFileStop()

    End Sub
End Class

Az alábbi példa az osztály összetettebb implementációját EventSource mutatja be.

using System;
using System.Diagnostics.Tracing;

namespace Demo2
{
    enum MyColor { Red, Yellow, Blue };

    [EventSource(Name = "MyCompany")]
    sealed class MyCompanyEventSource : EventSource
    {
        public static class Keywords
        {
            public const EventKeywords Page = (EventKeywords)1;
            public const EventKeywords DataBase = (EventKeywords)2;
            public const EventKeywords Diagnostic = (EventKeywords)4;
            public const EventKeywords Perf = (EventKeywords)8;
        }

        public static class Tasks
        {
            public const EventTask Page = (EventTask)1;
            public const EventTask DBQuery = (EventTask)2;
        }

        [Event(1, Message = "Application Failure: {0}", Level = EventLevel.Error, Keywords = Keywords.Diagnostic)]
        public void Failure(string message) { WriteEvent(1, message); }

        [Event(2, Message = "Starting up.", Keywords = Keywords.Perf, Level = EventLevel.Informational)]
        public void Startup() { WriteEvent(2); }

        [Event(3, Message = "loading page {1} activityID={0}", Opcode = EventOpcode.Start,
            Task = Tasks.Page, Keywords = Keywords.Page, Level = EventLevel.Informational)]
        public void PageStart(int ID, string url) { if (IsEnabled()) WriteEvent(3, ID, url); }

        [Event(4, Opcode = EventOpcode.Stop, Task = Tasks.Page, Keywords = Keywords.Page, Level = EventLevel.Informational)]
        public void PageStop(int ID) { if (IsEnabled()) WriteEvent(4, ID); }

        [Event(5, Opcode = EventOpcode.Start, Task = Tasks.DBQuery, Keywords = Keywords.DataBase, Level = EventLevel.Informational)]
        public void DBQueryStart(string sqlQuery) { WriteEvent(5, sqlQuery); }

        [Event(6, Opcode = EventOpcode.Stop, Task = Tasks.DBQuery, Keywords = Keywords.DataBase, Level = EventLevel.Informational)]
        public void DBQueryStop() { WriteEvent(6); }

        [Event(7, Level = EventLevel.Verbose, Keywords = Keywords.DataBase)]
        public void Mark(int ID) { if (IsEnabled()) WriteEvent(7, ID); }

        [Event(8)]
        public void LogColor(MyColor color) { WriteEvent(8, (int)color); }

        public static MyCompanyEventSource Log = new MyCompanyEventSource();
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyCompanyEventSource.Log.Startup();
            Console.WriteLine("Starting up");

            MyCompanyEventSource.Log.DBQueryStart("Select * from MYTable");
            var url = "http://localhost";
            for (int i = 0; i < 10; i++)
            {
                MyCompanyEventSource.Log.PageStart(i, url);
                MyCompanyEventSource.Log.Mark(i);
                MyCompanyEventSource.Log.PageStop(i);
            }
            MyCompanyEventSource.Log.DBQueryStop();
            MyCompanyEventSource.Log.LogColor(MyColor.Blue);

            MyCompanyEventSource.Log.Failure("This is a failure 1");
            MyCompanyEventSource.Log.Failure("This is a failure 2");
            MyCompanyEventSource.Log.Failure("This is a failure 3");
        }
    }
}
Imports System.Diagnostics.Tracing

Enum MyColor
    Red
    Yellow
    Blue
End Enum 'MyColor
<EventSource(Name:="MyCompany")>
Class MyCompanyEventSource1
    Inherits EventSource

    Public Class Keywords
        Public Const Page As EventKeywords = CType(1, EventKeywords)
        Public Const DataBase As EventKeywords = CType(2, EventKeywords)
        Public Const Diagnostic As EventKeywords = CType(4, EventKeywords)
        Public Const Perf As EventKeywords = CType(8, EventKeywords)
    End Class

    Public Class Tasks
        Public Const Page As EventTask = CType(1, EventTask)
        Public Const DBQuery As EventTask = CType(1, EventTask)
    End Class

    <[Event](1, Message:="Application Failure: {0}", Level:=EventLevel.Error, Keywords:=Keywords.Diagnostic)>
    Public Sub Failure(ByVal message As String)
        WriteEvent(1, message)
    End Sub

    <[Event](2, Message:="Starting up.", Keywords:=Keywords.Perf, Level:=EventLevel.Informational)>
    Public Sub Startup()
        WriteEvent(2)
    End Sub

    <[Event](3, Message:="loading page {1} activityID={0}", Opcode:=EventOpcode.Start, Task:=Tasks.Page, Keywords:=Keywords.Page, Level:=EventLevel.Informational)>
    Public Sub PageStart(ByVal ID As Integer, ByVal url As String)
        If IsEnabled() Then
            WriteEvent(3, ID, url)
        End If
    End Sub

    <[Event](4, Opcode:=EventOpcode.Stop, Task:=Tasks.Page, Keywords:=Keywords.Page, Level:=EventLevel.Informational)>
    Public Sub PageStop(ByVal ID As Integer)
        If IsEnabled() Then
            WriteEvent(4, ID)
        End If
    End Sub

    <[Event](5, Opcode:=EventOpcode.Start, Task:=Tasks.DBQuery, Keywords:=Keywords.DataBase, Level:=EventLevel.Informational)>
    Public Sub DBQueryStart(ByVal sqlQuery As String)
        WriteEvent(5, sqlQuery)
    End Sub

    <[Event](6, Opcode:=EventOpcode.Stop, Task:=Tasks.DBQuery, Keywords:=Keywords.DataBase, Level:=EventLevel.Informational)>
    Public Sub DBQueryStop()
        WriteEvent(6)
    End Sub

    <[Event](7, Level:=EventLevel.Verbose, Keywords:=Keywords.DataBase)>
    Public Sub Mark(ByVal ID As Integer)
        If IsEnabled() Then
            WriteEvent(7, ID)
        End If
    End Sub

    <[Event](8)>
    Public Sub LogColor(ByVal color As MyColor)
        WriteEvent(8, Fix(color))
    End Sub
    Public Shared Log As New MyCompanyEventSource1()
End Class

Class Program1

    Shared Sub Main(ByVal args() As String)
        MyCompanyEventSource1.Log.Startup()
        Console.WriteLine("Starting up")
        MyCompanyEventSource1.Log.DBQueryStart("Select * from MYTable")
        Dim url As String = "http:'localhost"
        Dim i As Integer
        For i = 0 To 9
            MyCompanyEventSource1.Log.PageStart(i, url)
            MyCompanyEventSource1.Log.Mark(i)
            MyCompanyEventSource1.Log.PageStop(i)
        Next i
        MyCompanyEventSource1.Log.DBQueryStop()
        MyCompanyEventSource1.Log.LogColor(MyColor.Blue)

        MyCompanyEventSource1.Log.Failure("This is a failure 1")
        MyCompanyEventSource1.Log.Failure("This is a failure 2")
        MyCompanyEventSource1.Log.Failure("This is a failure 3")
    End Sub
End Class

Haladó szintű használat

A felhasználó által definiált EventSource objektumok hagyományosan közvetlenül a felhasználótól EventSourceöröklődnek. Speciális forgatókönyvek esetén azonban létrehozhat abstractEventSource objektumokat, úgynevezett segédprogramforrásokat, és implementálhat interfészeket. Az egyik vagy mindkét módszer használatával kódot oszthat meg a különböző származtatott források között.

Fontos

Az absztrakt EventSource objektumok nem határozhatnak meg kulcsszavakat, feladatokat, opcode-okat, csatornákat vagy eseményeket.

Fontos

Az esemény metaadatainak létrehozásakor a névütközések futásidőben történő elkerülése érdekében ne implementáljon explicit módon felületi metódusokat a felületekkel való EventSourcehasználat során.

Az alábbi példa egy felületet használó implementációt EventSource mutat be.

public interface IMyLogging
{
    void Error(int errorCode, string message);
    void Warning(string message);
}

public sealed class MySource : EventSource, IMyLogging
{
    public static MySource Log = new();

    [Event(1)]
    public void Error(int errorCode, string message) => WriteEvent(1, errorCode, message);

    [Event(2)]
    public void Warning(string message) => WriteEvent(2, message);
}

Az alábbi példa az Utility EventSource-mintát használó implementációt EventSource mutatja be.

public abstract class UtilBaseEventSource : EventSource
{
    protected UtilBaseEventSource()
        : base()
    { }

    protected UtilBaseEventSource(bool throwOnEventWriteErrors)
        : base(throwOnEventWriteErrors)
    { }

    // helper overload of WriteEvent for optimizing writing an event containing
    // payload properties that don't align with a provided overload. This prevents
    // EventSource from using the object[] overload which is expensive.
    protected unsafe void WriteEvent(int eventId, int arg1, short arg2, long arg3)
    {
        if (IsEnabled())
        {
            EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
            descrs[0] = new EventData { DataPointer = (IntPtr)(&arg1), Size = 4 };
            descrs[1] = new EventData { DataPointer = (IntPtr)(&arg2), Size = 2 };
            descrs[2] = new EventData { DataPointer = (IntPtr)(&arg3), Size = 8 };
            WriteEventCore(eventId, 3, descrs);
        }
    }
}

public sealed class OptimizedEventSource : UtilBaseEventSource
{
    public static OptimizedEventSource Log = new();

    public static class Keywords
    {
        public const EventKeywords Kwd1 = (EventKeywords)1;
    }

    [Event(1, Keywords = Keywords.Kwd1, Level = EventLevel.Informational, Message = "LogElements called {0}/{1}/{2}.")]
    public void LogElements(int n, short sh, long l) => WriteEvent(1, n, sh, l); // uses the overload we added!
}

Az alábbi példa egy kódtár egy összetevőjére vonatkozó nyomkövetési EventSource információk implementálását mutatja be.

public class ComplexComponent : IDisposable
{
    internal static Dictionary<string, string> _internalState = new();

    private string _name;

    public ComplexComponent(string name)
    {
        _name = name ?? throw new ArgumentNullException(nameof(name));
        ComplexSource.Log.NewComponent(_name);
    }

    public void SetState(string key, string value)
    {
        lock (_internalState)
        {
            _internalState[key] = value;
            ComplexSource.Log.SetState(_name, key, value);
        }
    }

    private void ExpensiveWork1() => System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(250));
    private void ExpensiveWork2() => System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(250));
    private void ExpensiveWork3() => System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(250));
    private void ExpensiveWork4() => System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(250));

    public void DoWork()
    {
        ComplexSource.Log.ExpensiveWorkStart(_name);

        ExpensiveWork1();
        ExpensiveWork2();
        ExpensiveWork3();
        ExpensiveWork4();

        ComplexSource.Log.ExpensiveWorkStop(_name);
    }

    public void Dispose()
    {
        ComplexSource.Log.ComponentDisposed(_name);
    }
}

internal sealed class ComplexSource : EventSource
{
    public static ComplexSource Log = new();

    public static class Keywords
    {
        public const EventKeywords ComponentLifespan = (EventKeywords)1;
        public const EventKeywords StateChanges = (EventKeywords)(1 << 1);
        public const EventKeywords Performance = (EventKeywords)(1 << 2);
        public const EventKeywords DumpState = (EventKeywords)(1 << 3);
        // a utility keyword for a common combination of keywords users might enable
        public const EventKeywords StateTracking = ComponentLifespan & StateChanges & DumpState;
    }

    protected override void OnEventCommand(EventCommandEventArgs args)
    {
        base.OnEventCommand(args);

        if (args.Command == EventCommand.Enable)
        {
            DumpComponentState();
        }
    }

    [Event(1, Keywords = Keywords.ComponentLifespan, Message = "New component with name '{0}'.")]
    public void NewComponent(string name) => WriteEvent(1, name);

    [Event(2, Keywords = Keywords.ComponentLifespan, Message = "Component with name '{0}' disposed.")]
    public void ComponentDisposed(string name) => WriteEvent(2, name);

    [Event(3, Keywords = Keywords.StateChanges)]
    public void SetState(string name, string key, string value) => WriteEvent(3, name, key, value);

    [Event(4, Keywords = Keywords.Performance)]
    public void ExpensiveWorkStart(string name) => WriteEvent(4, name);

    [Event(5, Keywords = Keywords.Performance)]
    public void ExpensiveWorkStop(string name) => WriteEvent(5, name);

    [Event(6, Keywords = Keywords.DumpState)]
    public void ComponentState(string key, string value) => WriteEvent(6, key, value);

    [NonEvent]
    public void DumpComponentState()
    {
        if (IsEnabled(EventLevel.Informational, Keywords.DumpState))
        {
            lock (ComplexComponent._internalState)
            {
                foreach (var (key, value) in ComplexComponent._internalState)
                    ComponentState(key, value);
            }
        }
    }
}