1 /**
2  * This module defines a set of logging functions that can be used in any
3  * application. There is a set of basic `log` functions that accept any logging
4  * level, as well as pre-defined functions for the standard SLF4D logging
5  * levels.
6  * 
7  * ### Basic Log Functions
8  * ---
9  * log(Levels.WARN, "Warning message");
10  * log(Levels.ERROR, new Exception("Oh no!"));
11  * logF!"Info message: %d"(Levels.INFO, 42);
12  * ---
13  */
14 module slf4d.log_functions;
15 
16 import slf4d.level;
17 import slf4d : getLogger;
18 
19 /** 
20  * Writes a log message.
21  * Params:
22  *   level = The logging level.
23  *   msg = The message.
24  *   exception = An optional exception to log.
25  *   attributes = Key-value pairs of additional user-defined attributes.
26  *   moduleName = The name of the module where this log message was written.
27  *   functionName = The name of the function where this log message was written.
28  *   fileName = The name of the source file where this log message was written.
29  *   lineNumber = The line number where this log message was written.
30  */
31 public void log(
32     Level level,
33     string msg,
34     Exception exception = null,
35     string[string] attributes = string[string].init,
36     string moduleName = __MODULE__,
37     string functionName = __PRETTY_FUNCTION__,
38     string fileName = __FILE__,
39     size_t lineNumber = __LINE__
40 ) {
41     getLogger(moduleName).log(level, msg, exception, attributes, moduleName, functionName, fileName, lineNumber);
42 }
43 
44 /** 
45  * Writes an exception log message.
46  * Params:
47  *   level = The logging level.
48  *   exception = The exception to log.
49  *   attributes = Key-value pairs of additional user-defined attributes.
50  *   moduleName = The name of the module where this log message was written.
51  *   functionName = The name of the function where this log message was written.
52  *   fileName = The name of the source file where this log message was written.
53  *   lineNumber = The line number where this log message was written.
54  */
55 public void log(
56     Level level,
57     Exception exception,
58     string[string] attributes = string[string].init,
59     string moduleName = __MODULE__,
60     string functionName = __PRETTY_FUNCTION__,
61     string fileName = __FILE__,
62     size_t lineNumber = __LINE__
63 ) {
64     getLogger(moduleName).log(level, exception, attributes, moduleName, functionName, fileName, lineNumber);
65 }
66 
67 /** 
68  * Writes a formatted log message.
69  * Params:
70  *   level = The logging level.
71  *   args = The arguments to provide to the format string.
72  *   exception = An optional exception to log.
73  *   attributes = Key-value pairs of additional user-defined attributes.
74  *   moduleName = The name of the module where this log message was written.
75  *   functionName = The name of the function where this log message was written.
76  *   fileName = The name of the source file where this log message was written.
77  *   lineNumber = The line number where this log message was written.
78  */
79 public void logF(string fmt, T...)(
80     Level level,
81     T args,
82     Exception exception = null,
83     string[string] attributes = string[string].init,
84     string moduleName = __MODULE__,
85     string functionName = __PRETTY_FUNCTION__,
86     string fileName = __FILE__,
87     size_t lineNumber = __LINE__
88 ) {
89     auto logger = getLogger(moduleName);
90     if (logger.level.value <= level.value) {
91         import std.format : format;
92         logger.log(level, format!(fmt)(args), exception, attributes, moduleName, functionName, fileName, lineNumber);
93     }
94 }
95 
96 /** 
97  * Writes a trace log message.
98  * Params:
99  *   msg = The message.
100  *   exception = An optional exception to log.
101  *   attributes = Key-value pairs of additional user-defined attributes.
102  *   moduleName = The name of the module where this log message was written.
103  *   functionName = The name of the function where this log message was written.
104  *   fileName = The name of the source file where this log message was written.
105  *   lineNumber = The line number where this log message was written.
106  */
107 public void trace(
108     string msg,
109     Exception exception = null,
110     string[string] attributes = string[string].init,
111     string moduleName = __MODULE__,
112     string functionName = __PRETTY_FUNCTION__,
113     string fileName = __FILE__,
114     size_t lineNumber = __LINE__
115 ) {
116     log(Levels.TRACE, msg, exception, attributes, moduleName, functionName, fileName, lineNumber);
117 }
118 
119 /** 
120  * Writes an exception trace log message.
121  * Params:
122  *   level = The logging level.
123  *   exception = The exception to log.
124  *   attributes = Key-value pairs of additional user-defined attributes.
125  *   moduleName = The name of the module where this log message was written.
126  *   functionName = The name of the function where this log message was written.
127  *   fileName = The name of the source file where this log message was written.
128  *   lineNumber = The line number where this log message was written.
129  */
130 public void trace(
131     Exception exception,
132     string[string] attributes = string[string].init,
133     string moduleName = __MODULE__,
134     string functionName = __PRETTY_FUNCTION__,
135     string fileName = __FILE__,
136     size_t lineNumber = __LINE__
137 ) {
138     log(Levels.TRACE, exception, attributes, moduleName, functionName, fileName, lineNumber);
139 }
140 
141 /** 
142  * Writes a formatted trace log message.
143  * Params:
144  *   level = The logging level.
145  *   args = The arguments to provide to the format string.
146  *   exception = An optional exception to log.
147  *   attributes = Key-value pairs of additional user-defined attributes.
148  *   moduleName = The name of the module where this log message was written.
149  *   functionName = The name of the function where this log message was written.
150  *   fileName = The name of the source file where this log message was written.
151  *   lineNumber = The line number where this log message was written.
152  */
153 public void traceF(string fmt, T...)(
154     T args,
155     Exception exception = null,
156     string[string] attributes = string[string].init,
157     string moduleName = __MODULE__,
158     string functionName = __PRETTY_FUNCTION__,
159     string fileName = __FILE__,
160     size_t lineNumber = __LINE__
161 ) {
162     auto logger = getLogger(moduleName);
163     if (logger.level.value <= Levels.TRACE.value) {
164         import std.format : format;
165         logger.log(Levels.TRACE, format!(fmt)(args), exception, attributes, moduleName, functionName, fileName, lineNumber);
166     }
167 }
168 
169 /** 
170  * Writes a debug log message.
171  * Params:
172  *   msg = The message.
173  *   exception = An optional exception to log.
174  *   attributes = Key-value pairs of additional user-defined attributes.
175  *   moduleName = The name of the module where this log message was written.
176  *   functionName = The name of the function where this log message was written.
177  *   fileName = The name of the source file where this log message was written.
178  *   lineNumber = The line number where this log message was written.
179  */
180 public void debug_(
181     string msg,
182     Exception exception = null,
183     string[string] attributes = string[string].init,
184     string moduleName = __MODULE__,
185     string functionName = __PRETTY_FUNCTION__,
186     string fileName = __FILE__,
187     size_t lineNumber = __LINE__
188 ) {
189     log(Levels.DEBUG, msg, exception, attributes, moduleName, functionName, fileName, lineNumber);
190 }
191 
192 /** 
193  * Writes an exception debug log message.
194  * Params:
195  *   level = The logging level.
196  *   exception = The exception to log.
197  *   attributes = Key-value pairs of additional user-defined attributes.
198  *   moduleName = The name of the module where this log message was written.
199  *   functionName = The name of the function where this log message was written.
200  *   fileName = The name of the source file where this log message was written.
201  *   lineNumber = The line number where this log message was written.
202  */
203 public void debug_(
204     Exception exception,
205     string[string] attributes = string[string].init,
206     string moduleName = __MODULE__,
207     string functionName = __PRETTY_FUNCTION__,
208     string fileName = __FILE__,
209     size_t lineNumber = __LINE__
210 ) {
211     log(Levels.DEBUG, exception, attributes, moduleName, functionName, fileName, lineNumber);
212 }
213 
214 /** 
215  * Writes a formatted debug log message.
216  * Params:
217  *   level = The logging level.
218  *   args = The arguments to provide to the format string.
219  *   exception = An optional exception to log.
220  *   attributes = Key-value pairs of additional user-defined attributes.
221  *   moduleName = The name of the module where this log message was written.
222  *   functionName = The name of the function where this log message was written.
223  *   fileName = The name of the source file where this log message was written.
224  *   lineNumber = The line number where this log message was written.
225  */
226 public void debugF(string fmt, T...)(
227     T args,
228     Exception exception = null,
229     string[string] attributes = string[string].init,
230     string moduleName = __MODULE__,
231     string functionName = __PRETTY_FUNCTION__,
232     string fileName = __FILE__,
233     size_t lineNumber = __LINE__
234 ) {
235     auto logger = getLogger(moduleName);
236     if (logger.level.value <= Levels.DEBUG.value) {
237         import std.format : format;
238         logger.log(Levels.DEBUG, format!(fmt)(args), exception, attributes, moduleName, functionName, fileName, lineNumber);
239     }
240 }
241 
242 /** 
243  * Writes an info log message.
244  * Params:
245  *   msg = The message.
246  *   exception = An optional exception to log.
247  *   attributes = Key-value pairs of additional user-defined attributes.
248  *   moduleName = The name of the module where this log message was written.
249  *   functionName = The name of the function where this log message was written.
250  *   fileName = The name of the source file where this log message was written.
251  *   lineNumber = The line number where this log message was written.
252  */
253 public void info(
254     string msg,
255     Exception exception = null,
256     string[string] attributes = string[string].init,
257     string moduleName = __MODULE__,
258     string functionName = __PRETTY_FUNCTION__,
259     string fileName = __FILE__,
260     size_t lineNumber = __LINE__
261 ) {
262     log(Levels.INFO, msg, exception, attributes, moduleName, functionName, fileName, lineNumber);
263 }
264 
265 /** 
266  * Writes an exception info log message.
267  * Params:
268  *   level = The logging level.
269  *   exception = The exception to log.
270  *   attributes = Key-value pairs of additional user-defined attributes.
271  *   moduleName = The name of the module where this log message was written.
272  *   functionName = The name of the function where this log message was written.
273  *   fileName = The name of the source file where this log message was written.
274  *   lineNumber = The line number where this log message was written.
275  */
276 public void info(
277     Exception exception,
278     string[string] attributes = string[string].init,
279     string moduleName = __MODULE__,
280     string functionName = __PRETTY_FUNCTION__,
281     string fileName = __FILE__,
282     size_t lineNumber = __LINE__
283 ) {
284     log(Levels.INFO, exception, attributes, moduleName, functionName, fileName, lineNumber);
285 }
286 
287 /** 
288  * Writes a formatted info log message.
289  * Params:
290  *   level = The logging level.
291  *   args = The arguments to provide to the format string.
292  *   exception = An optional exception to log.
293  *   attributes = Key-value pairs of additional user-defined attributes.
294  *   moduleName = The name of the module where this log message was written.
295  *   functionName = The name of the function where this log message was written.
296  *   fileName = The name of the source file where this log message was written.
297  *   lineNumber = The line number where this log message was written.
298  */
299 public void infoF(string fmt, T...)(
300     T args,
301     Exception exception = null,
302     string[string] attributes = string[string].init,
303     string moduleName = __MODULE__,
304     string functionName = __PRETTY_FUNCTION__,
305     string fileName = __FILE__,
306     size_t lineNumber = __LINE__
307 ) {
308     auto logger = getLogger(moduleName);
309     if (logger.level.value <= Levels.INFO.value) {
310         import std.format : format;
311         logger.log(Levels.INFO, format!(fmt)(args), exception, attributes, moduleName, functionName, fileName, lineNumber);
312     }
313 }
314 
315 /** 
316  * Writes a warn log message.
317  * Params:
318  *   msg = The message.
319  *   exception = An optional exception to log.
320  *   attributes = Key-value pairs of additional user-defined attributes.
321  *   moduleName = The name of the module where this log message was written.
322  *   functionName = The name of the function where this log message was written.
323  *   fileName = The name of the source file where this log message was written.
324  *   lineNumber = The line number where this log message was written.
325  */
326 public void warn(
327     string msg,
328     Exception exception = null,
329     string[string] attributes = string[string].init,
330     string moduleName = __MODULE__,
331     string functionName = __PRETTY_FUNCTION__,
332     string fileName = __FILE__,
333     size_t lineNumber = __LINE__
334 ) {
335     log(Levels.WARN, msg, exception, attributes, moduleName, functionName, fileName, lineNumber);
336 }
337 
338 /** 
339  * Writes an exception warn log message.
340  * Params:
341  *   level = The logging level.
342  *   exception = The exception to log.
343  *   attributes = Key-value pairs of additional user-defined attributes.
344  *   moduleName = The name of the module where this log message was written.
345  *   functionName = The name of the function where this log message was written.
346  *   fileName = The name of the source file where this log message was written.
347  *   lineNumber = The line number where this log message was written.
348  */
349 public void warn(
350     Exception exception,
351     string[string] attributes = string[string].init,
352     string moduleName = __MODULE__,
353     string functionName = __PRETTY_FUNCTION__,
354     string fileName = __FILE__,
355     size_t lineNumber = __LINE__
356 ) {
357     log(Levels.WARN, exception, attributes, moduleName, functionName, fileName, lineNumber);
358 }
359 
360 /** 
361  * Writes a formatted warn log message.
362  * Params:
363  *   level = The logging level.
364  *   args = The arguments to provide to the format string.
365  *   exception = An optional exception to log.
366  *   attributes = Key-value pairs of additional user-defined attributes.
367  *   moduleName = The name of the module where this log message was written.
368  *   functionName = The name of the function where this log message was written.
369  *   fileName = The name of the source file where this log message was written.
370  *   lineNumber = The line number where this log message was written.
371  */
372 public void warnF(string fmt, T...)(
373     T args,
374     Exception exception = null,
375     string[string] attributes = string[string].init,
376     string moduleName = __MODULE__,
377     string functionName = __PRETTY_FUNCTION__,
378     string fileName = __FILE__,
379     size_t lineNumber = __LINE__
380 ) {
381     auto logger = getLogger(moduleName);
382     if (logger.level.value <= Levels.WARN.value) {
383         import std.format : format;
384         logger.log(Levels.WARN, format!(fmt)(args), exception, attributes, moduleName, functionName, fileName, lineNumber);
385     }
386 }
387 
388 /** 
389  * Writes an error log message.
390  * Params:
391  *   msg = The message.
392  *   exception = An optional exception to log.
393  *   attributes = Key-value pairs of additional user-defined attributes.
394  *   moduleName = The name of the module where this log message was written.
395  *   functionName = The name of the function where this log message was written.
396  *   fileName = The name of the source file where this log message was written.
397  *   lineNumber = The line number where this log message was written.
398  */
399 public void error(
400     string msg,
401     Exception exception = null,
402     string[string] attributes = string[string].init,
403     string moduleName = __MODULE__,
404     string functionName = __PRETTY_FUNCTION__,
405     string fileName = __FILE__,
406     size_t lineNumber = __LINE__
407 ) {
408     log(Levels.ERROR, msg, exception, attributes, moduleName, functionName, fileName, lineNumber);
409 }
410 
411 /** 
412  * Writes an exception error log message.
413  * Params:
414  *   level = The logging level.
415  *   exception = The exception to log.
416  *   attributes = Key-value pairs of additional user-defined attributes.
417  *   moduleName = The name of the module where this log message was written.
418  *   functionName = The name of the function where this log message was written.
419  *   fileName = The name of the source file where this log message was written.
420  *   lineNumber = The line number where this log message was written.
421  */
422 public void error(
423     Exception exception,
424     string[string] attributes = string[string].init,
425     string moduleName = __MODULE__,
426     string functionName = __PRETTY_FUNCTION__,
427     string fileName = __FILE__,
428     size_t lineNumber = __LINE__
429 ) {
430     log(Levels.ERROR, exception, attributes, moduleName, functionName, fileName, lineNumber);
431 }
432 
433 /** 
434  * Writes a formatted error log message.
435  * Params:
436  *   level = The logging level.
437  *   args = The arguments to provide to the format string.
438  *   exception = An optional exception to log.
439  *   attributes = Key-value pairs of additional user-defined attributes.
440  *   moduleName = The name of the module where this log message was written.
441  *   functionName = The name of the function where this log message was written.
442  *   fileName = The name of the source file where this log message was written.
443  *   lineNumber = The line number where this log message was written.
444  */
445 public void errorF(string fmt, T...)(
446     T args,
447     Exception exception = null,
448     string[string] attributes = string[string].init,
449     string moduleName = __MODULE__,
450     string functionName = __PRETTY_FUNCTION__,
451     string fileName = __FILE__,
452     size_t lineNumber = __LINE__
453 ) {
454     auto logger = getLogger(moduleName);
455     if (logger.level.value <= Levels.ERROR.value) {
456         import std.format : format;
457         logger.log(Levels.ERROR, format!(fmt)(args), exception, attributes, moduleName, functionName, fileName, lineNumber);
458     }
459 }
460 
461 import slf4d.logger : LogBuilder;
462 
463 public LogBuilder logBuilder(string moduleName = __MODULE__){
464     return getLogger(moduleName).builder();
465 }
466 
467 unittest {
468     import slf4d.test;
469     synchronized (loggingTestingMutex) {
470         TestingLoggingProvider provider = getTestingProvider();
471         
472         // Test formatted functions without any format specifiers.
473         logF!"Testing"(Levels.INFO);
474         provider.assertHasMessage("Testing");
475         traceF!"Testing trace"();
476         provider.assertHasMessage("Testing trace");
477         debugF!"Testing debug"();
478         provider.assertHasMessage("Testing debug");
479         infoF!"Testing info"();
480         provider.assertHasMessage("Testing info");
481         warnF!"Testing warn"();
482         provider.assertHasMessage("Testing warn");
483         errorF!"Testing error"();
484         provider.assertHasMessage("Testing error");
485         provider.reset();
486 
487         // Test formatted functions with argument and an exception.
488         Exception exc = new Exception("Uh oh");
489         
490         // Test calling the builder function.
491         logBuilder()
492             .lvl(Levels.DEBUG)
493             .msg("Testing builder")
494             .attr("test", "yes")
495             .log();
496         provider.assertHasMessage("Testing builder");
497         LogMessage msg = provider.messages[0];
498         assert(msg.level == Levels.DEBUG);
499         assert(msg.attributes["test"] == "yes");
500 
501         resetLoggingState();
502     }
503 }