Mercurial > pub > ImplabNet
annotate Implab/Diagnostics/TraceContext.cs @ 48:d9d794b61bb9 interactive logger
Interactive tracing
Improved working with tracing contexts
author | cin |
---|---|
date | Fri, 18 Apr 2014 12:34:45 +0400 |
parents | 7c2369f580b8 |
children | edf0bc558596 |
rev | line source |
---|---|
36 | 1 using System; |
2 using System.Collections.Generic; | |
3 using System.Linq; | |
4 using System.Text; | |
5 using System.Threading; | |
6 using System.Threading.Tasks; | |
7 | |
8 namespace Implab.Diagnostics { | |
40 | 9 /// <summary> |
10 /// Контекст трассировки, привязывается к потоку и содержит в себе информацию о стеке логических операций. | |
11 /// </summary> | |
12 /// <remarks> | |
13 /// Контекст трассировки передается слушателям событий для определения места, где возникло событие. | |
14 /// </remarks> | |
36 | 15 public class TraceContext { |
16 LogicalOperation m_currentOperation; | |
40 | 17 readonly LogicalOperation m_bound; |
36 | 18 readonly int m_threadId; |
19 | |
20 [ThreadStatic] | |
21 static TraceContext _current; | |
22 | |
40 | 23 /// <summary> |
24 /// Текущий контекст трассировки для потока, создается астоматически при первом обращении. | |
25 /// </summary> | |
36 | 26 public static TraceContext Current { |
27 get { | |
48 | 28 if (_current == null) { |
36 | 29 _current = new TraceContext(); |
48 | 30 _current.LogEvent(TraceEventType.Created,"[{0}]", _current.ThreadId); |
31 } | |
36 | 32 return _current; |
33 } | |
34 } | |
35 | |
48 | 36 TraceContext(TraceContext context) |
37 : this(context, false) { | |
38 } | |
39 | |
40 TraceContext(TraceContext context, bool attach) { | |
36 | 41 if (context == null) |
42 throw new ArgumentNullException("context"); | |
43 | |
44 m_currentOperation = context.CurrentOperation; | |
48 | 45 m_bound = attach ? context.BoundOperation : context.CurrentOperation; |
36 | 46 m_threadId = Thread.CurrentThread.ManagedThreadId; |
47 } | |
48 | |
49 TraceContext() { | |
50 m_currentOperation = new LogicalOperation(); | |
40 | 51 m_bound = m_currentOperation; |
36 | 52 m_threadId = Thread.CurrentThread.ManagedThreadId; |
53 } | |
54 | |
40 | 55 /// <summary> |
56 /// При необходимости копирует состояние контекста трассивровки в текущий поток. | |
57 /// </summary> | |
58 /// <param name="from">Исходный контекст трассировки, который передается.</param> | |
59 /// <remarks> | |
60 /// <para> | |
61 /// Копирование происходит за счет создания нового контекста трассировки и заполнением его | |
62 /// состояния из переданного контекста. При этом копируется стек операций, однако в новом | |
63 /// контексте ранее начатые логические операции не могут быть завершены. | |
64 /// </para> | |
65 /// <para> | |
48 | 66 /// Если передача состояния состоялась, то вызывается событие трассировки <see cref="TraceEventType.Fork"/>. |
40 | 67 /// </para> |
68 /// </remarks> | |
48 | 69 public static void Fork(TraceContext from) { |
40 | 70 if (_current == from) |
71 return; | |
72 if (from != null) { | |
73 var context = new TraceContext(from); | |
48 | 74 context.LogEvent(TraceEventType.Fork, "[{0}]-->[{1}]",from.ThreadId, context.ThreadId); |
40 | 75 _current = context; |
76 } else { | |
77 _current = new TraceContext(); | |
36 | 78 } |
79 } | |
80 | |
40 | 81 /// <summary> |
48 | 82 /// Задает текущему потоку указанный контекст, текущей поток может заканчивать ранее начатые |
83 /// логические операции в указанном контексте. | |
84 /// </summary> | |
85 /// <param name="source"></param> | |
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 } | |
97 | |
98 /// <summary> | |
99 /// Отсоединяет текущий контекст трассировки от потока, для дальнейшей его передачи другому потоку | |
100 /// <see cref="Attach(TraceContext)"/>. | |
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 } | |
113 | |
114 /// <summary> | |
115 /// Создает постоянную копию текущего контекста, данную копию можно хранить и использовать для передачи через <see cref="Fork(TraceContext)"/> | |
40 | 116 /// </summary> |
41 | 117 /// <returns>Копия текущего контекста трассировки.</returns> |
40 | 118 public static TraceContext Snapshot() { |
41 | 119 return _current == null ? new TraceContext() : new TraceContext(_current); |
40 | 120 } |
121 | |
122 /// <summary> | |
123 /// Выполняет переданное действие в указанном контексте трассировки, по окончании восстанавливает предыдущий контекст трассировки потока. | |
124 /// </summary> | |
125 /// <param name="action"></param> | |
126 public void Invoke(Action action) { | |
127 if (action == null) | |
128 throw new ArgumentNullException("action"); | |
129 var old = _current; | |
48 | 130 Fork(this); |
40 | 131 try { |
132 action(); | |
133 } finally { | |
43
7c2369f580b8
improved tracing, TextListenerBase can be bound to logical operation scope.
cin
parents:
41
diff
changeset
|
134 _current.EndAllOperations(); |
40 | 135 _current = old; |
136 } | |
137 } | |
138 | |
139 /// <summary> | |
140 /// Текущая логическая операция. | |
141 /// </summary> | |
36 | 142 public LogicalOperation CurrentOperation { |
143 get { | |
144 return m_currentOperation; | |
145 } | |
146 } | |
147 | |
40 | 148 /// <summary> |
149 /// Операция ниже которой нельзя опускаться в стеке логических операций, т.е. она не может быть завершена в текущем контексте. | |
150 /// </summary> | |
151 public LogicalOperation BoundOperation { | |
36 | 152 get { |
40 | 153 return m_bound; |
36 | 154 } |
155 } | |
156 | |
40 | 157 /// <summary> |
158 /// Поток, в котором создан контекст трассировки. | |
159 /// </summary> | |
36 | 160 public int ThreadId { |
161 get { | |
162 return m_threadId; | |
163 } | |
164 } | |
165 | |
40 | 166 /// <summary> |
167 /// Начинает безымянную логическую операцию. | |
168 /// </summary> | |
36 | 169 public void StartLogicalOperation() { |
170 StartLogicalOperation(null); | |
171 } | |
172 | |
40 | 173 /// <summary> |
174 /// Начинает логическую операцию с указанным именем. Созданная операция будет добвалена в стек логических операций контекста, затем будет создано соответсвующее событие. | |
175 /// </summary> | |
176 /// <param name="name">Имя начинаемой операции.</param> | |
36 | 177 public void StartLogicalOperation(string name) { |
178 m_currentOperation = new LogicalOperation(name, m_currentOperation); | |
40 | 179 LogEvent(TraceEventType.OperationStarted, name); |
36 | 180 } |
181 | |
40 | 182 /// <summary> |
183 /// Заканчивает логическую операцию начатую в текущем контексте. Операции, начатые в других контекстах не могут быть закончены в текущем контексте. | |
184 /// </summary> | |
185 /// <remarks> | |
186 /// При вызове данного метода создается событие журнала трассировки, либо о завершении операции, либо об ошибки, поскольку данная операция | |
187 /// начата в другом контексте. | |
188 /// </remarks> | |
36 | 189 public void EndLogicalOperation() { |
40 | 190 if (m_bound == m_currentOperation) { |
36 | 191 LogEvent(TraceEventType.Error, "Trying to end the operation which isn't belongs to current trace"); |
192 } else { | |
193 var op = m_currentOperation; | |
40 | 194 LogEvent(TraceEventType.OperationCompleted, "{0} {1} ms", op.Name, op.Duration); |
36 | 195 m_currentOperation = m_currentOperation.Parent; |
196 } | |
197 } | |
198 | |
43
7c2369f580b8
improved tracing, TextListenerBase can be bound to logical operation scope.
cin
parents:
41
diff
changeset
|
199 /// <summary> |
7c2369f580b8
improved tracing, TextListenerBase can be bound to logical operation scope.
cin
parents:
41
diff
changeset
|
200 /// Заврешает все начатые в этом контексте операции |
7c2369f580b8
improved tracing, TextListenerBase can be bound to logical operation scope.
cin
parents:
41
diff
changeset
|
201 /// </summary> |
7c2369f580b8
improved tracing, TextListenerBase can be bound to logical operation scope.
cin
parents:
41
diff
changeset
|
202 public void EndAllOperations() { |
7c2369f580b8
improved tracing, TextListenerBase can be bound to logical operation scope.
cin
parents:
41
diff
changeset
|
203 while (m_bound != m_currentOperation) |
7c2369f580b8
improved tracing, TextListenerBase can be bound to logical operation scope.
cin
parents:
41
diff
changeset
|
204 EndLogicalOperation(); |
7c2369f580b8
improved tracing, TextListenerBase can be bound to logical operation scope.
cin
parents:
41
diff
changeset
|
205 } |
7c2369f580b8
improved tracing, TextListenerBase can be bound to logical operation scope.
cin
parents:
41
diff
changeset
|
206 |
36 | 207 void LogEvent(TraceEventType type, string format, params object[] args) { |
37 | 208 LogChannel<TraceEvent>.Default.LogEvent(this, TraceEvent.Create(type, format, args)); |
36 | 209 } |
210 } | |
211 } |