TraceContext.cs
211 lines
| 9.9 KiB
| text/x-csharp
|
CSharpLexer
cin
|
r36 | using System; | ||
using System.Collections.Generic; | ||||
using System.Linq; | ||||
using System.Text; | ||||
using System.Threading; | ||||
using System.Threading.Tasks; | ||||
namespace Implab.Diagnostics { | ||||
cin
|
r40 | /// <summary> | ||
/// Контекст трассировки, привязывается к потоку и содержит в себе информацию о стеке логических операций. | ||||
/// </summary> | ||||
/// <remarks> | ||||
/// Контекст трассировки передается слушателям событий для определения места, где возникло событие. | ||||
/// </remarks> | ||||
cin
|
r36 | public class TraceContext { | ||
LogicalOperation m_currentOperation; | ||||
cin
|
r40 | readonly LogicalOperation m_bound; | ||
cin
|
r36 | readonly int m_threadId; | ||
[ThreadStatic] | ||||
static TraceContext _current; | ||||
cin
|
r40 | /// <summary> | ||
/// Текущий контекст трассировки для потока, создается астоматически при первом обращении. | ||||
/// </summary> | ||||
cin
|
r36 | public static TraceContext Current { | ||
get { | ||||
cin
|
r48 | if (_current == null) { | ||
cin
|
r36 | _current = new TraceContext(); | ||
cin
|
r48 | _current.LogEvent(TraceEventType.Created,"[{0}]", _current.ThreadId); | ||
} | ||||
cin
|
r36 | return _current; | ||
} | ||||
} | ||||
cin
|
r48 | TraceContext(TraceContext context) | ||
: this(context, false) { | ||||
} | ||||
TraceContext(TraceContext context, bool attach) { | ||||
cin
|
r36 | if (context == null) | ||
throw new ArgumentNullException("context"); | ||||
m_currentOperation = context.CurrentOperation; | ||||
cin
|
r48 | m_bound = attach ? context.BoundOperation : context.CurrentOperation; | ||
cin
|
r36 | m_threadId = Thread.CurrentThread.ManagedThreadId; | ||
} | ||||
TraceContext() { | ||||
m_currentOperation = new LogicalOperation(); | ||||
cin
|
r40 | m_bound = m_currentOperation; | ||
cin
|
r36 | m_threadId = Thread.CurrentThread.ManagedThreadId; | ||
} | ||||
cin
|
r40 | /// <summary> | ||
/// При необходимости копирует состояние контекста трассивровки в текущий поток. | ||||
/// </summary> | ||||
/// <param name="from">Исходный контекст трассировки, который передается.</param> | ||||
/// <remarks> | ||||
/// <para> | ||||
/// Копирование происходит за счет создания нового контекста трассировки и заполнением его | ||||
/// состояния из переданного контекста. При этом копируется стек операций, однако в новом | ||||
/// контексте ранее начатые логические операции не могут быть завершены. | ||||
/// </para> | ||||
/// <para> | ||||
cin
|
r48 | /// Если передача состояния состоялась, то вызывается событие трассировки <see cref="TraceEventType.Fork"/>. | ||
cin
|
r40 | /// </para> | ||
/// </remarks> | ||||
cin
|
r48 | public static void Fork(TraceContext from) { | ||
cin
|
r40 | if (_current == from) | ||
return; | ||||
if (from != null) { | ||||
var context = new TraceContext(from); | ||||
cin
|
r48 | context.LogEvent(TraceEventType.Fork, "[{0}]-->[{1}]",from.ThreadId, context.ThreadId); | ||
cin
|
r40 | _current = context; | ||
} else { | ||||
_current = new TraceContext(); | ||||
cin
|
r36 | } | ||
} | ||||
cin
|
r40 | /// <summary> | ||
cin
|
r48 | /// Задает текущему потоку указанный контекст, текущей поток может заканчивать ранее начатые | ||
/// логические операции в указанном контексте. | ||||
/// </summary> | ||||
/// <param name="source"></param> | ||||
public static void Attach(TraceContext source) { | ||||
if (_current == source) | ||||
return; | ||||
if (source != null) { | ||||
var context = new TraceContext(source, true); | ||||
context.LogEvent(TraceEventType.Attach, "[{0}]-->[{1}]", source.ThreadId, context.ThreadId); | ||||
_current = context; | ||||
} else { | ||||
_current = new TraceContext(); | ||||
} | ||||
} | ||||
/// <summary> | ||||
/// Отсоединяет текущий контекст трассировки от потока, для дальнейшей его передачи другому потоку | ||||
/// <see cref="Attach(TraceContext)"/>. | ||||
/// </summary> | ||||
/// <returns>Контекст трассировки потока</returns> | ||||
/// <remarks> | ||||
/// После отсоединения контекста трассировки от потока, при первом обращении к трассировке в этом | ||||
/// потоке будет создан новый контекст. | ||||
/// </remarks> | ||||
public static TraceContext Detach() { | ||||
var context = Current; | ||||
context.LogEvent(TraceEventType.Detach, null); | ||||
_current = null; | ||||
return context; | ||||
} | ||||
/// <summary> | ||||
/// Создает постоянную копию текущего контекста, данную копию можно хранить и использовать для передачи через <see cref="Fork(TraceContext)"/> | ||||
cin
|
r40 | /// </summary> | ||
cin
|
r41 | /// <returns>Копия текущего контекста трассировки.</returns> | ||
cin
|
r40 | public static TraceContext Snapshot() { | ||
cin
|
r41 | return _current == null ? new TraceContext() : new TraceContext(_current); | ||
cin
|
r40 | } | ||
/// <summary> | ||||
/// Выполняет переданное действие в указанном контексте трассировки, по окончании восстанавливает предыдущий контекст трассировки потока. | ||||
/// </summary> | ||||
/// <param name="action"></param> | ||||
public void Invoke(Action action) { | ||||
if (action == null) | ||||
throw new ArgumentNullException("action"); | ||||
var old = _current; | ||||
cin
|
r48 | Fork(this); | ||
cin
|
r40 | try { | ||
action(); | ||||
} finally { | ||||
cin
|
r43 | _current.EndAllOperations(); | ||
cin
|
r40 | _current = old; | ||
} | ||||
} | ||||
/// <summary> | ||||
/// Текущая логическая операция. | ||||
/// </summary> | ||||
cin
|
r36 | public LogicalOperation CurrentOperation { | ||
get { | ||||
return m_currentOperation; | ||||
} | ||||
} | ||||
cin
|
r40 | /// <summary> | ||
/// Операция ниже которой нельзя опускаться в стеке логических операций, т.е. она не может быть завершена в текущем контексте. | ||||
/// </summary> | ||||
public LogicalOperation BoundOperation { | ||||
cin
|
r36 | get { | ||
cin
|
r40 | return m_bound; | ||
cin
|
r36 | } | ||
} | ||||
cin
|
r40 | /// <summary> | ||
/// Поток, в котором создан контекст трассировки. | ||||
/// </summary> | ||||
cin
|
r36 | public int ThreadId { | ||
get { | ||||
return m_threadId; | ||||
} | ||||
} | ||||
cin
|
r40 | /// <summary> | ||
/// Начинает безымянную логическую операцию. | ||||
/// </summary> | ||||
cin
|
r36 | public void StartLogicalOperation() { | ||
StartLogicalOperation(null); | ||||
} | ||||
cin
|
r40 | /// <summary> | ||
/// Начинает логическую операцию с указанным именем. Созданная операция будет добвалена в стек логических операций контекста, затем будет создано соответсвующее событие. | ||||
/// </summary> | ||||
/// <param name="name">Имя начинаемой операции.</param> | ||||
cin
|
r36 | public void StartLogicalOperation(string name) { | ||
m_currentOperation = new LogicalOperation(name, m_currentOperation); | ||||
cin
|
r40 | LogEvent(TraceEventType.OperationStarted, name); | ||
cin
|
r36 | } | ||
cin
|
r40 | /// <summary> | ||
/// Заканчивает логическую операцию начатую в текущем контексте. Операции, начатые в других контекстах не могут быть закончены в текущем контексте. | ||||
/// </summary> | ||||
/// <remarks> | ||||
/// При вызове данного метода создается событие журнала трассировки, либо о завершении операции, либо об ошибки, поскольку данная операция | ||||
/// начата в другом контексте. | ||||
/// </remarks> | ||||
cin
|
r36 | public void EndLogicalOperation() { | ||
cin
|
r40 | if (m_bound == m_currentOperation) { | ||
cin
|
r36 | LogEvent(TraceEventType.Error, "Trying to end the operation which isn't belongs to current trace"); | ||
} else { | ||||
var op = m_currentOperation; | ||||
cin
|
r40 | LogEvent(TraceEventType.OperationCompleted, "{0} {1} ms", op.Name, op.Duration); | ||
cin
|
r36 | m_currentOperation = m_currentOperation.Parent; | ||
} | ||||
} | ||||
cin
|
r43 | /// <summary> | ||
/// Заврешает все начатые в этом контексте операции | ||||
/// </summary> | ||||
public void EndAllOperations() { | ||||
while (m_bound != m_currentOperation) | ||||
EndLogicalOperation(); | ||||
} | ||||
cin
|
r36 | void LogEvent(TraceEventType type, string format, params object[] args) { | ||
cin
|
r37 | LogChannel<TraceEvent>.Default.LogEvent(this, TraceEvent.Create(type, format, args)); | ||
cin
|
r36 | } | ||
} | ||||
} | ||||