using System;
using System.Collections.Generic;
using System.Threading;
namespace Implab.Diagnostics {
///
/// Trace context is bound to the specific thread, each thread has it's own ThreadContext.
///
///
/// ThreadContext manages relations between logical operations and threads.
///
public class TraceContext {
[ThreadStatic]
static TraceContext _instance;
OperationContext m_current = OperationContext.EMPTY;
readonly Stack m_stack = new Stack();
readonly int m_threadId;
public static TraceContext Instance {
get {
if (_instance == null)
_instance = new TraceContext();
return _instance;
}
}
public TraceContext() {
m_threadId = Thread.CurrentThread.ManagedThreadId;
}
public int ThreadId {
get { return m_threadId; }
}
public LogicalOperation CurrentOperation {
get {
return m_current.CurrentOperation;
}
}
public void EnterLogicalOperation(LogicalOperation operation, bool takeOwnership) {
LogChannel.Default.LogEvent(new TraceEvent(TraceEventType.Attach, String.Format("{0} -> [{1}]", operation.Name, m_threadId)));
m_stack.Push(m_current);
m_current = new OperationContext(operation, takeOwnership);
}
public void StartLogicalOperation(string name) {
m_current.BeginLogicalOperation(name);
LogChannel.Default.LogEvent(new TraceEvent(TraceEventType.OperationStarted, String.Format("+{0}",CurrentOperation.Name)));
}
public void StartLogicalOperation() {
StartLogicalOperation(String.Empty);
}
public void EndLogicalOperation() {
LogChannel.Default.LogEvent(new TraceEvent(TraceEventType.OperationCompleted, String.Format("-{0} : {1}ms",CurrentOperation.Name, CurrentOperation.Duration)));
m_current.EndLogicalOperation();
}
public LogicalOperation DetachLogicalOperation() {
var op = m_current.DetachLogicalOperation();
LogChannel.Default.LogEvent(new TraceEvent(TraceEventType.Detach, String.Format("[{0}] -> {1}", m_threadId, op.Name)));
return op;
}
public void Leave() {
if (m_stack.Count > 0) {
m_current.Leave();
m_current = m_stack.Pop();
} else {
TraceLog.TraceWarning("Attemtp to leave the last operation context");
m_current = OperationContext.EMPTY;
}
}
}
}