Отслеживание действий с параллельными потоками

#.net #trace

#.net #трассировка

Вопрос:

В MSDN я нашел статью о том, как назначить некоторые трассировки определенному действию. Это удобно при просмотре журнала трассировки в средстве просмотра трассировки служб Microsoft, потому что вы можете щелкнуть по действию, чтобы увидеть, что происходит с этим конкретным действием.

Вот пример кода из статьи, как вы присваиваете некоторому событию трассировки действие:

 Guid traceID = Guid.NewGuid();
ts.TraceTransfer(0, "transfer", traceID);
Trace.CorrelationManager.ActivityId = traceID; // Trace is static
ts.TraceEvent(TraceEventType.Start, 0, "Add request");
  

Проблема в том, что CorrelationManager является статическим и, следовательно, влияет на все приложение. Что вы делаете в многопоточном приложении?
К сожалению, я не нашел способа выполнить несколько параллельных действий.

Ответ №1:

Трассировка статична. Однако CorrelationManager хранит ActivityId и LogicalOperationStack в виде локального хранилища потока. CorrelationManager использует CallContext.LogicalSetData для хранения значений в CallContext.

Это означает, что каждый поток может иметь свой собственный ActivityId и LogicalOperationStack.

В псевдокоде реализация для трассировки.CorrelationManager и CorrelationManager.ActivityId выглядит примерно так:

 public static class Trace
{
  private static correlationManager = null;
  public CorrelationManager CorrelationManager
  {
    get
    {
      if (correlationManager == null) correlationManager = new CorrelationManager();
      return correlationManager;
    }
  }
}


public class CorrelationManager
{
  public Guid ActivityId
  {
    get
    {
      object id = CallContext.LogicalGetData("CorelationManager.ActivityId");
      if (id == null)
      {
        return Guid.Empty;
      }
      return (Guid) id;
    }
    set
    {
      CallContext.LogicalSetData("CorrelationManager.ActivityId", value);
    }
  }
}
  

Как вы можете видеть, существует только один «объект» трассировки (поскольку он статичен) и только один CorrelationManager (поскольку это свойство, экземпляр реального объекта, для объекта трассировки). Создание экземпляра контекстных данных для каждого потока (ActivityId и LogicalOperationStack) достигается с помощью объекта CallContext.

Данные, хранящиеся через CallContext.LogicalSetData, также «перетекают» в нижестоящие потоки. Итак, если вы задаете ActivityId в начале потока и этот поток впоследствии порождает потоки (которые могут порождать другие потоки), то все эти нижестоящие потоки будут иметь одинаковый ActivityId.

Вы можете увидеть исходный код для Trace и CorrelationManager здесь (не уверен, из какой версии .Net это, но я подозреваю, что это довольно близко к тому, как работают Trace и CorrelationManager сегодня:

Трассировка

CorrelationManager

Комментарии:

1. Хм, с этим есть какая-то проблема — мы попробовали трассировку. CorrelationManager. ActivityId в приложении MVC, и это работало нормально, пока мы не запустили несколько параллельных веб-запросов — тогда ActivityId иногда внезапно переходил к ‘00000000-0000-0000-0000-000000000000’. Кажется, там что-то сломано. Возможно, нам придется сохранить наш собственный ActivityId в HttpContext, но мы не уверены, поможет ли это.