ETW,.NET 4.5 - 如何写入事件日志?

25

我正在努力理解ETW以及如何将其集成到高性能应用中。

我们都知道旧的EventLog以及它的非结构化API(因此不太优化)。

现在有一个新的高性能跟踪API-ETW,.NET 4.5版本中添加了一个名为EventSource的类,您可以轻松地对其进行子类化(因此不再需要编写清单)。

这使我有了一些问题,试图让它工作。

  • 目前是什么(根据文档和指南)最佳的工作方式来使用ETW并将事件从其中传递到EventLog?我有一个必须写入(性能)事件的应用程序,并希望使用ETW;但是事件应出现在(自定义)事件日志中。
  • 是否有完整的示例?我可以找到一些示例,但它们都是针对.NET 4.0时代的,并且始于清单。

我尝试了什么?我已经使EventSource工作,但是没有得到有关如何从下游获取正确文档的信息。


4
这是一个非常好的问题,我不知道为什么它被踩了。我花了很多时间晚上去研究它,但仍然没有找到答案。现在我已经开始编码了,大部分都是猜测。似乎 Vance 和 MSDN 是唯一的信息来源 - 但 Vance 只承诺稍后解释,而 MSDN 则没有帮助...... - Casper Leon Nielsen
请注意,使用WriteEvent方法可以使用EventLog类编写结构化条目。http://msdn.microsoft.com/en-us/library/vstudio/04bh0k4k.虽然需要编写清单并部署匹配的资源dll,并且它使用旧的事件API,但这种方法并不方便,但是它是可行的。 - fsimonazzi
@fsimonazzi请注意,根据我的评论,这完全是不必要的。答案是正确的-但是提到的那些错误在几个月前的nuget版本中已经被修复了。现在,您可以进行相当不错的结构化事件而不需要解决问题。 - TomTom
@TomTom,我只是想澄清一下你所说的无法使用EventLog进行结构化日志记录的问题。当然,使用EventSource会更好。 - fsimonazzi
顶一下这个问题!尽管有些博客对C#中的ETW进行了大肆宣传,但它似乎仍然是一个晦涩难懂且不够完善的(再次)微软库。我想看到一些真实世界的ETW用例,其中事件可以轻松地定向到第三方存储。 - Aaron Hudon
7个回答

10
在2013年8月,Microsoft.Diagnostics.Tracing.EventSource 1.0.4 beta发布于NuGet上。其中三个重要的改进是通道支持、静态(已安装)清单支持(这两个东西是进入事件查看器所必需的)和.NET 4.0支持。
根据宣布RTM的博客帖子,Microsoft.Diagnostics.Tracing.EventSource“使快速应用程序跟踪到Windows事件日志成为可能,包括在生产中使用”。

在博客文章中工作链接 - White hawk

8
由于以下原因,您想要达到的目标是不可能实现的:
  • 如果您想将ETW事件直接定向到事件日志,则需要在清单中指定Admin、Operational或一些经典通道(如Application),并使用wevtutil进行注册。很遗憾,即使您有一个清单,也不能使用EventSource来完成此操作,因为当调用WriteEvent时,底层实现不会在EventDescriptor块上设置通道字节,例如,您的事件永远不会被标记为特定通道。

  • EventSource在后台执行什么操作以避免冗长的过程,例如注册清单、将其编译为win32资源、将其链接到程序集/DLL、注册等等,是从您的EventSource实现生成清单,并将其作为已知事件发送以允许接收服务解析所有其他事件负载,而不是依赖于Windows基础架构来获取清单信息。据我所知,目前只有PerfView支持此功能。


谢谢你的回答,Lars。我一直在试图理解ETW,昨天也得出了与EventSource和通道相同的结论。我不知道“已知事件”的部分,但这很有道理。不幸的是,我认为这也使其基本上不兼容事件日志通道,这实际上是向管理员公开事件的最明智的方法,而不是期望他们使用其他工具来开始和停止跟踪会话等。:P - anton.burger
仅作为最终说明 - 根据2014年的情况,这一切都是错误的,因为微软最终开始改变了。现在,在NuGet(以发布形式)中提供了一个新的EventSource,它添加了适当的通道类型,以便可以将它们集成。终于。感谢微软修复了这个明显的疏忽;) 只需在Nuget中搜索EventSource即可找到它。 - TomTom
@LarsSkovslund EventSource会将清单作为事件发送,以供不进入通道的事件使用。对于那些需要进入通道的事件,您需要安装一个清单。NuGet包中包含了用于为您生成清单dll的工具(实际上是引用的EventRegister完成此操作)。 - fsimonazzi
@fsimonazzi 错了。这只适用于.NET框架中包含的版本 - nuget发布的版本可以设置标准通道(管理员、操作等),这非常好用;自Nuget下载的EventSource在新版本中完全可用,至少对于90%的情况来说 - 自定义通道是今天的问题。对我来说非常好用。 - TomTom
@TomTom,我在谈论EventSource nuget包。我从未声称它无法使用。您确实需要安装使用通道的提供程序的清单,但nuget包含使其变得容易的工具。安装EventSource nuget包(目前为v1.0.16),您将获得一个描述过程的文档文件,“确保为需要显式注册的每个EventSource类生成注册工件(DLL和MAN文件)将生成在项目的输出目录中(目前仅限使用ETW通道支持的类)”。 - fsimonazzi


0

0

你不应该在这里做广告。如果你有什么要提供的,请在此处提供,并使用“可访问”的来源引用。 - M--
好的。抱歉,我没有做广告。我只是在那里找到了答案。 - Oleksandr Bilyk

0

这非常有趣,因为我最近一直在处理类似的需求。首先,您可以使用EventSource类的静态方法GenerateManifest(typeof(MyEvents), null)生成清单。这将为您提供事件等的清单,但它不包含有关通道的详细信息。您需要在清单中自己定义通道,然后使用wevtutil.exe、mc.exe和rc.exe实用程序进行注册。这将根据清单中的提供程序名称为您创建事件日志。

有趣的是,我成功地让Debug和Analytic日志显示了通过EventSource生成的事件。我还可以使用Perfmon的跟踪会话记录带有关键字和级别过滤器的事件一段时间。提供程序也出现在跟踪会话提供程序列表中。

目前我唯一关注的是将事件带入Admim和Operation的通道。如果您需要示例等,请告诉我。

详细信息请参见- http://www.suneet.net/FrmBlogViewer.aspx?blogid=75


刚刚尝试手动修改清单(manifest)以按照下面所描述的方式添加频道标识“chid”到事件中,看起来它正在工作。在承诺之前,我将进一步测试它... <event value="2001" version="0" level="win:Informational" channel="Admin" keywords="Request" opcode="Start" task="Authentication" template="AuthenticationStartArgs" message="$(string.Event.AuthenticationStart)"/> - Suneet Nangia
进一步的调查表明,我们可以将事件绑定到特定的通道,并且它确实有效。然而,如果在C#中向事件添加关键字,则无法在Windows事件查看器中获取事件。我可以使用Trace Session跟踪它们,这至少证明了关键字已附加到事件上。我还没有找到让关键字附加事件可在事件查看器中查看的方法。 - Suneet Nangia

0

使用 .Net 3.5,引入了 Microsoft.Diagnostics.Tracing.EventSource,你可以在 nuget 上找到它,并且一些示例在 GitHub 这里

要写入 etw,请使用

using System.Diagnostics.Eventing;
    
    public void MyFunctionWithEtwLogging(){
       // ... some code
       MyEventSource.Log.Verbose("MyFunctionWithEtwLogging done");
    }

    [EventSource(Name = "MyEventSource")]
    sealed class MyEventSource : EventSource
    {
        [Event(1, Level = EventLevel.Error)]
        public void Error(string message) { WriteEvent(1, message); }

        [Event(2, Level = EventLevel.Warning)]
        public void Warning(string message) { WriteEvent(2, message); }

        [Event(3, Level = EventLevel.Informational)]
        public void Informational(string message) { WriteEvent(3, message); }

        
        public static MyEventSource Log = new LxTrackEventSource();
    }

阅读用

using Microsoft.Diagnostics.Tracing.Session;
using Microsoft.Diagnostics.Tracing;

using (TraceEventSession session = new TraceEventSession(MyUniqueSessionName)) {

    var restarted = _session.EnableProvider("MyEventSource", TraceEventLevel.Verbose, ulong.MaxValue, options);
    if (restarted)  Console.WriteLine("Session restarted");

    session.Source.Dynamic.All += delegate (TraceEvent data)
    {
         Console.WriteLine("Provider: {0}" data.ProviderName)
         Console.WriteLine("TimeStamp: {0}" data.TimeStamp)
         Console.WriteLine("EventName: {0}" data.EventName)
         Console.WriteLine("Message: {0}" GetPayloadString(data));
    }
    _session.Source.Process();

}

private string GetPayloadString(TraceEvent data, int expedtedPyloadCount = 1*/Depends on the count of payload*/)
    {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < expedtedPyloadCount ; i++)
    {
        sb.Append(data.PayloadString(i));
    }
    return sb.ToString();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接