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

Uyarı

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. Olaylar günlüğe kaydedilmek için EventSource.WriteEvent yöntemleri ç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ğı, işlem içinde EventListener kullanılarak ve EventPipe tabanlı araçlar, dotnet-trace gibi, veya Windows için Olay İzleme (ETW) tabanlı araçlar, PerfView veya Logman gibi, kullanılarak işlem dışında etkinleştirilebilir. 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 singleton tasarımını uygulamalıdır. Tekil örnek geleneksel olarak Log şeklinde adlandırılır. Kullanıcılar, IDisposable.Dispose işlevini elle çağırmamalı ve yönetilen kod yürütmesi sona erdiğinde çalışma zamanının tekil örneği temizlemesine izin vermelidir.
  • 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.
  • Etkinlik tetikleme ile ilgili kaynak yoğun bir iş gerçekleştirmeden önce IsEnabled()'ı çağırın.
  • Örtük olarak EventTask nesneleri, <EventName>Start adlandırma desenini takip eden ardışık olay kimliklerine sahip iki olay yöntemi bildirerek oluşturabilirsiniz<EventName>Stop. Bu olaylar sınıf tanımında yan yana bildirilmelidir ve <EventName>Start yöntemi önce gelmelidir.
  • Nesneleri geriye dönük uyumlu tutmak ve bunları uygun şekilde versiyonlamak için çalışın. Bir etkinliğin varsayılan sürümü 0. Sürüm, Version ayarıyla değ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 static class Keywords bir public const EventKeywords üye sınıfı tanımlayarak anahtar sözcükler belirtebilirsiniz.
  • Pahalı olayları bir EventKeywords ile EventAttribute kullanarak ilişkilendirin. Bu model, kullanıcılarınızın EventSource bu pahalı işlemlerden vazgeçmelerine olanak tanır.

Kendini açıklayan (iz kaydı) ve bildirim olayı biçimleri

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 EventSource öğesinin kendi üzerinde yansımasını gerektirir.

Kendini açıklayan (izleme) olay biçimini kullanmak için, EventSource'yi EventSource(String) oluşturucusunu kullanarak, EventSource(String, EventSourceSettings) oluşturucusunu kullanarak veya EtwSelfDescribingEventFormat bayrağını EventSourceSettings üzerine ayarlayarak oluşturun. Öz tanımlayıcı kaynaklar, başlatma sırasında mümkün olan en az sağlayıcı meta verisini oluşturur ve yalnızca Write(String) çağrıldığında olay meta verilerini oluşturur. Bildirim tabanlı biçimin aksine, ETW aracılığıyla dinlerken öznitelikten EventAttribute yalnızca Düzey, Anahtar Sözcük ve Opcode meta verileri eklenir. EventId veya Message gibi diğer özellikler dahil değildir.

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 EventSource öğesinden devralmayı bekler. Ancak gelişmiş senaryolar için Yardımcı Program Kaynaklarıabstractnesneler oluşturabilir EventSource 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 EventSource arabirimleri kullanırken arabirim yöntemlerini açıkça uygulamayın.

Aşağıdaki örnek, bir arabirim kullanan bir uygulamanın EventSource'ı nasıl kullandığını göstermektedir.

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