TraceContext.cs
172 lines
| 8.0 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 { | ||||
if (_current == null) | ||||
_current = new TraceContext(); | ||||
return _current; | ||||
} | ||||
} | ||||
TraceContext(TraceContext context) { | ||||
if (context == null) | ||||
throw new ArgumentNullException("context"); | ||||
m_currentOperation = context.CurrentOperation; | ||||
cin
|
r40 | m_bound = 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> | ||||
/// Если передача состояния состоялась, то вызывается событие трассировки <see cref="TraceEventType.Transfer"/>. | ||||
/// </para> | ||||
/// </remarks> | ||||
cin
|
r36 | public static void Transfer(TraceContext from) { | ||
cin
|
r40 | if (_current == from) | ||
return; | ||||
if (from != null) { | ||||
var context = new TraceContext(from); | ||||
context.LogEvent(TraceEventType.Transfer, "[{0}]-->[{1}]",from.ThreadId, context.ThreadId); | ||||
_current = context; | ||||
} else { | ||||
_current = new TraceContext(); | ||||
cin
|
r36 | } | ||
} | ||||
cin
|
r40 | /// <summary> | ||
/// Создает постоянную копию текущего контекста, данную копию можно хранить и использовать для передачи через <see cref="Transfer(TraceContext)"/> | ||||
/// </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; | ||||
Transfer(this); | ||||
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 | } | ||
} | ||||
} | ||||