diff Implab/Diagnostics/TraceContext.cs @ 192:f1da3afc3521 release v2.1

Слияние с v2
author cin
date Fri, 22 Apr 2016 13:10:34 +0300
parents 04d4c92d0f28
children ea485487a424
line wrap: on
line diff
--- a/Implab/Diagnostics/TraceContext.cs	Wed Sep 03 18:34:02 2014 +0400
+++ b/Implab/Diagnostics/TraceContext.cs	Fri Apr 22 13:10:34 2016 +0300
@@ -1,238 +1,83 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Implab.Diagnostics {
-    /// <summary>
-    /// Контекст трассировки, привязывается к потоку и содержит в себе информацию о стеке логических операций.
-    /// </summary>
-    /// <remarks>
-    /// Контекст трассировки передается слушателям событий для определения места, где возникло событие.
-    /// </remarks>
-    public class TraceContext {
-        LogicalOperation m_currentOperation;
-        readonly LogicalOperation m_bound;
-        readonly int m_threadId;
-
-        [ThreadStatic]
-        static TraceContext _current;
-
-        /// <summary>
-        /// Текущий контекст трассировки для потока, создается астоматически при первом обращении.
-        /// </summary>
-        public static TraceContext Current {
-            get {
-                if (_current == null) {
-                    _current = new TraceContext();
-                    _current.LogEvent(TraceEventType.Created,"[{0}]", _current.ThreadId);
-                }
-                return _current;
-            }
-        }
-
-        TraceContext(TraceContext context)
-            : this(context, false) {
-        }
-
-        TraceContext(TraceContext context, bool attach) {
-            if (context == null)
-                throw new ArgumentNullException("context");
-
-            m_currentOperation = context.CurrentOperation;
-            m_bound = attach ? context.BoundOperation : context.CurrentOperation;
-            m_threadId = Thread.CurrentThread.ManagedThreadId;
-        }
-
-        TraceContext() {
-            m_currentOperation = new LogicalOperation();
-            m_bound = m_currentOperation;
-            m_threadId = Thread.CurrentThread.ManagedThreadId;
-        }
-
-        /// <summary>
-        /// При необходимости копирует состояние контекста трассивровки в текущий поток.
-        /// </summary>
-        /// <param name="from">Исходный контекст трассировки, который передается.</param>
-        /// <remarks>
-        /// <para>
-        /// Копирование происходит за счет создания нового контекста трассировки и заполнением его
-        /// состояния из переданного контекста. При этом копируется стек операций, однако в новом
-        /// контексте ранее начатые логические операции не могут быть завершены.
-        /// </para>
-        /// <para>
-        /// Если передача состояния состоялась, то вызывается событие трассировки <see cref="TraceEventType.Fork"/>.
-        /// </para>
-        /// </remarks>
-        public static void Fork(TraceContext from) {
-            if (_current == from)
-                return;
-            if (from != null) {
-                var context = new TraceContext(from);
-                context.LogEvent(TraceEventType.Fork, "[{0}]-->[{1}]",from.ThreadId, context.ThreadId);
-                _current = context;
-            } else {
-                _current = new TraceContext();
-            }
-        }
-
-        /// <summary>
-        /// Задает текущему потоку указанный контекст, текущей поток может заканчивать ранее начатые
-        /// логические операции в указанном контексте.
-        /// </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)"/>
-        /// </summary>
-        /// <returns>Копия текущего контекста трассировки.</returns>
-        public static TraceContext Snapshot() {
-            return _current == null ? new TraceContext() : new TraceContext(_current,false);
-        }
-
-        /// <summary>
-        /// Выполняет переданное действие в указанном контексте трассировки, по окончании восстанавливает предыдущий контекст трассировки потока.
-        /// </summary>
-        /// <param name="action"></param>
-        public void Invoke(Action action) {
-            if (action == null)
-                throw new ArgumentNullException("action");
-            var old = _current;
-            Fork(this);
-            try {
-                action();
-            } finally {
-                if(_current != null)
-                    _current.EndAllOperations();
-                _current = old;
-            }
-        }
-
-        /// <summary>
-        /// Текущая логическая операция.
-        /// </summary>
-        public LogicalOperation CurrentOperation {
-            get {
-                return m_currentOperation;
-            }
-        }
-
-        /// <summary>
-        /// Операция ниже которой нельзя опускаться в стеке логических операций, т.е. она не может быть завершена в текущем контексте.
-        /// </summary>
-        public LogicalOperation BoundOperation {
-            get {
-                return m_bound;
-            }
-        }
-
-        /// <summary>
-        /// Поток, в котором создан контекст трассировки.
-        /// </summary>
-        public int ThreadId {
-            get {
-                return m_threadId;
-            }
-        }
-
-        /// <summary>
-        /// Начинает безымянную логическую операцию.
-        /// </summary>
-        public void StartLogicalOperation() {
-            StartLogicalOperation(null);
-        }
-
-        /// <summary>
-        /// Начинает логическую операцию с указанным именем. Созданная операция будет добвалена в стек логических операций контекста, затем будет создано соответсвующее событие.
-        /// </summary>
-        /// <param name="name">Имя начинаемой операции.</param>
-        public void StartLogicalOperation(string name) {
-            m_currentOperation = new LogicalOperation(name, m_currentOperation);
-            LogEvent(TraceEventType.OperationStarted, name);
-        }
-
-        /// <summary>
-        /// Заканчивает логическую операцию начатую в текущем контексте. Операции, начатые в других контекстах не могут быть закончены в текущем контексте.
-        /// </summary>
-        /// <remarks>
-        /// При вызове данного метода создается событие журнала трассировки, либо о завершении операции, либо об ошибки, поскольку данная операция
-        /// начата в другом контексте.
-        /// </remarks>
-        public void EndLogicalOperation() {
-            if (m_bound == m_currentOperation) {
-                LogEvent(TraceEventType.Error, "Trying to end the operation which isn't belongs to current trace");
-            } else {
-                var op = m_currentOperation;
-                LogEvent(TraceEventType.OperationCompleted, "{0} {1} ms", op.Name, op.Duration);
-                m_currentOperation = m_currentOperation.Parent;
-            }
-        }
-
-        /// <summary>
-        /// Создает копию контекста и возвращается на предыдущую операцию в текущем контексте, это позволяет начать операцию в одном потоке, а завершить - в другом.
-        /// </summary>
-        /// <returns>Контекст трассировки, который можно присоединить к другому потоку.</returns>
-        public TraceContext DetachLogicalOperation() {
-            if (m_bound == m_currentOperation) {
-                return new TraceContext();
-            } else {
-                var detached = new TraceContext(this, true);
-                m_currentOperation = m_currentOperation.Parent;
-                return detached;
-            }
-        }
-
-        public void BindLogicalOperationToPromise(IPromise promise) {
-            Safe.ArgumentNotNull(promise, "promise");
-
-            var ctx = DetachLogicalOperation();
-            promise.Finally(() => {
-                var old = _current;
-                TraceContext.Attach(ctx);
-                TraceContext.Current.EndLogicalOperation();
-                _current = old;
-            });
-        }
-
-        /// <summary>
-        /// Заврешает все начатые в этом контексте операции
-        /// </summary>
-        public void EndAllOperations() {
-            while (m_bound != m_currentOperation)
-                EndLogicalOperation();
-        }
-
-        void LogEvent(TraceEventType type, string format, params object[] args) {
-            LogChannel<TraceEvent>.Default.LogEvent(this, TraceEvent.Create(type, format, args));
-        }
-    }
-}
+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;
+            }
+        }
+    }
+}
+