Mercurial > pub > ImplabNet
annotate Implab/Diagnostics/TraceContext.cs @ 43:7c2369f580b8
improved tracing, TextListenerBase can be bound to logical operation scope.
author | cin |
---|---|
date | Wed, 16 Apr 2014 10:12:56 +0400 |
parents | 2fc0fbe7d58b |
children | d9d794b61bb9 |
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 { | |
28 if (_current == null) | |
29 _current = new TraceContext(); | |
30 return _current; | |
31 } | |
32 } | |
33 | |
34 TraceContext(TraceContext context) { | |
35 if (context == null) | |
36 throw new ArgumentNullException("context"); | |
37 | |
38 m_currentOperation = context.CurrentOperation; | |
40 | 39 m_bound = context.CurrentOperation; |
36 | 40 m_threadId = Thread.CurrentThread.ManagedThreadId; |
41 } | |
42 | |
43 TraceContext() { | |
44 m_currentOperation = new LogicalOperation(); | |
40 | 45 m_bound = m_currentOperation; |
36 | 46 m_threadId = Thread.CurrentThread.ManagedThreadId; |
47 } | |
48 | |
40 | 49 /// <summary> |
50 /// При необходимости копирует состояние контекста трассивровки в текущий поток. | |
51 /// </summary> | |
52 /// <param name="from">Исходный контекст трассировки, который передается.</param> | |
53 /// <remarks> | |
54 /// <para> | |
55 /// Копирование происходит за счет создания нового контекста трассировки и заполнением его | |
56 /// состояния из переданного контекста. При этом копируется стек операций, однако в новом | |
57 /// контексте ранее начатые логические операции не могут быть завершены. | |
58 /// </para> | |
59 /// <para> | |
60 /// Если передача состояния состоялась, то вызывается событие трассировки <see cref="TraceEventType.Transfer"/>. | |
61 /// </para> | |
62 /// </remarks> | |
36 | 63 public static void Transfer(TraceContext from) { |
40 | 64 if (_current == from) |
65 return; | |
66 if (from != null) { | |
67 var context = new TraceContext(from); | |
68 context.LogEvent(TraceEventType.Transfer, "[{0}]-->[{1}]",from.ThreadId, context.ThreadId); | |
69 _current = context; | |
70 } else { | |
71 _current = new TraceContext(); | |
36 | 72 } |
73 } | |
74 | |
40 | 75 /// <summary> |
76 /// Создает постоянную копию текущего контекста, данную копию можно хранить и использовать для передачи через <see cref="Transfer(TraceContext)"/> | |
77 /// </summary> | |
41 | 78 /// <returns>Копия текущего контекста трассировки.</returns> |
40 | 79 public static TraceContext Snapshot() { |
41 | 80 return _current == null ? new TraceContext() : new TraceContext(_current); |
40 | 81 } |
82 | |
83 /// <summary> | |
84 /// Выполняет переданное действие в указанном контексте трассировки, по окончании восстанавливает предыдущий контекст трассировки потока. | |
85 /// </summary> | |
86 /// <param name="action"></param> | |
87 public void Invoke(Action action) { | |
88 if (action == null) | |
89 throw new ArgumentNullException("action"); | |
90 var old = _current; | |
91 Transfer(this); | |
92 try { | |
93 action(); | |
94 } finally { | |
43
7c2369f580b8
improved tracing, TextListenerBase can be bound to logical operation scope.
cin
parents:
41
diff
changeset
|
95 _current.EndAllOperations(); |
40 | 96 _current = old; |
97 } | |
98 } | |
99 | |
100 /// <summary> | |
101 /// Текущая логическая операция. | |
102 /// </summary> | |
36 | 103 public LogicalOperation CurrentOperation { |
104 get { | |
105 return m_currentOperation; | |
106 } | |
107 } | |
108 | |
40 | 109 /// <summary> |
110 /// Операция ниже которой нельзя опускаться в стеке логических операций, т.е. она не может быть завершена в текущем контексте. | |
111 /// </summary> | |
112 public LogicalOperation BoundOperation { | |
36 | 113 get { |
40 | 114 return m_bound; |
36 | 115 } |
116 } | |
117 | |
40 | 118 /// <summary> |
119 /// Поток, в котором создан контекст трассировки. | |
120 /// </summary> | |
36 | 121 public int ThreadId { |
122 get { | |
123 return m_threadId; | |
124 } | |
125 } | |
126 | |
40 | 127 /// <summary> |
128 /// Начинает безымянную логическую операцию. | |
129 /// </summary> | |
36 | 130 public void StartLogicalOperation() { |
131 StartLogicalOperation(null); | |
132 } | |
133 | |
40 | 134 /// <summary> |
135 /// Начинает логическую операцию с указанным именем. Созданная операция будет добвалена в стек логических операций контекста, затем будет создано соответсвующее событие. | |
136 /// </summary> | |
137 /// <param name="name">Имя начинаемой операции.</param> | |
36 | 138 public void StartLogicalOperation(string name) { |
139 m_currentOperation = new LogicalOperation(name, m_currentOperation); | |
40 | 140 LogEvent(TraceEventType.OperationStarted, name); |
36 | 141 } |
142 | |
40 | 143 /// <summary> |
144 /// Заканчивает логическую операцию начатую в текущем контексте. Операции, начатые в других контекстах не могут быть закончены в текущем контексте. | |
145 /// </summary> | |
146 /// <remarks> | |
147 /// При вызове данного метода создается событие журнала трассировки, либо о завершении операции, либо об ошибки, поскольку данная операция | |
148 /// начата в другом контексте. | |
149 /// </remarks> | |
36 | 150 public void EndLogicalOperation() { |
40 | 151 if (m_bound == m_currentOperation) { |
36 | 152 LogEvent(TraceEventType.Error, "Trying to end the operation which isn't belongs to current trace"); |
153 } else { | |
154 var op = m_currentOperation; | |
40 | 155 LogEvent(TraceEventType.OperationCompleted, "{0} {1} ms", op.Name, op.Duration); |
36 | 156 m_currentOperation = m_currentOperation.Parent; |
157 } | |
158 } | |
159 | |
43
7c2369f580b8
improved tracing, TextListenerBase can be bound to logical operation scope.
cin
parents:
41
diff
changeset
|
160 /// <summary> |
7c2369f580b8
improved tracing, TextListenerBase can be bound to logical operation scope.
cin
parents:
41
diff
changeset
|
161 /// Заврешает все начатые в этом контексте операции |
7c2369f580b8
improved tracing, TextListenerBase can be bound to logical operation scope.
cin
parents:
41
diff
changeset
|
162 /// </summary> |
7c2369f580b8
improved tracing, TextListenerBase can be bound to logical operation scope.
cin
parents:
41
diff
changeset
|
163 public void EndAllOperations() { |
7c2369f580b8
improved tracing, TextListenerBase can be bound to logical operation scope.
cin
parents:
41
diff
changeset
|
164 while (m_bound != m_currentOperation) |
7c2369f580b8
improved tracing, TextListenerBase can be bound to logical operation scope.
cin
parents:
41
diff
changeset
|
165 EndLogicalOperation(); |
7c2369f580b8
improved tracing, TextListenerBase can be bound to logical operation scope.
cin
parents:
41
diff
changeset
|
166 } |
7c2369f580b8
improved tracing, TextListenerBase can be bound to logical operation scope.
cin
parents:
41
diff
changeset
|
167 |
36 | 168 void LogEvent(TraceEventType type, string format, params object[] args) { |
37 | 169 LogChannel<TraceEvent>.Default.LogEvent(this, TraceEvent.Create(type, format, args)); |
36 | 170 } |
171 } | |
172 } |