我如何收听TPL TaskStarted / TaskCompleted ETW事件
我有兴趣听ETW(Windows的事件跟踪)TPL事件,特别是我想知道Task
何时开始以及何时停止。
这是我用于测试的示例程序:
using System; using System.Collections.Generic; using System.Diagnostics.Tracing; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication10 { class Listener : EventListener { private static readonly Guid tplGuid = new Guid("2e5dba47-a3d2-4d16-8ee0-6671ffdcd7b5"); protected override void OnEventSourceCreated(EventSource eventSource) { Console.WriteLine("Got guid: " + eventSource.Guid); EnableEvents(eventSource, EventLevel.LogAlways); } protected override void OnEventWritten(EventWrittenEventArgs eventData) { Console.WriteLine("Event: " + eventData.EventId); } } class Program { static void Main(string[] args) { using (var listener = new Listener()) { Action doIt = null; doIt = () => { Thread.Sleep(1000); Console.Write('.'); Task.Run(doIt); }; Task.Run(doIt); Parallel.Invoke(() => Console.WriteLine("invoke")); Console.Read(); } } } }
我的机器上的示例输出如下:
Got guid: 8e9f5090-2d75-4d03-8a81-e5afbf85daf1 Got guid: 2e5dba47-a3d2-4d16-8ee0-6671ffdcd7b5 Event: 3 invoke Event: 4 .......
因此,Invoke方法会导致事件触发,但任务不会触发任何事件。 查看任务源(例如参考源 ),代码与Parallel.Invoke
事件的触发方式没有什么不同。
上面有什么问题,或者,我如何监听TaskStarted和TaskCompleted事件(或任何与此相关的任务相关事件)?
你的问题让我想到了ETW(我一直想要研究一下)。 我能够使用Microsoft.Diagnostics.Tracing.TraceEvent NuGet库捕获“任务开始”和“任务结束”,其中包含以下简单代码:
private static void Main(string[] args) { Task.Run(() => { using (var session = new TraceEventSession("TplCaptureSession")) { session.EnableProvider(new Guid("2e5dba47-a3d2-4d16-8ee0-6671ffdcd7b5"), TraceEventLevel.Always); session.Source.Dynamic.AddCallbackForProviderEvent("System.Threading.Tasks .TplEventSource", "TaskExecute/Start", @event => { Console.WriteLine("Inside Task Started"); }); session.Source.Dynamic.AddCallbackForProviderEvent("System.Threading.Tasks .TplEventSource", "TaskExecute/Stop", @event => { Console.WriteLine("Inside Task Stopped"); }); session.Source.Process(); } }); var task = Task.Run(async () => { await Task.Delay(20000); }); task.Wait(); }
基本上会发生什么:
-
我们使用
TraceEventSession
开始新的实时事件捕获会话,我们将它传递给TraceEventLevel.Always
打印出所有消息(我们可以将其缩小到TranceEventLevel.Information
,但是对于我选择全部的示例)。 -
我们通过将其
Guid
传递给session.EnableProvider
来启用TplEventSource提供程序。 -
一旦
TplEventSource
(显然是TPL的事件源)触发TaskExecute/Start
或TaskExecute/Stop
事件(取自参考源 ),我们就会注册一个回调TplEventSource
-
一旦我们进入活动,我们就会打印出来。
注意我使用Task.Run
只是因为session.Source.Process()
是一个阻塞调用,我希望它在后台运行。
以下是我编写的代码示例 ,该代码仅使用BCL侦听TPL ETW事件。
绊倒我的部分是你需要运行这段代码的事实:
// Cause the type initializer for System.Threading.Tasks.TplEtwProvider to run. // Otherwise async method builders starting events will be missed. Type.GetType("System.Threading.Tasks.TplEtwProvider, mscorlib", true).GetField("Log").GetValue(null);
否则,一切似乎都按照你期望的方式运作。 不需要第三方库!