1 /** 2 * Default logger 3 * 4 * Authors: Tristan Brice Velloza Kildaire (deavmi) 5 */ 6 module dlog.defaults; 7 8 import dlog.core; 9 import dlog.basic : BasicMessage, FileHandler, Level, BasicLogger; 10 import std.stdio : stdout; 11 import std.conv : to; 12 import dlog.utilities : flatten; 13 import std.array :join; 14 import std.datetime.systime : Clock, SysTime; 15 16 /** 17 * DefaultLogger 18 * 19 * The default logger logs using 20 * a pretty stock-standard (non-colored) 21 * message transformation and supports 22 * the basic levels of logging. 23 */ 24 public final class DefaultLogger : BasicLogger 25 { 26 /** 27 * The joiner for multi-argument 28 * log messages 29 */ 30 private string multiArgJoiner; 31 32 /** 33 * Constructs a new default logger 34 * 35 * Params: 36 * multiArgJoiner = the joiner to use 37 */ 38 this(string multiArgJoiner = " ") 39 { 40 this.multiArgJoiner = multiArgJoiner; 41 42 addTransform(new DefaultTransform()); 43 addHandler(new FileHandler(stdout)); 44 } 45 46 /** 47 * Logs the given message of an arbitrary amount of 48 * arguments and specifically sets the level to ERROR 49 * 50 * Params: 51 * segments = the arbitrary argumnets (alias sequence) 52 */ 53 public void error(TextType...)(TextType segments) 54 { 55 doLog(segments, Level.ERROR); 56 } 57 58 /** 59 * Logs the given message of an arbitrary amount of 60 * arguments and specifically sets the level to INFO 61 * 62 * Params: 63 * segments = the arbitrary argumnets (alias sequence) 64 */ 65 public void info(TextType...)(TextType segments) 66 { 67 doLog(segments, Level.INFO); 68 } 69 70 /** 71 * Logs the given message of an arbitrary amount of 72 * arguments and specifically sets the level to WARN 73 * 74 * Params: 75 * segments = the arbitrary argumnets (alias sequence) 76 */ 77 public void warn(TextType...)(TextType segments) 78 { 79 doLog(segments, Level.WARN); 80 } 81 82 /** 83 * Logs the given message of an arbitrary amount of 84 * arguments and specifically sets the level to DEBUG 85 * 86 * Params: 87 * segments = the arbitrary argumnets (alias sequence) 88 */ 89 public void debug_(TextType...)(TextType segments) 90 { 91 doLog(segments, Level.DEBUG); 92 } 93 94 /** 95 * Performs the actual logging 96 * by packing up everything before 97 * sending it to the `log(Message)` 98 * method 99 * 100 * Params: 101 * segments = the compile-time segments 102 * level = the log level to use 103 */ 104 private void doLog(TextType...)(TextType segments, Level level) 105 { 106 /* Create a new basic message */ 107 BasicMessage message = new BasicMessage(); 108 109 /* Set the level */ 110 message.setLevel(level); 111 112 /** 113 * Grab all compile-time arguments and make them 114 * into an array, then join them together and 115 * set that text as the message's text 116 */ 117 message.setText(join(flatten(segments), multiArgJoiner)); 118 119 /* Log this message */ 120 log(message); 121 } 122 123 /** 124 * Alias for debug_ 125 */ 126 public alias dbg = debug_; 127 } 128 129 /** 130 * DefaultTransform 131 * 132 * Provides a transformation of the kind 133 * 134 * [date+time] (level): message `\n` 135 */ 136 private final class DefaultTransform : Transform 137 { 138 /** 139 * Performs the default transformation. 140 * If the message is not a `BasicMessage` 141 * then no transformation occurs. 142 * 143 * Params: 144 * message = the message to transform 145 * Returns: the transformed message 146 */ 147 public Message transform(Message message) 148 { 149 // Only handle BasicMessage(s) 150 BasicMessage bmesg = cast(BasicMessage)message; 151 if(bmesg is null) 152 { 153 return message; 154 } 155 156 string text; 157 158 /* Date and time */ 159 SysTime currTime = Clock.currTime(); 160 string timestamp = to!(string)(currTime); 161 text = "["~timestamp~"]"; 162 163 /* Level */ 164 text = text ~ "\t("; 165 text = text ~ to!(string)(bmesg.getLevel()); 166 text = text ~ "): "~bmesg.getText(); 167 168 /* Add trailing newline */ 169 text = text ~ '\n'; 170 171 /* Store the updated text */ 172 bmesg.setText(text); 173 174 return message; 175 } 176 } 177 178 version(unittest) 179 { 180 import std.meta : AliasSeq; 181 import std.stdio : writeln; 182 } 183 184 /** 185 * Tests the DefaultLogger 186 */ 187 unittest 188 { 189 DefaultLogger logger = new DefaultLogger(); 190 191 // Set logging level to at least INFO 192 logger.setLevel(Level.INFO); 193 194 alias testParameters = AliasSeq!("This is a log message", 1.1, true, [1,2,3], 'f', logger); 195 196 197 // Test various types one-by-one 198 static foreach(testParameter; testParameters) 199 { 200 logger.info(testParameter); 201 } 202 203 // Test various parameters (of various types) all at once 204 logger.info(testParameters); 205 206 // Same as above but with a custom joiner set 207 logger = new DefaultLogger("(-)"); 208 209 // Set logging level to at least INFO 210 logger.setLevel(Level.INFO); 211 212 logger.info(testParameters); 213 214 writeln(); 215 } 216 217 /** 218 * Printing out some mixed data-types, also using a DEFAULT context 219 */ 220 unittest 221 { 222 // Create a default logger with the default joiner 223 DefaultLogger logger = new DefaultLogger(); 224 225 // Set logging level to at least INFO 226 logger.setLevel(Level.INFO); 227 228 // Log some stuff 229 logger.info(["a", "b", "c", "d"], [1, 2], true); 230 231 writeln(); 232 } 233 234 /** 235 * Printing out some mixed data-types, also using a DEFAULT context 236 * but also testing out the `error()`, `warn()`, `info()` and `debug()` 237 */ 238 unittest 239 { 240 // Create a default logger with the default joiner 241 DefaultLogger logger = new DefaultLogger(); 242 243 // Set logging level to at least DEBUG 244 logger.setLevel(Level.DEBUG); 245 246 // Test out `error()` 247 logger.error(["woah", "LEVELS!"], 69.420); 248 249 // Test out `info()` 250 logger.info(["woah", "LEVELS!"], 69.420); 251 252 // Test out `warn()` 253 logger.warn(["woah", "LEVELS!"], 69.420); 254 255 // Test out `debug_()` 256 logger.debug_(["woah", "LEVELS!"], 69.420); 257 258 // Should not be able to see this 259 logger.setLevel(Level.INFO); 260 logger.debug_("Can't see me!"); 261 262 writeln(); 263 }