Mercurial > projects > ldc
comparison tango/example/logging/context.d @ 132:1700239cab2e trunk
[svn r136] MAJOR UNSTABLE UPDATE!!!
Initial commit after moving to Tango instead of Phobos.
Lots of bugfixes...
This build is not suitable for most things.
author | lindquist |
---|---|
date | Fri, 11 Jan 2008 17:57:40 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
131:5825d48b27d1 | 132:1700239cab2e |
---|---|
1 /******************************************************************************* | |
2 | |
3 copyright: Copyright (c) 2007 Stonecobra. All rights reserved | |
4 | |
5 license: BSD style: $(LICENSE) | |
6 | |
7 version: Initial release: December 2007 | |
8 | |
9 author: stonecobra | |
10 | |
11 *******************************************************************************/ | |
12 | |
13 module context; | |
14 | |
15 import tango.core.Thread, | |
16 tango.util.log.Log, | |
17 tango.util.log.Event, | |
18 tango.util.log.EventLayout, | |
19 tango.util.log.ConsoleAppender; | |
20 | |
21 import tango.util.log.model.IHierarchy; | |
22 | |
23 /******************************************************************************* | |
24 | |
25 Allows the dynamic setting of log levels on a per-thread basis. | |
26 Imagine that a user request comes into your production threaded | |
27 server. You can't afford to turn logging up to trace for the sake | |
28 of debugging this one users problem, but you also can't afford to | |
29 find the problem and fix it. So now you just set the override log | |
30 level to TRACE for the thread the user is on, and you get full trace | |
31 output for only that user. | |
32 | |
33 *******************************************************************************/ | |
34 | |
35 class ThreadLocalDiagnosticContext : IHierarchy.Context | |
36 { | |
37 private ThreadLocal!(DCData) dcData; | |
38 private char[128] tmp; | |
39 | |
40 /*********************************************************************** | |
41 | |
42 ***********************************************************************/ | |
43 | |
44 public this() | |
45 { | |
46 dcData = new ThreadLocal!(DCData); | |
47 } | |
48 | |
49 /*********************************************************************** | |
50 | |
51 set the 'diagnostic' Level for logging. This overrides | |
52 the Level in the current Logger. The default level starts | |
53 at NONE, so as not to modify the behavior of existing clients | |
54 of tango.util.log | |
55 | |
56 ***********************************************************************/ | |
57 | |
58 void setLevel (ILevel.Level level) | |
59 { | |
60 auto data = dcData.val; | |
61 data.level = level; | |
62 dcData.val = data; | |
63 } | |
64 | |
65 /*********************************************************************** | |
66 | |
67 All log appends will be checked against this to see if a | |
68 log level needs to be temporarily adjusted. | |
69 | |
70 ***********************************************************************/ | |
71 | |
72 bool isEnabled (ILevel.Level setting, ILevel.Level level = ILevel.Level.Trace) | |
73 { | |
74 return level >= setting || level >= dcData.val.level; | |
75 } | |
76 | |
77 /*********************************************************************** | |
78 | |
79 Return the label to use for the current log message. Usually | |
80 called by the Layout. This implementation returns "{}". | |
81 | |
82 ***********************************************************************/ | |
83 | |
84 char[] label () | |
85 { | |
86 return dcData.val.getLabel; | |
87 } | |
88 | |
89 /*********************************************************************** | |
90 | |
91 Push another string into the 'stack'. This strings will be | |
92 appened together when getLabel is called. | |
93 | |
94 ***********************************************************************/ | |
95 | |
96 void push (char[] label) | |
97 { | |
98 auto data = dcData.val; | |
99 data.push(label); | |
100 dcData.val = data; | |
101 } | |
102 | |
103 /*********************************************************************** | |
104 | |
105 pop the current label off the stack. | |
106 | |
107 ***********************************************************************/ | |
108 | |
109 void pop () | |
110 { | |
111 auto data = dcData.val; | |
112 data.pop; | |
113 dcData.val = data; | |
114 } | |
115 | |
116 /*********************************************************************** | |
117 | |
118 Clear the label stack. | |
119 | |
120 ***********************************************************************/ | |
121 | |
122 void clear() | |
123 { | |
124 auto data = dcData.val; | |
125 data.clear; | |
126 dcData.val = data; | |
127 } | |
128 } | |
129 | |
130 | |
131 /******************************************************************************* | |
132 | |
133 The thread locally stored struct to hold the logging level and | |
134 the label stack. | |
135 | |
136 *******************************************************************************/ | |
137 | |
138 private struct DCData { | |
139 | |
140 ILevel.Level level = ILevel.Level.None; | |
141 char[][8] stack; | |
142 bool shouldUpdate = true; | |
143 int stackIndex = 0; | |
144 uint labelLength; | |
145 char[256] labelContent; | |
146 | |
147 | |
148 char[] getLabel() { | |
149 if (shouldUpdate) { | |
150 labelLength = 0; | |
151 append(" {"); | |
152 for (int i = 0; i < stackIndex; i++) { | |
153 append(stack[i]); | |
154 if (i < stackIndex - 1) { | |
155 append(" "); | |
156 } | |
157 } | |
158 append("}"); | |
159 shouldUpdate = false; | |
160 } | |
161 return labelContent[0..labelLength]; | |
162 } | |
163 | |
164 void append(char[] x) { | |
165 uint addition = x.length; | |
166 uint newLength = labelLength + x.length; | |
167 | |
168 if (newLength < labelContent.length) | |
169 { | |
170 labelContent [labelLength..newLength] = x[0..addition]; | |
171 labelLength = newLength; | |
172 } | |
173 } | |
174 | |
175 void push(char[] label) { | |
176 shouldUpdate = true; | |
177 stack[stackIndex] = label.dup; | |
178 stackIndex++; | |
179 } | |
180 | |
181 void pop() { | |
182 shouldUpdate = true; | |
183 if (stackIndex > 0) { | |
184 stack[stackIndex] = null; | |
185 stackIndex--; | |
186 } | |
187 } | |
188 | |
189 void clear() { | |
190 shouldUpdate = true; | |
191 for (int i = 0; i < stack.length; i++) { | |
192 stack[i] = null; | |
193 } | |
194 } | |
195 } | |
196 | |
197 | |
198 /******************************************************************************* | |
199 | |
200 Simple console appender that counts the number of log lines it | |
201 has written. | |
202 | |
203 *******************************************************************************/ | |
204 | |
205 class TestingConsoleAppender : ConsoleAppender { | |
206 | |
207 int events = 0; | |
208 | |
209 this (EventLayout layout = null) | |
210 { | |
211 super(layout); | |
212 } | |
213 | |
214 override void append (Event event) | |
215 { | |
216 events++; | |
217 super.append(event); | |
218 } | |
219 } | |
220 | |
221 | |
222 /******************************************************************************* | |
223 | |
224 Testing harness for the DiagnosticContext functionality. | |
225 | |
226 *******************************************************************************/ | |
227 | |
228 void main(char[][] args) | |
229 { | |
230 //set up our appender that counts the log output. This is the configuration | |
231 //equivalent of importing tango.util.log.Configurator. | |
232 auto appender = new TestingConsoleAppender(new SimpleTimerLayout); | |
233 Log.getRootLogger.addAppender(appender); | |
234 | |
235 char[128] tmp = 0; | |
236 auto log = Log.getLogger("context"); | |
237 log.setLevel(log.Level.Info); | |
238 | |
239 //first test, use all defaults, validating it is working. None of the trace() | |
240 //calls should count in the test. | |
241 for (int i=0;i < 10; i++) { | |
242 log.info(log.format(tmp, "test1 {}", i)); | |
243 log.trace(log.format(tmp, "test1 {}", i)); | |
244 } | |
245 if (appender.events !is 10) { | |
246 log.error(log.format(tmp, "events:{}", appender.events)); | |
247 throw new Exception("Incorrect Number of events in normal mode"); | |
248 } | |
249 | |
250 appender.events = 0; | |
251 | |
252 //test the thread local implementation without any threads, as a baseline. | |
253 //should be same result as test1 | |
254 auto context = new ThreadLocalDiagnosticContext; | |
255 Log.getHierarchy.context(context); | |
256 for (int i=0;i < 10; i++) { | |
257 log.info(log.format(tmp, "test2 {}", i)); | |
258 log.trace(log.format(tmp, "test2 {}", i)); | |
259 } | |
260 if (appender.events !is 10) { | |
261 log.error(log.format(tmp, "events:{}", appender.events)); | |
262 throw new Exception("Incorrect Number of events in TLS single thread mode"); | |
263 } | |
264 | |
265 appender.events = 0; | |
266 | |
267 //test the thread local implementation without any threads, as a baseline. | |
268 //This should count all logging requests, because the DiagnosticContext has | |
269 //'overridden' the logging level on ALL loggers up to TRACE. | |
270 context.setLevel(log.Level.Trace); | |
271 for (int i=0;i < 10; i++) { | |
272 log.info(log.format(tmp, "test3 {}", i)); | |
273 log.trace(log.format(tmp, "test3 {}", i)); | |
274 } | |
275 if (appender.events !is 20) { | |
276 log.error(log.format(tmp, "events:{}", appender.events)); | |
277 throw new Exception("Incorrect Number of events in TLS single thread mode with level set"); | |
278 } | |
279 | |
280 appender.events = 0; | |
281 | |
282 //test the thread local implementation without any threads, as a baseline. | |
283 context.setLevel(log.Level.None); | |
284 for (int i=0;i < 10; i++) { | |
285 log.info(log.format(tmp, "test4 {}", i)); | |
286 log.trace(log.format(tmp, "test4 {}", i)); | |
287 } | |
288 if (appender.events !is 10) { | |
289 log.error(log.format(tmp, "events:{}", appender.events)); | |
290 throw new Exception("Incorrect Number of events in TLS single thread mode after level reset"); | |
291 } | |
292 | |
293 //Now test threading. set up a trace context in one thread, with a label, while | |
294 //keeping the second thread at the normal configuration. | |
295 appender.events = 0; | |
296 ThreadGroup tg = new ThreadGroup(); | |
297 tg.create({ | |
298 char[128] tmp = 0; | |
299 context.setLevel(log.Level.Trace); | |
300 context.push("specialthread"); | |
301 context.push("2ndlevel"); | |
302 for (int i=0;i < 10; i++) { | |
303 log.info(log.format(tmp, "test5 {}", i)); | |
304 log.trace(log.format(tmp, "test5 {}", i)); | |
305 } | |
306 }); | |
307 tg.create({ | |
308 char[128] tmp = 0; | |
309 context.setLevel(log.Level.None); | |
310 for (int i=0;i < 10; i++) { | |
311 log.info(log.format(tmp, "test6 {}", i)); | |
312 log.trace(log.format(tmp, "test6 {}", i)); | |
313 } | |
314 }); | |
315 tg.joinAll(); | |
316 | |
317 if (appender.events !is 30) { | |
318 log.error(log.format(tmp, "events:{}", appender.events)); | |
319 throw new Exception("Incorrect Number of events in TLS multi thread mode"); | |
320 } | |
321 } | |
322 |