1 module mysql.logger;
2 
3 @safe:
4 
5 /*
6   The aliased log functions in this module map to equivelant functions in either vibe.core.log or std.experimental.logger.
7   For this reason, only log levels common to both are used. The exception to this is logDebug which is uses trace when
8   using std.experimental.logger, only because it's commonly used and trace/debug/verbose are all similar in use.
9   Also, I've chosen not to support fatal errors as std.experimental.logger will create an exception if you choose to
10   log at this level, which is an unhelpful side effect.
11 
12   See the following table for how they are mapped:
13 
14   | Our logger		| vibe.core.log | LogLevel (std.experimental.logger) |
15   | --------------- | ------------- | ---------------------------------- |
16   | logTrace 		| logTrace 		| LogLevel.trace		  			 |
17   |	N/A				| logDebugV		| N/A				      			 |
18   | logDebug		| logDebug		| LogLevel.trace					 |
19   | N/A				| logDiagnostic | N/A				      			 |
20   | logInfo			| logInfo		| LogLevel.info 		  			 |
21   | logWarn			| logWarn		| LogLevel.warning  	  			 |
22   | logError		| logError		| LogLevel.error 		  			 |
23   | logCritical		| logCritical	| LogLevel.critical 	  			 |
24   | N/A				| logFatal		| LogLevel.fatal 		  			 |
25 
26 */
27 version(Have_vibe_core) {
28 	import vibe.core.log;
29 
30 	alias logTrace = vibe.core.log.logTrace;
31 	alias logDebug = vibe.core.log.logDebug;
32 	alias logInfo = vibe.core.log.logInfo;
33 	alias logWarn = vibe.core.log.logWarn;
34 	alias logError = vibe.core.log.logError;
35 	alias logCritical = vibe.core.log.logCritical;
36 	//alias logFatal = vibe.core.log.logFatal;
37 } else static if(__traits(compiles, (){ import std.experimental.logger; } )) {
38 	import std.experimental.logger;
39 
40 	alias logTrace = std.experimental.logger.tracef;
41 	alias logDebug = std.experimental.logger.tracef; // no debug level in std.experimental.logger but arguably trace/debug/verbose all mean the same
42 	alias logInfo = std.experimental.logger.infof;
43 	alias logWarn = std.experimental.logger.warningf;
44 	alias logError = std.experimental.logger.errorf;
45 	alias logCritical = std.experimental.logger.criticalf;
46 	//alias logFatal = std.experimental.logger.fatalf;
47 } else static assert(false);
48 
49 unittest {
50 	version(Have_vibe_core) {
51 		import std.stdio : writeln;
52 		writeln("Running the logger tests using (vibe.core.log)");
53 		// Althouth there are no asserts here, this confirms that the alias compiles ok also the output
54 		// is shown in the terminal when running 'dub test' and the levels logged using different colours.
55 		logTrace("Test that a call to mysql.logger.logTrace maps to vibe.core.log.logTrace");
56 		logDebug("Test that a call to mysql.logger.logDebug maps to vibe.core.log.logDebug");
57 		logInfo("Test that a call to mysql.logger.logInfo maps to vibe.core.log.logInfo");
58 		logWarn("Test that a call to mysql.logger.logWarn maps to vibe.core.log.logWarn");
59 		logError("Test that a call to mysql.logger.logError maps to vibe.core.log.logError");
60 		logCritical("Test that a call to mysql.logger.logCritical maps to vibe.core.log.logCritical");
61 		//logFatal("Test that a call to mysql.logger.logFatal maps to vibe.core.log.logFatal");
62 	} else static if(__traits(compiles, (){ import std.experimental.logger; } )) {
63 		// Checks that when using std.experimental.logger the log entry is correct.
64 		// This test kicks in when commenting out the 'vibe-core' dependency and running 'dub test', although
65 		// not ideal if vibe-core is availble the logging goes through vibe anyway.
66 		// Output can be seen in terminal when running 'dub test'.
67 		import std.experimental.logger : Logger, LogLevel, sharedLog;
68 		import std.stdio : writeln, writefln;
69 		import std.conv : to;
70 
71 		writeln("Running the logger tests using (std.experimental.logger)");
72 
73 		class TestLogger : Logger {
74 			LogLevel logLevel;
75 			string file;
76 			string moduleName;
77 			string msg;
78 
79 			this(LogLevel lv) @safe {
80 				super(lv);
81 			}
82 
83 			override void writeLogMsg(ref LogEntry payload) @trusted {
84 				this.logLevel = payload.logLevel;
85 				this.file = payload.file;
86 				this.moduleName = payload.moduleName;
87 				this.msg = payload.msg;
88 				// now output it to stdio so it can be seen in terminal when testing
89 				writefln(" - testing [%s] %s(%s) : %s", payload.logLevel, payload.file, to!string(payload.line), payload.msg);
90 			}
91 		}
92 
93 		auto logger = new TestLogger(LogLevel.all);
94 		sharedLog = logger;
95 
96 		// check that the various log alias functions get the expected results
97 		logDebug("This is a TRACE message");
98 		assert(logger.logLevel == LogLevel.trace, "expected 'LogLevel.trace' got: " ~ logger.logLevel);
99 		assert(logger.msg == "This is a TRACE message", "The logger should have logged 'This is a TRACE message' but instead was: " ~ logger.msg);
100 		assert(logger.file == "source/mysql/logger.d", "expected 'source/mysql/logger.d' got: " ~ logger.file);
101 		assert(logger.moduleName == "mysql.logger", "expected 'mysql.logger' got: " ~ logger.moduleName);
102 
103 		logDebug("This is a DEBUG message (maps to trace)");
104 		assert(logger.logLevel == LogLevel.trace, "expected 'LogLevel.trace' got: " ~ logger.logLevel);
105 		assert(logger.msg == "This is a DEBUG message (maps to trace)", "The logger should have logged 'This is a DEBUG message (maps to trace)' but instead was: " ~ logger.msg);
106 		assert(logger.file == "source/mysql/logger.d", "expected 'source/mysql/logger.d' got: " ~ logger.file);
107 		assert(logger.moduleName == "mysql.logger", "expected 'mysql.logger' got: " ~ logger.moduleName);
108 
109 		logInfo("This is an INFO message");
110 		assert(logger.logLevel == LogLevel.info, "expected 'LogLevel.info' got: " ~ logger.logLevel);
111 		assert(logger.msg == "This is an INFO message", "The logger should have logged 'This is an INFO message' but instead was: " ~ logger.msg);
112 
113 		logWarn("This is a WARNING message");
114 		assert(logger.logLevel == LogLevel.warning, "expected 'LogLevel.warning' got: " ~ logger.logLevel);
115 		assert(logger.msg == "This is a WARNING message", "The logger should have logged 'This is a WARNING message' but instead was: " ~ logger.msg);
116 
117 		logError("This is a ERROR message");
118 		assert(logger.logLevel == LogLevel.error, "expected 'LogLevel.error' got: " ~ logger.logLevel);
119 		assert(logger.msg == "This is a ERROR message", "The logger should have logged 'This is a ERROR message' but instead was: " ~ logger.msg);
120 
121 		logCritical("This is a CRITICAL message");
122 		assert(logger.logLevel == LogLevel.critical, "expected 'LogLevel.critical' got: " ~ logger.logLevel);
123 		assert(logger.msg == "This is a CRITICAL message", "The logger should have logged 'This is a CRITICAL message' but instead was: " ~ logger.msg);
124 	}
125 }