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 Logman
gibi 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>Stop
iç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
birpublic static class Keywords
üye sınıfı tanımlayarak anahtar sözcükler belirtebilirsiniz. - Pahalı olayları kullanarak EventKeywords EventAttributeiliş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 abstract
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 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);
}
}
}
}