DiagnosticSource专为进程内高性能诊断设计,用于捕获HttpContext等不可序列化对象及追踪异步上下文;EventSource则面向跨进程ETW场景,要求数据可序列化。

DiagnosticSource 不是日志工具,也不是通用事件总线。它专为进程内高性能诊断设计,只在你明确需要捕获不可序列化对象(如 HttpContext、HttpResponseMessage)或追踪异步上下文流转时才值得引入。
如何判断该用 DiagnosticSource 还是 EventSource
两者常被混淆,但定位完全不同:
-
EventSource用于跨进程/ETW 场景,所有数据必须可序列化,适合写入 Windows ETW 或 Linux LTTng; -
DiagnosticSource仅限同一进程内消费,允许传ref struct、Span<byte></byte>、IDisposable等类型,且无序列化开销; - 若你在写中间件、HttpClient 扩展或自定义
IAsyncEnumerable<T>实现,且需观察真实对象状态而非日志字符串,DiagnosticSource是唯一选择; - 误用
DiagnosticSource做业务事件广播,会导致内存泄漏(监听器未及时Dispose)和 GC 压力上升。
注册监听器时为什么收不到 "System.Net.Http" 事件
常见现象:代码写了 DiagnosticListener.AllListeners.Subscribe(...),但始终不触发 "RequestStart" 类事件。原因通常是:
-
DiagnosticSource实例必须在目标组件创建前就存在——HttpClient内部使用的是静态new DiagnosticListener("System.Net.Http"),若你在HttpClient实例化后才订阅,事件早已错过; - 监听器名称必须完全匹配,大小写敏感:
"System.Net.Http"≠"system.net.http"; - .NET 6+ 默认禁用部分诊断源,需显式启用:在
Program.cs开头加AppContext.SetSwitch("System.Net.Http.EnableDiagnostics", true);; - 检查是否被其他库覆盖了默认
DiagnosticListener,例如某些 APM SDK 会劫持全局监听器链,导致你的Subscribe失效。
Write 方法传参为什么不能直接 new {} 匿名对象
看似方便的写法:source.Write("MyEvent", new { Value = 42 });,实际可能引发 NullReferenceException 或静默丢弃事件。根本原因是:
-
DiagnosticSource.Write()不做反射解析,它直接把传入对象当有效负载(payload)传递给监听器; - 匿名类型是编译器生成的私有类,监听器若在不同程序集(如独立诊断工具),无法访问其属性;
- 推荐做法是定义公开的、轻量的结构体:
public readonly struct MyEventPayload { public int Value { get; } },并确保字段为public; - 若必须用匿名对象,监听器端需用
payload.GetType().GetProperties()反射读取——但性能差、不可靠,且破坏DiagnosticSource“零拷贝”设计初衷。
取消订阅不及时导致内存泄漏的真实表现
DiagnosticListener.Subscribe() 返回的 IDisposable 必须被释放,否则监听器会持续持有对消费者对象的强引用:
- 典型症状:GC 能力下降,
DiagnosticListener实例长期存活,关联的Observer对象无法回收; - 在 ASP.NET Core 中,若在
Middleware构造函数里订阅,却没在IDisposable.Dispose()中调用subscription.Dispose(),每次请求都会累积一个监听器实例; - 验证方式:用 dotMemory 或 PerfView 查看
DiagnosticListener+Subscription的实例数是否随请求线性增长; - 安全模式是使用
using语句包裹订阅逻辑,或在IServiceProvider生命周期结束时统一清理。
最易被忽略的一点:DiagnosticSource 的事件传播不经过 GC Root 检查,一旦监听器持有大对象(比如缓存的 byte[] 或 Stream),即使业务逻辑已退出,这些对象也不会被回收——这不是 bug,是设计使然,得靠开发者自己控制 payload 生命周期。


















