Mercurial > pub > ImplabNet
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 71:1714fd8678ef | 192:f1da3afc3521 |
|---|---|
| 1 using System; | 1 using System; |
| 2 using System.Collections.Generic; | 2 using System.Collections.Generic; |
| 3 using System.Linq; | |
| 4 using System.Text; | |
| 5 using System.Threading; | 3 using System.Threading; |
| 6 using System.Threading.Tasks; | |
| 7 | 4 |
| 8 namespace Implab.Diagnostics { | 5 namespace Implab.Diagnostics { |
| 9 /// <summary> | 6 /// <summary> |
| 10 /// Контекст трассировки, привязывается к потоку и содержит в себе информацию о стеке логических операций. | 7 /// Trace context is bound to the specific thread, each thread has it's own ThreadContext. |
| 11 /// </summary> | 8 /// </summary> |
| 12 /// <remarks> | 9 /// <remarks> |
| 13 /// Контекст трассировки передается слушателям событий для определения места, где возникло событие. | 10 /// ThreadContext manages relations between logical operations and threads. |
| 14 /// </remarks> | 11 /// </remarks> |
| 15 public class TraceContext { | 12 public class TraceContext { |
| 16 LogicalOperation m_currentOperation; | 13 |
| 17 readonly LogicalOperation m_bound; | 14 [ThreadStatic] |
| 15 static TraceContext _instance; | |
| 16 | |
| 17 OperationContext m_current = OperationContext.EMPTY; | |
| 18 readonly Stack<OperationContext> m_stack = new Stack<OperationContext>(); | |
| 18 readonly int m_threadId; | 19 readonly int m_threadId; |
| 19 | 20 |
| 20 [ThreadStatic] | 21 public static TraceContext Instance { |
| 21 static TraceContext _current; | |
| 22 | |
| 23 /// <summary> | |
| 24 /// Текущий контекст трассировки для потока, создается астоматически при первом обращении. | |
| 25 /// </summary> | |
| 26 public static TraceContext Current { | |
| 27 get { | 22 get { |
| 28 if (_current == null) { | 23 if (_instance == null) |
| 29 _current = new TraceContext(); | 24 _instance = new TraceContext(); |
| 30 _current.LogEvent(TraceEventType.Created,"[{0}]", _current.ThreadId); | 25 return _instance; |
| 31 } | |
| 32 return _current; | |
| 33 } | 26 } |
| 34 } | 27 } |
| 35 | 28 |
| 36 TraceContext(TraceContext context) | 29 public TraceContext() { |
| 37 : this(context, false) { | |
| 38 } | |
| 39 | |
| 40 TraceContext(TraceContext context, bool attach) { | |
| 41 if (context == null) | |
| 42 throw new ArgumentNullException("context"); | |
| 43 | |
| 44 m_currentOperation = context.CurrentOperation; | |
| 45 m_bound = attach ? context.BoundOperation : context.CurrentOperation; | |
| 46 m_threadId = Thread.CurrentThread.ManagedThreadId; | 30 m_threadId = Thread.CurrentThread.ManagedThreadId; |
| 47 } | 31 } |
| 48 | 32 |
| 49 TraceContext() { | 33 public int ThreadId { |
| 50 m_currentOperation = new LogicalOperation(); | 34 get { return m_threadId; } |
| 51 m_bound = m_currentOperation; | |
| 52 m_threadId = Thread.CurrentThread.ManagedThreadId; | |
| 53 } | 35 } |
| 54 | 36 |
| 55 /// <summary> | 37 public LogicalOperation CurrentOperation { |
| 56 /// При необходимости копирует состояние контекста трассивровки в текущий поток. | 38 get { |
| 57 /// </summary> | 39 return m_current.CurrentOperation; |
| 58 /// <param name="from">Исходный контекст трассировки, который передается.</param> | |
| 59 /// <remarks> | |
| 60 /// <para> | |
| 61 /// Копирование происходит за счет создания нового контекста трассировки и заполнением его | |
| 62 /// состояния из переданного контекста. При этом копируется стек операций, однако в новом | |
| 63 /// контексте ранее начатые логические операции не могут быть завершены. | |
| 64 /// </para> | |
| 65 /// <para> | |
| 66 /// Если передача состояния состоялась, то вызывается событие трассировки <see cref="TraceEventType.Fork"/>. | |
| 67 /// </para> | |
| 68 /// </remarks> | |
| 69 public static void Fork(TraceContext from) { | |
| 70 if (_current == from) | |
| 71 return; | |
| 72 if (from != null) { | |
| 73 var context = new TraceContext(from); | |
| 74 context.LogEvent(TraceEventType.Fork, "[{0}]-->[{1}]",from.ThreadId, context.ThreadId); | |
| 75 _current = context; | |
| 76 } else { | |
| 77 _current = new TraceContext(); | |
| 78 } | 40 } |
| 79 } | 41 } |
| 80 | 42 |
| 81 /// <summary> | 43 public void EnterLogicalOperation(LogicalOperation operation, bool takeOwnership) { |
| 82 /// Задает текущему потоку указанный контекст, текущей поток может заканчивать ранее начатые | 44 //var prev = CurrentOperation; |
| 83 /// логические операции в указанном контексте. | 45 //LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(takeOwnership ? TraceEventType.Attach : TraceEventType.Enter, String.Format("{0} -> {1}",prev.Name, operation.Name))); |
| 84 /// </summary> | 46 m_stack.Push(m_current); |
| 85 /// <param name="source"></param> | 47 m_current = new OperationContext(operation, takeOwnership); |
| 86 public static void Attach(TraceContext source) { | |
| 87 if (_current == source) | |
| 88 return; | |
| 89 if (source != null) { | |
| 90 var context = new TraceContext(source, true); | |
| 91 context.LogEvent(TraceEventType.Attach, "[{0}]-->[{1}]", source.ThreadId, context.ThreadId); | |
| 92 _current = context; | |
| 93 } else { | |
| 94 _current = new TraceContext(); | |
| 95 } | |
| 96 } | 48 } |
| 97 | 49 |
| 98 /// <summary> | 50 public void StartLogicalOperation(string name) { |
| 99 /// Отсоединяет текущий контекст трассировки от потока, для дальнейшей его передачи другому потоку | 51 LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(TraceEventType.OperationStarted, name)); |
| 100 /// <see cref="Attach(TraceContext)"/>. | 52 m_current.BeginLogicalOperation(name); |
| 101 /// </summary> | |
| 102 /// <returns>Контекст трассировки потока</returns> | |
| 103 /// <remarks> | |
| 104 /// После отсоединения контекста трассировки от потока, при первом обращении к трассировке в этом | |
| 105 /// потоке будет создан новый контекст. | |
| 106 /// </remarks> | |
| 107 public static TraceContext Detach() { | |
| 108 var context = Current; | |
| 109 context.LogEvent(TraceEventType.Detach, null); | |
| 110 _current = null; | |
| 111 return context; | |
| 112 } | 53 } |
| 113 | 54 |
| 114 /// <summary> | 55 public void StartLogicalOperation() { |
| 115 /// Создает постоянную копию текущего контекста, данную копию можно хранить и использовать для передачи через <see cref="Fork(TraceContext)"/> | 56 StartLogicalOperation(String.Empty); |
| 116 /// </summary> | |
| 117 /// <returns>Копия текущего контекста трассировки.</returns> | |
| 118 public static TraceContext Snapshot() { | |
| 119 return _current == null ? new TraceContext() : new TraceContext(_current,false); | |
| 120 } | 57 } |
| 121 | 58 |
| 122 /// <summary> | 59 public void EndLogicalOperation() { |
| 123 /// Выполняет переданное действие в указанном контексте трассировки, по окончании восстанавливает предыдущий контекст трассировки потока. | 60 var op = m_current.EndLogicalOperation(); |
| 124 /// </summary> | 61 LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(TraceEventType.OperationCompleted, String.Format("-{0} : {1}ms",op.Name, op.Duration))); |
| 125 /// <param name="action"></param> | |
| 126 public void Invoke(Action action) { | |
| 127 if (action == null) | |
| 128 throw new ArgumentNullException("action"); | |
| 129 var old = _current; | |
| 130 Fork(this); | |
| 131 try { | |
| 132 action(); | |
| 133 } finally { | |
| 134 if(_current != null) | |
| 135 _current.EndAllOperations(); | |
| 136 _current = old; | |
| 137 } | |
| 138 } | 62 } |
| 139 | 63 |
| 140 /// <summary> | 64 public LogicalOperation DetachLogicalOperation() { |
| 141 /// Текущая логическая операция. | 65 var prev = m_current.DetachLogicalOperation(); |
| 142 /// </summary> | 66 //LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(TraceEventType.Detach, String.Format("{0} -> {1}",prev.Name, CurrentOperation.Name))); |
| 143 public LogicalOperation CurrentOperation { | 67 return prev; |
| 144 get { | |
| 145 return m_currentOperation; | |
| 146 } | |
| 147 } | 68 } |
| 148 | 69 |
| 149 /// <summary> | 70 public void Leave() { |
| 150 /// Операция ниже которой нельзя опускаться в стеке логических операций, т.е. она не может быть завершена в текущем контексте. | 71 if (m_stack.Count > 0) { |
| 151 /// </summary> | 72 m_current.Leave(); |
| 152 public LogicalOperation BoundOperation { | 73 //var prev = CurrentOperation; |
| 153 get { | 74 m_current = m_stack.Pop(); |
| 154 return m_bound; | 75 //LogChannel<TraceEvent>.Default.LogEvent(new TraceEvent(TraceEventType.Leave, String.Format("{0} -> {1}", prev.Name, CurrentOperation.Name))); |
| 76 } else { | |
| 77 TraceLog.TraceWarning("Attempt to leave the last operation context"); | |
| 78 m_current = OperationContext.EMPTY; | |
| 155 } | 79 } |
| 156 } | |
| 157 | |
| 158 /// <summary> | |
| 159 /// Поток, в котором создан контекст трассировки. | |
| 160 /// </summary> | |
| 161 public int ThreadId { | |
| 162 get { | |
| 163 return m_threadId; | |
| 164 } | |
| 165 } | |
| 166 | |
| 167 /// <summary> | |
| 168 /// Начинает безымянную логическую операцию. | |
| 169 /// </summary> | |
| 170 public void StartLogicalOperation() { | |
| 171 StartLogicalOperation(null); | |
| 172 } | |
| 173 | |
| 174 /// <summary> | |
| 175 /// Начинает логическую операцию с указанным именем. Созданная операция будет добвалена в стек логических операций контекста, затем будет создано соответсвующее событие. | |
| 176 /// </summary> | |
| 177 /// <param name="name">Имя начинаемой операции.</param> | |
| 178 public void StartLogicalOperation(string name) { | |
| 179 m_currentOperation = new LogicalOperation(name, m_currentOperation); | |
| 180 LogEvent(TraceEventType.OperationStarted, name); | |
| 181 } | |
| 182 | |
| 183 /// <summary> | |
| 184 /// Заканчивает логическую операцию начатую в текущем контексте. Операции, начатые в других контекстах не могут быть закончены в текущем контексте. | |
| 185 /// </summary> | |
| 186 /// <remarks> | |
| 187 /// При вызове данного метода создается событие журнала трассировки, либо о завершении операции, либо об ошибки, поскольку данная операция | |
| 188 /// начата в другом контексте. | |
| 189 /// </remarks> | |
| 190 public void EndLogicalOperation() { | |
| 191 if (m_bound == m_currentOperation) { | |
| 192 LogEvent(TraceEventType.Error, "Trying to end the operation which isn't belongs to current trace"); | |
| 193 } else { | |
| 194 var op = m_currentOperation; | |
| 195 LogEvent(TraceEventType.OperationCompleted, "{0} {1} ms", op.Name, op.Duration); | |
| 196 m_currentOperation = m_currentOperation.Parent; | |
| 197 } | |
| 198 } | |
| 199 | |
| 200 /// <summary> | |
| 201 /// Создает копию контекста и возвращается на предыдущую операцию в текущем контексте, это позволяет начать операцию в одном потоке, а завершить - в другом. | |
| 202 /// </summary> | |
| 203 /// <returns>Контекст трассировки, который можно присоединить к другому потоку.</returns> | |
| 204 public TraceContext DetachLogicalOperation() { | |
| 205 if (m_bound == m_currentOperation) { | |
| 206 return new TraceContext(); | |
| 207 } else { | |
| 208 var detached = new TraceContext(this, true); | |
| 209 m_currentOperation = m_currentOperation.Parent; | |
| 210 return detached; | |
| 211 } | |
| 212 } | |
| 213 | |
| 214 public void BindLogicalOperationToPromise(IPromise promise) { | |
| 215 Safe.ArgumentNotNull(promise, "promise"); | |
| 216 | |
| 217 var ctx = DetachLogicalOperation(); | |
| 218 promise.Finally(() => { | |
| 219 var old = _current; | |
| 220 TraceContext.Attach(ctx); | |
| 221 TraceContext.Current.EndLogicalOperation(); | |
| 222 _current = old; | |
| 223 }); | |
| 224 } | |
| 225 | |
| 226 /// <summary> | |
| 227 /// Заврешает все начатые в этом контексте операции | |
| 228 /// </summary> | |
| 229 public void EndAllOperations() { | |
| 230 while (m_bound != m_currentOperation) | |
| 231 EndLogicalOperation(); | |
| 232 } | |
| 233 | |
| 234 void LogEvent(TraceEventType type, string format, params object[] args) { | |
| 235 LogChannel<TraceEvent>.Default.LogEvent(this, TraceEvent.Create(type, format, args)); | |
| 236 } | 80 } |
| 237 } | 81 } |
| 238 } | 82 } |
| 83 |
