view Implab/Diagnostics/TraceContext.cs @ 119:2573b562e328 v2

Promises rewritten, added improved version of AsyncQueue
author cin
date Sun, 11 Jan 2015 19:13:02 +0300
parents a43745f81f10
children 6c49d02a9a05
line wrap: on
line source

using System;
using System.Collections.Generic;
using System.Threading;

namespace Implab.Diagnostics {
    /// <summary>
    /// Trace context is bound to the specific thread, each thread has it's own ThreadContext.
    /// </summary>
    /// <remarks>
    /// ThreadContext manages relations between logical operations and threads.
    /// </remarks>
    public class TraceContext {

        [ThreadStatic]
        static TraceContext _instance;

        OperationContext m_current = OperationContext.EMPTY;
        readonly Stack<OperationContext> m_stack = new Stack<OperationContext>();
        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) {
            var prev = CurrentOperation;
            m_stack.Push(m_current);
            m_current = new OperationContext(operation, takeOwnership);
            LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(takeOwnership ? TraceEventType.Attach : TraceEventType.Enter, String.Format("{0} -> {1}",prev.Name, operation.Name)));
        }

        public void StartLogicalOperation(string name) {
            m_current.BeginLogicalOperation(name);
            LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(TraceEventType.OperationStarted, String.Format("+{0}",CurrentOperation.Name)));
        }

        public void StartLogicalOperation() {
            StartLogicalOperation(String.Empty);
        }

        public void EndLogicalOperation() {
            LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(TraceEventType.OperationCompleted, String.Format("-{0} : {1}ms",CurrentOperation.Name, CurrentOperation.Duration)));
            m_current.EndLogicalOperation();
        }

        public LogicalOperation DetachLogicalOperation() {
            var prev = m_current.DetachLogicalOperation();
            LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(TraceEventType.Detach, String.Format("{0} -> {1}",prev.Name, CurrentOperation.Name)));
            return prev;
        }

        public void Leave() {
            if (m_stack.Count > 0) {
                m_current.Leave();
                var prev = CurrentOperation;
                m_current = m_stack.Pop();
                LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(TraceEventType.Leave, String.Format("{0} -> {1}", prev.Name, CurrentOperation.Name)));
            } else {
                TraceLog.TraceWarning("Attempt to leave the last operation context");
                m_current = OperationContext.EMPTY;
            }
        }
    }
}