EventSource Class

Definition

Provides the ability to create events for event tracing across platforms.

public ref class EventSource : IDisposable
public class EventSource : IDisposable
type EventSource = class
    interface IDisposable
Public Class EventSource
Implements IDisposable
Inheritance
EventSource
Derived
Implements

Examples

The following example shows a simple implementation of the EventSource class.

using System.Diagnostics.Tracing;
using System.Collections.Generic;

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 Program
    {
        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

The following example shows a more complex implementation of the EventSource class.

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 MyCompanyEventSource
    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 MyCompanyEventSource()
End Class


Class Program

    Shared Sub Main(ByVal args() As String)
        MyCompanyEventSource.Log.Startup()
        Console.WriteLine("Starting up")
        MyCompanyEventSource.Log.DBQueryStart("Select * from MYTable")
        Dim url As String = "http:'localhost"
        Dim i As Integer
        For i = 0 To 9
            MyCompanyEventSource.Log.PageStart(i, url)
            MyCompanyEventSource.Log.Mark(i)
            MyCompanyEventSource.Log.PageStop(i)
        Next 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")
    End Sub
End Class

Advanced Usage

Traditionally, user-defined EventSource objects expect to inherit directly from EventSource. For advanced scenarios, however, you can create abstract EventSource objects, called Utility Sources, and implement interfaces. Using one or both of these techniques allows you to share code between different derived sources.

Important

Abstract EventSource objects cannot define keywords, tasks, opcodes, channels, or events.

Important

To avoid name collisions at run time when generating event metadata, don't explicitly implement interface methods when using interfaces with EventSource.

The following example shows an implementation of EventSource that uses an interface.

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

The following example shows an implementation of EventSource that uses the Utility EventSource pattern.

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

The following example shows an implementation of EventSource for tracing information about a component in a library.

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

Remarks

This class is intended to be inherited by a user class that provides specific events to be used for event tracing. The EventSource.WriteEvent methods are called to log the events.

The basic functionality of EventSource is sufficient for most applications. If you want more control over the event metadata that's created, you can apply the EventAttribute attribute to the methods. For advanced event source applications, it is possible to intercept the commands being sent to the derived event source and change the filtering, or to cause actions (such as dumping a data structure) to be performed by the inheritor. An event source can be activated in-process using EventListener and out-of-process using EventPipe-based tools such as dotnet-trace or Event Tracing for Windows (ETW) based tools like PerfView or Logman. It is also possible to programmatically control and intercept the data dispatcher. The EventListener class provides additional functionality.

Conventions

EventSource-derived classes should follow the following conventions:

  • User-defined classes should implement a singleton pattern. The singleton instance is traditionally named Log. By extension, users should not call IDisposable.Dispose manually and allow the runtime to clean up the singleton instance at the end of managed code execution.
  • A user-defined, derived class should be marked as sealed unless it implements the advanced "Utility EventSource" configuration discussed in the Advanced Usage section.
  • Call IsEnabled() before performing any resource intensive work related to firing an event.
  • You can implicitly create EventTask objects by declaring two event methods with subsequent event IDs that have the naming pattern <EventName>Start and <EventName>Stop. These events must be declared next to each other in the class definition and the <EventName>Start method must come first.
  • Attempt to keep EventSource objects backwards compatible and version them appropriately. The default version for an event is 0. The version can be can be changed by setting Version. Change the version of an event whenever you change properties of the payload. Always add new payload properties to the end of the event declaration. If this is not possible, create a new event with a new ID to replace the old one.
  • When declaring event methods, specify fixed-size payload properties before variably sized properties.
  • EventKeywords are used as a bit mask for specifying specific events when subscribing to a provider. You can specify keywords by defining a public static class Keywords member class that has public const EventKeywords members.
  • Associate expensive events with an EventKeywords using EventAttribute. This pattern allows users of your EventSource to opt out of these expensive operations.

Self-describing (tracelogging) vs. manifest event formats

EventSource can be configured into to two different modes based on the constructor used or what flags are set on EventSourceOptions.

Historically, these two formats are derived from two formats that Event Tracing for Windows (ETW) used. While these two modes don't affect your ability to use Event Tracing for Windows (ETW) or EventPipe-based listeners, they do generate the metadata for events differently.

The default event format is EtwManifestEventFormat, which is set if not specified on EventSourceSettings. Manifest-based EventSource objects generate an XML document representing the events defined on the class upon initialization. This requires the EventSource to reflect over itself to generate the provider and event metadata.

To use self-describing (tracelogging) event format, construct your EventSource using the EventSource(String) constructor, the EventSource(String, EventSourceSettings) constructor, or by setting the EtwSelfDescribingEventFormat flag on EventSourceSettings. Self-describing sources generate minimal provider metadata on initialization and only generate event metadata when Write(String) is called.

In practice, these event format settings only affect usage with readers based on Event Tracing for Windows (ETW). They can, however, have a small effect on initialization time and per-event write times due to the time required for reflection and generating the metadata.

Constructors

EventSource()

Creates a new instance of the EventSource class.

EventSource(Boolean)

Creates a new instance of the EventSource class and specifies whether to throw an exception when an error occurs in the underlying Windows code.

EventSource(EventSourceSettings)

Creates a new instance of the EventSource class with the specified configuration settings.

EventSource(EventSourceSettings, String[])

Initializes a new instance of the EventSource to be used with non-contract events that contains the specified settings and traits.

EventSource(String)

Creates a new instance of the EventSource class with the specified name.

EventSource(String, EventSourceSettings)

Creates a new instance of the EventSource class with the specified name and settings.

EventSource(String, EventSourceSettings, String[])

Creates a new instance of the EventSource class with the specified configuration settings.

Properties

ConstructionException

Gets any exception that was thrown during the construction of the event source.

CurrentThreadActivityId

Gets the activity ID of the current thread.

Guid

The unique identifier for the event source.

Name

The friendly name of the class that is derived from the event source.

Settings

Gets the settings applied to this event source.

Methods

Dispose()

Releases all resources used by the current instance of the EventSource class.

Dispose(Boolean)

Releases the unmanaged resources used by the EventSource class and optionally releases the managed resources.

Equals(Object)

Determines whether the specified object is equal to the current object.

(Inherited from Object)
Finalize()

Allows the EventSource object to attempt to free resources and perform other cleanup operations before the object is reclaimed by garbage collection.

GenerateManifest(Type, String)

Returns a string of the XML manifest that is associated with the current event source.

GenerateManifest(Type, String, EventManifestOptions)

Returns a string of the XML manifest that is associated with the current event source.

GetGuid(Type)

Gets the unique identifier for this implementation of the event source.

GetHashCode()

Serves as the default hash function.

(Inherited from Object)
GetName(Type)

Gets the friendly name of the event source.

GetSources()

Gets a snapshot of all the event sources for the application domain.

GetTrait(String)

Gets the trait value associated with the specified key.

GetType()

Gets the Type of the current instance.

(Inherited from Object)
IsEnabled()

Determines whether the current event source is enabled.

IsEnabled(EventLevel, EventKeywords)

Determines whether the current event source that has the specified level and keyword is enabled.

IsEnabled(EventLevel, EventKeywords, EventChannel)

Determines whether the current event source is enabled for events with the specified level, keywords and channel.

MemberwiseClone()

Creates a shallow copy of the current Object.

(Inherited from Object)
OnEventCommand(EventCommandEventArgs)

Called when the current event source is updated by the controller.

SendCommand(EventSource, EventCommand, IDictionary<String,String>)

Sends a command to a specified event source.

SetCurrentThreadActivityId(Guid)

Sets the activity ID on the current thread.

SetCurrentThreadActivityId(Guid, Guid)

Sets the activity ID on the current thread, and returns the previous activity ID.

ToString()

Obtains a string representation of the current event source instance.

ToString()

Returns a string that represents the current object.

(Inherited from Object)
Write(String)

Writes an event without fields, but with the specified name and default options.

Write(String, EventSourceOptions)

Writes an event without fields, but with the specified name and options.

Write<T>(String, EventSourceOptions, Guid, Guid, T)

Writes an event with the specified name, options, related activity and event data.

Write<T>(String, EventSourceOptions, T)

Writes an event with the specified name, event data and options.

Write<T>(String, EventSourceOptions, T)

Writes an event with the specified name, options and event data.

Write<T>(String, T)

Writes an event with the specified name and data.

WriteEvent(Int32)

Writes an event by using the provided event identifier.

WriteEvent(Int32, Byte[])

Writes an event by using the provided event identifier and byte array argument.

WriteEvent(Int32, Int32)

Writes an event by using the provided event identifier and 32-bit integer argument.

WriteEvent(Int32, Int32, Int32)

Writes an event by using the provided event identifier and 32-bit integer arguments.

WriteEvent(Int32, Int32, Int32, Int32)

Writes an event by using the provided event identifier and 32-bit integer arguments.

WriteEvent(Int32, Int32, String)

Writes an event by using the provided event identifier and 32-bit integer and string arguments.

WriteEvent(Int32, Int64)

Writes an event by using the provided event identifier and 64-bit integer argument.

WriteEvent(Int32, Int64, Byte[])

Writes the event data using the specified identifier and 64-bit integer and byte array arguments.

WriteEvent(Int32, Int64, Int64)

Writes an event by using the provided event identifier and 64-bit arguments.

WriteEvent(Int32, Int64, Int64, Int64)

Writes an event by using the provided event identifier and 64-bit arguments.

WriteEvent(Int32, Int64, String)

Writes an event by using the provided event identifier and 64-bit integer, and string arguments.

WriteEvent(Int32, Object[])

Writes an event by using the provided event identifier and array of arguments.

WriteEvent(Int32, String)

Writes an event by using the provided event identifier and string argument.

WriteEvent(Int32, String, Int32)

Writes an event by using the provided event identifier and arguments.

WriteEvent(Int32, String, Int32, Int32)

Writes an event by using the provided event identifier and arguments.

WriteEvent(Int32, String, Int64)

Writes an event by using the provided event identifier and arguments.

WriteEvent(Int32, String, String)

Writes an event by using the provided event identifier and string arguments.

WriteEvent(Int32, String, String, String)

Writes an event by using the provided event identifier and string arguments.

WriteEventCore(Int32, Int32, EventSource+EventData*)

Creates a new WriteEvent overload by using the provided event identifier and event data.

WriteEventWithRelatedActivityId(Int32, Guid, Object[])

Writes an event that indicates that the current activity is related to another activity.

WriteEventWithRelatedActivityIdCore(Int32, Guid*, Int32, EventSource+EventData*)

Writes an event that indicates that the current activity is related to another activity.

Events

EventCommandExecuted

Occurs when a command comes from an event listener.

Applies to

Thread Safety

This type is thread safe.