How do I listen to TPL TaskStarted/TaskCompleted ETW events

北城余情 提交于 2019-11-30 19:31:27

Your question challanged me to look into ETW (which I've been wanting to look into for a while). I was able to capture "task start" and "task end" using Microsoft.Diagnostics.Tracing.TraceEvent NuGet library with the simple following code:

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();
}

Basically what happens is:

  1. We start new a live event capturing session using TraceEventSession where we pass it TraceEventLevel.Always to print out all messages (we could narrow this down to TranceEventLevel.Information, but for the example I chose all).

  2. We enable the TplEventSource provider by passing its Guid to session.EnableProvider.

  3. We register a callback to be invoked once TplEventSource (which is the event source for TPL, obviously) fires either TaskExecute/Start or TaskExecute/Stop events (taken from the reference source)

  4. We print out once we're inside the event.

Note my use of Task.Run was simply because session.Source.Process() is a blocking call, and I wanted it to run in the background.

Here is an example of code I wrote that listens to TPL ETW events using only the BCL.

The part that tripped me up was the fact that you need to run this code:

// 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);

Otherwise, everything just seems to work the way you'd expect. No need for third-party libraries!

Base on Yuvals answer that didn't work for me because the event names seem to be different, I have come up with a solution that is typesafe and does not use magic guids or strings:

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.Diagnostics.Tracing;
using Microsoft.Diagnostics.Tracing.Parsers;
using Microsoft.Diagnostics.Tracing.Parsers.Tpl;
using Microsoft.Diagnostics.Tracing.Session;

...

Task.Run(() =>
{
    using (var session = new TraceEventSession("TplCaptureSession"))
    {
        session.EnableProvider(TplEtwProviderTraceEventParser.ProviderGuid, TraceEventLevel.Always);

        var parser = new TplEtwProviderTraceEventParser(session.Source);
parser.AddCallbackForEvent<TaskStartedArgs>(
            null,
            @event =>
            {
                Console.WriteLine($"Task {@event.TaskID} started by {@event.OriginatingTaskID}");
            });

        parser.AddCallbackForEvent<TaskCompletedArgs>(
            null,
            @event =>
            {
                Console.WriteLine($"Task {@event.TaskID} completed");
            });

        session.Source.Process();
    }
});

And for completeness, here is a list of event names I have seen being generated by the System.Threading.Tasks.TplEventSource source:

  • AwaitTaskContinuationScheduled/Send
  • DebugFacilityMessage
  • DebugFacilityMessage1
  • DebugMessage
  • EventSourceMessage
  • ForkJoin/Start
  • ForkJoin/Stop
  • IncompleteAsyncMethod
  • Invoke/Start
  • Invoke/Stop
  • Loop/Start
  • Loop/Stop
  • ManifestData
  • NewID
  • RunningContinuation
  • RunningContinuationList
  • SetActivityId
  • TaskCompleted
  • TaskScheduled/Send
  • TaskStarted
  • TaskWait/Send
  • TaskWaitContinuationComplete
  • TaskWaitContinuationStarted
  • TaskWaitEnd
  • TraceOperationBegin
  • TraceOperationEnd
  • TraceOperationRelation
  • TraceSynchronousWorkBegin
  • TraceSynchronousWorkEnd
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!