view Implab/Diagnostics/TraceContext.cs @ 187:dd4a3590f9c6 ref20160224

Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler Any unhandled OperationCanceledException will cause the promise cancelation
author cin
date Tue, 19 Apr 2016 17:35:20 +0300
parents 04d4c92d0f28
children ea485487a424
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;
            //LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(takeOwnership ? TraceEventType.Attach : TraceEventType.Enter, String.Format("{0} -> {1}",prev.Name, operation.Name)));
            m_stack.Push(m_current);
            m_current = new OperationContext(operation, takeOwnership);
        }

        public void StartLogicalOperation(string name) {
            LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(TraceEventType.OperationStarted, name));
            m_current.BeginLogicalOperation(name);
        }

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

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

        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;
            }
        }
    }
}