In MSDN I found an article on how to assign some traces to a specific action. This comes in handy when examining a trace log in the Microsoft Service Trace Viewer, because you can click on an activity to see what’s going on with that specific action.
Here’s the code example from the article, how you assign some trace event to an action:
Guid traceID = Guid.NewGuid();
ts.TraceTransfer(0, "transfer", traceID);
Trace.CorrelationManager.ActivityId = traceID; // Trace is static
ts.TraceEvent(TraceEventType.Start, 0, "Add request");
The problem is: CorrelationManager is static and thus affects the whole application. What do you do in a multi-threaded application?
Unfortunately I found no way to accomplish multiple parallel activities.
Trace is static. However, CorrelationManager stores ActivityId and LogicalOperationStack in a form of thread local storage. CorrelationManager uses CallContext.LogicalSetData to store values in the CallContext.
This means that each thread can have its own ActivityId and LogicalOperationStack.
In pseudocode the implementation for Trace.CorrelationManager and CorrelationManager.ActivityId looks something like this:
As you can see, there is only one Trace “object” (since it is static) and there is only one CorrelationManager (since it is a property, a real object instance, on the Trace object). Per-thread instancing of context data (ActivityId and LogicalOperationStack) is achieved via the CallContext object.
Data stored via CallContext.LogicalSetData also “flows” to downstream threads. So, if you set ActivityId at the beginning of a thread and that that thread subsequently spawns threads (which might spawn other threads), then all of those downstream threads will have the same ActivityId.
You can see the source for Trace and CorrelationManager here (not sure what version of .Net this is from, but I suspect that it is pretty close to how Trace and CorrelationManager work today:
Trace
CorrelationManager