System.Diagnostics.Tracing.EventSource sınıfı

Bu makale, bu API'nin başvuru belgelerine ek açıklamalar sağlar.

sınıfı EventSource , olay izleme için kullanılacak belirli olayları sağlayan bir kullanıcı sınıfı tarafından devralınmaya yöneliktir. EventSource.WriteEvent Olayları günlüğe kaydetmek için yöntemler çağrılır.

temel işlevselliği EventSource çoğu uygulama için yeterlidir. Oluşturulan olay meta verileri üzerinde daha fazla denetime sahip olmak istiyorsanız, özniteliğini yöntemlere uygulayabilirsiniz EventAttribute . Gelişmiş olay kaynağı uygulamaları için türetilen olay kaynağına gönderilen komutları kesmek ve filtrelemeyi değiştirmek veya eylemlerin (veri yapısının dökümünü alma gibi) devralan tarafından gerçekleştirilmesini sağlamak mümkündür. Bir olay kaynağı, veya Logmangibi PerfView Windows için Olay İzleme (ETW) tabanlı araçlar veya gibi dotnet-trace EventPipe tabanlı araçlar kullanılarak işlem içinde etkinleştirilebilirEventListener. Veri dağıtıcısını program aracılığıyla denetlemek ve kesmek de mümkündür. EventListener sınıfı ek işlevsellik sağlar.

Kurallar

EventSource-derived sınıfları aşağıdaki kuralları izlemelidir:

  • Kullanıcı tanımlı sınıflar tekil bir desen uygulamalıdır. Tekil örnek geleneksel olarak olarak adlandırılır Log. Uzantıya göre, kullanıcılar el ile aramamalı IDisposable.Dispose ve yönetilen kod yürütmenin sonunda çalışma zamanının tekil örneği temizlemesine izin vermemelidir.
  • Kullanıcı tanımlı, türetilmiş bir sınıf, Gelişmiş Kullanım bölümünde açıklanan gelişmiş "Utility EventSource" yapılandırmasını uygulamadığı sürece olarak sealed işaretlenmelidir.
  • Bir olayı tetiklemeyle ilgili yoğun kaynak gerektiren bir çalışma gerçekleştirmeden önce çağrısı IsEnabled() yapın.
  • ve adlandırma desenini <EventName>Start<EventName>Stopiçeren sonraki olay kimliklerine sahip iki olay yöntemi bildirerek örtük olarak nesneler oluşturabilirsinizEventTask. Bu olaylar sınıf tanımında yan yana bildirilmelidir ve <EventName>Start yöntemi önce gelmelidir.
  • Nesneleri geriye dönük olarak uyumlu tutmaya EventSource ve uygun şekilde sürüme eklemeye çalışma. Bir olayın varsayılan sürümü şeklindedir 0. sürümü ayarıyla Versiondeğiştirilebilir. Yükün özelliklerini her değiştirdiğinizde olayın sürümünü değiştirin. Olay bildiriminin sonuna her zaman yeni yük özellikleri ekleyin. Bu mümkün değilse, eskisini değiştirmek için yeni bir kimlikle yeni bir olay oluşturun.
  • Olay yöntemlerini bildirirken, değişken boyuttaki özelliklerden önce sabit boyutlu yük özelliklerini belirtin.
  • EventKeywords bir sağlayıcıya abone olunduğunda belirli olayları belirtmek için bit maskesi olarak kullanılır. Üyeleri olan public const EventKeywords bir public static class Keywords üye sınıfı tanımlayarak anahtar sözcükler belirtebilirsiniz.
  • Pahalı olayları kullanarak EventKeywordsEventAttributeilişkilendirin. Bu düzen, kullanıcılarınızın EventSource bu pahalı işlemleri geri çevirmesini sağlar.

Kendini açıklayan (izleme) ve bildirim olayı biçimleri karşılaştırması

EventSource , kullanılan oluşturucuya veya üzerinde EventSourceOptionshangi bayrakların ayarlandığına bağlı olarak iki farklı moda yapılandırılabilir.

Geçmişte bu iki biçim, Windows için Olay İzleme'nin (ETW) kullandığı iki biçimden türetilmiştir. Bu iki mod, Windows için Olay İzleme (ETW) veya EventPipe tabanlı dinleyicileri kullanma becerinizi etkilemez ancak olaylar için meta verileri farklı şekilde oluşturur.

Varsayılan olay biçimi , EtwManifestEventFormatüzerinde EventSourceSettingsbelirtilmezse ayarlanır. Bildirim tabanlı EventSource nesneler, başlatmadan sonra sınıfında tanımlanan olayları temsil eden bir XML belgesi oluşturur. Bu, sağlayıcıyı ve olay meta verilerini oluşturmak için öğesinin kendi üzerine yansıtmasını gerektirir EventSource .

Kendini açıklayan (izleme) olay biçimini kullanmak için oluşturucuyu, EventSource(String, EventSourceSettings) oluşturucuyu EventSource(String) kullanarak veya bayrağını EtwSelfDescribingEventFormat üzerinde EventSourceSettingsayarlayarak oluşturma.EventSource Kendi kendini açıklayan kaynaklar başlatma sırasında en az sağlayıcı meta verilerini oluşturur ve yalnızca çağrıldığında Write(String) olay meta verileri oluşturur.

Uygulamada, bu olay biçimi ayarları yalnızca Windows için Olay İzleme 'yi (ETW) temel alan okuyucuların kullanımını etkiler. Ancak, yansıtma ve meta verileri oluşturma için gereken süre nedeniyle başlatma süresi ve olay başına yazma süreleri üzerinde küçük bir etkiye sahip olabilirler.

Örnekler

Aşağıdaki örnekte sınıfının basit bir uygulaması gösterilmektedir EventSource .

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

Aşağıdaki örnekte sınıfının daha karmaşık bir uygulaması gösterilmektedir EventSource .

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

Gelişmiş kullanım

Geleneksel olarak, kullanıcı tanımlı EventSource nesneler doğrudan öğesinden EventSourcedevralmayı bekler. Ancak gelişmiş senaryolar için Yardımcı Program Kaynakları adlı nesneler oluşturabilir abstractEventSource ve arabirimleri uygulayabilirsiniz. Bu tekniklerden birini veya her ikisini birden kullanmak, farklı türetilmiş kaynaklar arasında kod paylaşmanıza olanak tanır.

Önemli

Soyut EventSource nesneler anahtar sözcükleri, görevleri, opcode'ları, kanalları veya olayları tanımlayamaz.

Önemli

Olay meta verileri oluştururken çalışma zamanında ad çakışmalarını önlemek için ile EventSourcearabirimleri kullanırken arabirim yöntemlerini açıkça uygulamayın.

Aşağıdaki örnekte, arabirimi kullanan bir uygulaması EventSource gösterilmektedir.

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);
}

Aşağıdaki örnekte, Yardımcı Program EventSource desenini kullanan bir uygulaması EventSource gösterilmektedir.

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!
}

Aşağıdaki örnek, bir kitaplıktaki bir bileşen hakkında izleme bilgileri için uygulamasını EventSource gösterir.

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);
            }
        }
    }
}