EventSource 类

定义

提供跨平台为事件跟踪创建事件的功能。

public ref class EventSource : IDisposable
public class EventSource : IDisposable
[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicMethods | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicNestedTypes)]
public class EventSource : IDisposable
[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)]
public class EventSource : IDisposable
type EventSource = class
    interface IDisposable
[<System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicMethods | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicNestedTypes)>]
type EventSource = class
    interface IDisposable
[<System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)>]
type EventSource = class
    interface IDisposable
Public Class EventSource
Implements IDisposable
继承
EventSource
派生
属性
实现

示例

以下示例演示类的 EventSource 简单实现。

using System.Diagnostics.Tracing;

namespace Demo
{
    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

以下示例演示类 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 Program
    {
        static void Main(string[] args)
        {
            MyCompanyEventSource.Log.Startup();
            // ...
            MyCompanyEventSource.Log.OpenFileStart("SomeFile");
            // ...
            MyCompanyEventSource.Log.OpenFileStop();
        }
    }
}
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

高级用法

传统上,用户定义 EventSource 对象通常被期望直接从 EventSource 继承。 但是,对于高级方案,可以创建abstractEventSource对象,称为实用工具源,并实现接口。 使用其中一种或两种技术,可以在不同的派生源之间共享代码。

重要

抽象 EventSource 对象不能定义关键字、任务、操作码、通道或事件。

重要

为了避免在运行时生成事件元数据时发生名称冲突,在使用接口EventSource时不要显式实现接口方法。

以下示例演示一个使用接口的 EventSource 实现。

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

以下示例演示了使用该实用工具 EventSource 模式的 EventSource 实现。

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

以下示例演示了跟踪库中组件相关信息的实现 EventSource

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

注解

EventSource 类旨在由用户类继承,该类提供用于事件跟踪的特定事件。 调用 EventSource.WriteEvent 这些方法来记录事件。

基本功能 EventSource 足以满足大多数应用程序的需求。 如果希望更好地控制所创建的事件元数据,可以将属性应用于 EventAttribute 方法。 对于高级事件源应用程序,可以截获发送到派生事件源的命令并更改筛选,或导致继承者执行操作(如转储数据结构)。 事件源可以在进程内使用EventListener进行激活,或在进程外使用基于 EventPipe 的工具(如dotnet-trace)以及基于 Windows 的事件跟踪(ETW)工具(如PerfViewLogman)进行激活。 还可以以编程方式控制和截获数据调度程序。 该 EventListener 类提供其他功能。

Conventions

EventSource 派生类应遵循以下约定:

  • 用户定义的类应实现单例模式。 单一实例传统上命名 Log。 通过扩展,用户不应手动调用 IDisposable.Dispose ,并允许运行时在托管代码执行结束时清理单一实例。
  • 用户定义派生类应标记为 sealed ,除非它实现了“高级用法”部分中讨论的高级“实用工具 EventSource”配置。
  • 在执行与触发事件相关的任何资源密集型工作之前调用 IsEnabled()
  • 可以通过声明两个使用命名模式EventTask<EventName>Start且具有连续事件 ID 的事件方法,隐式创建<EventName>Stop对象。 这些事件 必须在 类定义中彼此旁边声明,并且 <EventName>Start 该方法 必须 首先出现。
  • 尝试使 EventSource 对象向后兼容并相应地对其进行版本控制。 事件的默认版本为 0。 可以通过设置 Version更改版本。 每当更改有效负载的属性时,请更新事件的版本。 始终将新的有效负载属性添加到事件声明的末尾。 如果无法做到这一点,请使用新 ID 创建新的事件来替换旧的事件。
  • 声明事件方法时,请先指定固定大小的有效负载属性,然后再指定可变大小的属性。
  • EventKeywords 在订阅提供程序时用作指定特定事件的位掩码。 可以通过定义 public static class Keywords 具有 public const EventKeywords 成员的成员类来指定关键字。
  • 使用 EventKeywords 将开销较大的事件与 EventAttribute 关联。 此模式允许 EventSource 的用户选择不进行这些昂贵的操作。

自描述(跟踪日志记录)与清单事件格式

EventSource 可以根据所用的构造函数或 EventSourceOptions 设置的标志,配置为两种不同的模式。

从历史上看,这两种格式派生自 Windows 事件跟踪(ETW)使用的两种格式。 虽然这两种模式不会影响使用 Windows 事件跟踪(ETW)或基于 EventPipe 的侦听器的能力,但它们确实会以不同的方式为事件生成元数据。

默认事件格式是 EtwManifestEventFormat,如果未指定 EventSourceSettings,则设置此格式。 基于 EventSource 清单的对象生成一个 XML 文档,该文档表示初始化时在类上定义的事件。 这需要 EventSource 自我反射以生成提供程序和事件元数据。

若要使用自描述的 (tracelogging) 事件格式,请构造您的 EventSource,方法是使用 EventSource(String) 构造函数、EventSource(String, EventSourceSettings) 构造函数或者在 EtwSelfDescribingEventFormat 上设置 EventSourceSettings 标志。 自描述源在初始化时生成最少的提供程序元数据,仅在调用Write(String)时才生成事件元数据。 与基于清单的格式不同,通过 ETW 进行侦听时,EventAttribute 属性中仅包含级别、关键字和操作码元数据。 不包括其他属性,如 EventId 或 Message。

实际上,这些事件格式设置仅影响基于 Windows 事件跟踪 (ETW) 的读取器的使用。 但是,由于反射和生成元数据所需的时间,它们对初始化时间和每事件写入时间的影响很小。

构造函数

名称 说明
EventSource()

创建类的新实例 EventSource

EventSource(Boolean)

创建 EventSource 类的新实例,并指定在基础Windows代码中发生错误时是否引发异常。

EventSource(EventSourceSettings, String[])

初始化要用于包含指定设置和特征的非协定事件的新实例 EventSource

EventSource(EventSourceSettings)

使用指定的配置设置创建类的新实例 EventSource

EventSource(String, EventSourceSettings, String[])

使用指定的配置设置创建类的新实例 EventSource

EventSource(String, EventSourceSettings)

使用指定的名称和设置创建类的新实例 EventSource

EventSource(String, Guid, EventSourceSettings, String[])

提供跨平台为事件跟踪创建事件的功能。

EventSource(String, Guid)

提供跨平台为事件跟踪创建事件的功能。

EventSource(String)

使用指定名称创建类的新实例 EventSource

属性

名称 说明
ConstructionException

获取在构造事件源期间引发的任何异常。

CurrentThreadActivityId

获取当前线程的活动 ID。

Guid

事件源的唯一标识符。

Name

派生自事件源的类的友好名称。

Settings

获取应用于此事件源的设置。

方法

名称 说明
Dispose()

释放类的 EventSource 当前实例使用的所有资源。

Dispose(Boolean)

释放类使用 EventSource 的非托管资源,并选择性地释放托管资源。

Equals(Object)

确定指定的对象是否等于当前对象。

(继承自 Object)
Finalize()

EventSource允许对象尝试释放资源并执行其他清理操作,然后再通过垃圾回收回收对象。

GenerateManifest(Type, String, EventManifestOptions)

返回与当前事件源关联的 XML 清单的字符串。

GenerateManifest(Type, String)

返回与当前事件源关联的 XML 清单的字符串。

GetGuid(Type)

获取此事件源实现的唯一标识符。

GetHashCode()

用作默认哈希函数。

(继承自 Object)
GetName(Type)

获取事件源的友好名称。

GetSources()

获取应用程序域的所有事件源的快照。

GetTrait(String)

获取与指定键关联的特征值。

GetType()

获取当前实例的 Type

(继承自 Object)
IsEnabled()

确定是否启用当前事件源。

IsEnabled(EventLevel, EventKeywords, EventChannel)

确定是否为具有指定级别、关键字和通道的事件启用当前事件源。

IsEnabled(EventLevel, EventKeywords)

确定是否启用具有指定级别和关键字的当前事件源。

MemberwiseClone()

创建当前 Object的浅表副本。

(继承自 Object)
OnEventCommand(EventCommandEventArgs)

当控制器更新当前事件源时调用。

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

将命令发送到指定的事件源。

SetCurrentThreadActivityId(Guid, Guid)

设置当前线程上的活动 ID,并返回以前的活动 ID。

SetCurrentThreadActivityId(Guid)

设置当前线程上的活动 ID。

ToString()

获取当前事件源实例的字符串表示形式。

Write(String, EventSourceOptions)

在没有字段的情况下写入事件,但具有指定的名称和选项。

Write(String)

在没有字段的情况下写入事件,但具有指定的名称和默认选项。

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

写入具有指定名称、选项、相关活动和事件数据的事件。

Write<T>(String, EventSourceOptions, T)

写入具有指定名称、事件数据和选项的事件。

Write<T>(String, EventSourceOptions, T)

写入具有指定名称、选项和事件数据的事件。

Write<T>(String, T)

写入具有指定名称和数据的事件。

WriteEvent(Int32, Byte[])

使用提供的事件标识符和字节数组参数写入事件。

WriteEvent(Int32, EventSource+EventSourcePrimitive[])

使用提供的事件标识符和可变数量的事件源基元写入事件。

WriteEvent(Int32, Int32, Int32, Int32)

使用提供的事件标识符和 32 位整数参数写入事件。

WriteEvent(Int32, Int32, Int32)

使用提供的事件标识符和 32 位整数参数写入事件。

WriteEvent(Int32, Int32, String)

使用提供的事件标识符和 32 位整数和字符串参数写入事件。

WriteEvent(Int32, Int32)

使用提供的事件标识符和 32 位整数参数写入事件。

WriteEvent(Int32, Int64, Byte[])

使用指定的标识符和 64 位整数和字节数组参数写入事件数据。

WriteEvent(Int32, Int64, Int64, Int64)

使用提供的事件标识符和 64 位参数写入事件。

WriteEvent(Int32, Int64, Int64)

使用提供的事件标识符和 64 位参数写入事件。

WriteEvent(Int32, Int64, String)

使用提供的事件标识符和 64 位整数和字符串参数写入事件。

WriteEvent(Int32, Int64)

使用提供的事件标识符和 64 位整数参数写入事件。

WriteEvent(Int32, Object[])

使用提供的事件标识符和参数数组写入事件。

WriteEvent(Int32, String, Int32, Int32)

使用提供的事件标识符和参数写入事件。

WriteEvent(Int32, String, Int32)

使用提供的事件标识符和参数写入事件。

WriteEvent(Int32, String, Int64)

使用提供的事件标识符和参数写入事件。

WriteEvent(Int32, String, String, String)

使用提供的事件标识符和字符串参数写入事件。

WriteEvent(Int32, String, String)

使用提供的事件标识符和字符串参数写入事件。

WriteEvent(Int32, String)

使用提供的事件标识符和字符串参数写入事件。

WriteEvent(Int32)

使用提供的事件标识符写入事件。

WriteEventCore(Int32, Int32, EventSource+EventData*)

使用提供的事件标识符和事件数据创建新的 WriteEvent 重载。

WriteEventWithRelatedActivityId(Int32, Guid, Object[])

写入一个事件,该事件指示当前活动与另一个活动相关。

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

写入一个事件,该事件指示当前活动与另一个活动相关。

活动

名称 说明
EventCommandExecuted

当命令来自事件侦听器时发生。

适用于

线程安全性

此类型是线程安全的。