eventsource 必须显式指定 name 特性(如 [eventsource(name = "mycompany.myapp")]),确保 provider 名匹配且符合 etw 规范;监听需调用 enableevents 并核对 name、level、keywords;避免大对象传参、耗时计算及缓冲区满导致静默丢事件。

EventSource 怎么写才不会被忽略
默认情况下,EventSource 发出的事件会被系统丢弃——不是代码没跑,而是没启用监听或没配对提供者名称。关键点在于:类名必须匹配 EventSource 构造时传入的 name,且该 name 会成为 ETW 会话里的 Provider GUID 或字符串标识。
常见错误是直接继承 EventSource 却没指定 name,导致 Windows 无法识别这个提供者:
public class MyEventSource : EventSource
{
public static MyEventSource Log = new MyEventSource();
[Event(1)] public void RequestStarted(string url) => WriteEvent(1, url);
}
这段代码注册的 Provider 名是 MyEventSource(类全名),但实际调试时你会发现 logman query providers | findstr My 找不到它——因为 .NET 默认用 Guid 做 name,而类名只是 fallback。正确做法是显式传入稳定字符串:
- 使用
[EventSource(Name = "MyCompany.MyApp")]特性修饰类 - 确保 name 不含空格、不以数字开头、长度合理(ETW 对 provider name 有字符限制)
- 避免每次新建实例都 new 一个
EventSource,静态单例是标准实践 - 发布前务必调用
MyEventSource.Log.Dispose(),否则可能残留未刷新的缓冲事件
EventListener 接收不到事件?检查这三处
EventListener 不是“启动就自动收”,它只监听已启用(enabled)的 Provider。即使你的 EventSource 写对了,没调用 EnableEvents 就等于没打开水龙头。
典型漏点:
- 忘记在
OnEventSourceCreated里调用EnableEvents(eventSource, EventLevel.Informational, EventKeywords.All) - 传错
EventLevel:比如EventSource里用[Event(1, Level = EventLevel.Verbose)],但EnableEvents只设了Informational,那这条事件永远进不来 - Provider name 不一致:
EventSource的 name 是"MyCompany.MyApp",但你在EnableEvents里写成了"MyApp",匹配失败
验证是否启用成功,可在 OnEventWritten 里加断点,或用 PowerShell 快速确认:
Get-WinEvent -ListProvider "MyCompany.MyApp"
如果返回空,说明 Provider 没注册成功;如果有结果但没事件,大概率是 level 或 keywords 过滤掉了。
性能敏感场景下 EventSource 的坑
EventSource 默认走内核 ETW 缓冲区,看似无锁,但频繁写入仍可能触发缓冲区满、丢事件(EventSource.SendCommand 返回 false)、甚至拖慢主线程。尤其在高并发日志场景中,容易误以为“没打出来”是逻辑问题,其实是被限流了。
- 避免在
[Event]方法里传大对象(如整个Exception实例),应提取关键字段(ex.Message,ex.GetType().Name) - 不要在
WriteEvent调用前做耗时计算,例如字符串拼接、JSON 序列化——这些该提前做好,参数传进去就是最终值 - 启用
EventSourceSettings.EtwSelfDescribingEventFormat会增加序列化开销,仅在需要跨平台解析时开启 - 生产环境建议关闭
Verbose级别,用Informational或Warning控制量级
如何用 dotnet-trace 抓到自己的 EventSource
dotnet-trace 是最轻量的线上诊断工具,但它默认只捕获 SDK 自带 Provider(如 Microsoft-Windows-DotNETRuntime)。要抓自定义的,必须显式加 --providers 参数。
命令格式:
dotnet-trace collect --providers "MyCompany.MyApp:0x0000000000000001:5" --duration 30s
其中:
-
MyCompany.MyApp是你EventSource.Name -
0x0000000000000001是 keywords 的十六进制掩码(0x1表示所有 keywords) -
5是 level(5 = Verbose,4 = Informational,3 = Warning)
抓完生成 trace.nettrace,用 dotnet trace convert 转成 JSON 查看,或直接用 PerfView 打开——注意 PerfView 的 “Collect → Run” 页里也要手动勾选你的 Provider 名称,否则照样看不到。
真正难的不是写两行 WriteEvent,而是让事件从进程内存穿过 ETW 内核管道,再被工具稳稳接住。中间任何一环 name、level、keywords、buffer size、enable 时机对不上,都会静默失败。










