1 /* 2 * Hunt - A refined core library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.logging.ConsoleLogger; 13 14 import hunt.concurrency.thread.Helper; 15 16 import core.stdc.stdlib; 17 import core.runtime; 18 import core.thread; 19 20 import std.stdio; 21 import std.datetime; 22 import std.format; 23 import std.range; 24 import std.conv; 25 import std.regex; 26 import std.typecons; 27 import std.traits; 28 import std.string; 29 30 // ThreadID getTid() 31 // { 32 // return Thread.getThis.id; 33 // } 34 35 version (Windows) { 36 import core.sys.windows.wincon; 37 import core.sys.windows.winbase; 38 import core.sys.windows.windef; 39 40 private __gshared HANDLE g_hout; 41 42 shared static this() { 43 g_hout = GetStdHandle(STD_OUTPUT_HANDLE); 44 SetConsoleTextAttribute(g_hout, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); 45 } 46 47 void resetConsoleColor() { 48 SetConsoleTextAttribute(g_hout, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); 49 } 50 } 51 52 version (Posix) { 53 enum PRINT_COLOR_NONE = "\033[m"; 54 enum PRINT_COLOR_RED = "\033[0;32;31m"; 55 enum PRINT_COLOR_GREEN = "\033[0;32;32m"; 56 enum PRINT_COLOR_YELLOW = "\033[1;33m"; 57 } 58 59 enum LogLevel { 60 Trace = 0, 61 Info = 1, 62 Warning = 2, 63 Error = 3, 64 Fatal = 4, 65 Off = 5 66 } 67 68 /** 69 */ 70 class ConsoleLogger { 71 private __gshared LogLevel g_logLevel = LogLevel.Trace; 72 private enum traceLevel = toString(LogLevel.Trace); 73 private enum infoLevel = toString(LogLevel.Info); 74 private enum warningLevel = toString(LogLevel.Warning); 75 private enum errorLevel = toString(LogLevel.Error); 76 private enum fatalLevel = toString(LogLevel.Fatal); 77 private enum offlLevel = toString(LogLevel.Off); 78 79 static void setLogLevel(LogLevel level) { 80 g_logLevel = level; 81 } 82 83 static void trace(string file = __FILE__, size_t line = __LINE__, 84 string func = __FUNCTION__, A...)(lazy A args) nothrow { 85 writeFormatColor(LogLevel.Trace, layout!(file, line, func)(logFormat(args), traceLevel)); 86 } 87 88 static void tracef(string file = __FILE__, size_t line = __LINE__, 89 string func = __FUNCTION__, A...)(lazy A args) nothrow { 90 writeFormatColor(LogLevel.Trace, layout!(file, line, func)(logFormatf(args), traceLevel)); 91 } 92 93 static void info(string file = __FILE__, size_t line = __LINE__, 94 string func = __FUNCTION__, A...)(lazy A args) nothrow { 95 writeFormatColor(LogLevel.Info, layout!(file, line, func)(logFormat(args), infoLevel)); 96 } 97 98 static void infof(string file = __FILE__, size_t line = __LINE__, 99 string func = __FUNCTION__, A...)(lazy A args) nothrow { 100 writeFormatColor(LogLevel.Info, layout!(file, line, func)(logFormatf(args), infoLevel)); 101 } 102 103 static void warning(string file = __FILE__, size_t line = __LINE__, 104 string func = __FUNCTION__, A...)(lazy A args) nothrow { 105 writeFormatColor(LogLevel.Warning, layout!(file, line, 106 func)(logFormat(args), warningLevel)); 107 } 108 109 static void warningf(string file = __FILE__, size_t line = __LINE__, 110 string func = __FUNCTION__, A...)(lazy A args) nothrow { 111 writeFormatColor(LogLevel.Warning, layout!(file, line, 112 func)(logFormatf(args), warningLevel)); 113 } 114 115 static void error(string file = __FILE__, size_t line = __LINE__, 116 string func = __FUNCTION__, A...)(lazy A args) nothrow { 117 writeFormatColor(LogLevel.Error, layout!(file, line, func)(logFormat(args), errorLevel)); 118 } 119 120 static void errorf(string file = __FILE__, size_t line = __LINE__, 121 string func = __FUNCTION__, A...)(lazy A args) nothrow { 122 writeFormatColor(LogLevel.Error, layout!(file, line, func)(logFormatf(args), errorLevel)); 123 } 124 125 static void fatal(string file = __FILE__, size_t line = __LINE__, 126 string func = __FUNCTION__, A...)(lazy A args) nothrow { 127 writeFormatColor(LogLevel.Fatal, layout!(file, line, func)(logFormat(args), fatalLevel)); 128 } 129 130 static void fatalf(string file = __FILE__, size_t line = __LINE__, 131 string func = __FUNCTION__, A...)(lazy A args) nothrow { 132 writeFormatColor(LogLevel.Fatal, layout!(file, line, func)(logFormatf(args), fatalLevel)); 133 } 134 135 private static string logFormatf(A...)(A args) { 136 Appender!string buffer; 137 formattedWrite(buffer, args); 138 return buffer.data; 139 } 140 141 private static string logFormat(A...)(A args) { 142 auto w = appender!string(); 143 foreach (arg; args) { 144 alias A = typeof(arg); 145 static if (isAggregateType!A || is(A == enum)) { 146 import std.format : formattedWrite; 147 148 formattedWrite(w, "%s", arg); 149 } 150 else static if (isSomeString!A) { 151 put(w, arg); 152 } 153 else static if (isIntegral!A) { 154 import std.conv : toTextRange; 155 156 toTextRange(arg, w); 157 } 158 else static if (isBoolean!A) { 159 put(w, arg ? "true" : "false"); 160 } 161 else static if (isSomeChar!A) { 162 put(w, arg); 163 } 164 else { 165 import std.format : formattedWrite; 166 167 // Most general case 168 formattedWrite(w, "%s", arg); 169 } 170 } 171 return w.data; 172 } 173 174 private static string layout(string file = __FILE__, size_t line = __LINE__, 175 string func = __FUNCTION__)(string msg, string level) { 176 enum lineNum = std.conv.to!string(line); 177 string time_prior = Clock.currTime.toString(); 178 string tid = std.conv.to!string(getTid()); 179 180 // writeln(func); 181 string fun = func; 182 ptrdiff_t index = lastIndexOf(func, '.'); 183 if (index != -1) { 184 if(func[index -1] != ')') { 185 ptrdiff_t idx = lastIndexOf(func, '.', index); 186 if (idx != -1) 187 index = idx; 188 } 189 fun = func[index + 1 .. $]; 190 } 191 192 return time_prior ~ " | " ~ tid ~ " | " ~ level ~ " | " ~ fun ~ " | " ~ msg 193 ~ " | " ~ file ~ ":" ~ lineNum; 194 } 195 196 // private static string defaultLayout(string context, string msg, string level) 197 // { 198 // string time_prior = Clock.currTime.toString(); 199 // string tid = std.conv.to!string(getTid()); 200 201 // return time_prior ~ " | " ~ tid ~ " | " ~ level ~ context ~ msg; 202 // } 203 204 static string toString(LogLevel level) nothrow { 205 string r; 206 final switch (level) with (LogLevel) { 207 case Trace: 208 r = "trace"; 209 break; 210 case Info: 211 r = "info"; 212 break; 213 case Warning: 214 r = "warning"; 215 break; 216 case Error: 217 r = "error"; 218 break; 219 case Fatal: 220 r = "fatal"; 221 break; 222 case Off: 223 r = "off"; 224 break; 225 } 226 return r; 227 } 228 229 private static void writeFormatColor(LogLevel level, lazy string msg) nothrow { 230 if (level < g_logLevel) 231 return; 232 233 version (Posix) { 234 string prior_color; 235 switch (level) with (LogLevel) { 236 case Error: 237 case Fatal: 238 prior_color = PRINT_COLOR_RED; 239 break; 240 case Warning: 241 prior_color = PRINT_COLOR_YELLOW; 242 break; 243 case Info: 244 prior_color = PRINT_COLOR_GREEN; 245 break; 246 default: 247 prior_color = string.init; 248 } 249 import std.exception; 250 collectException(writeln(prior_color ~ msg ~ PRINT_COLOR_NONE)); 251 252 } 253 else version (Windows) { 254 import std.windows.charset; 255 import core.stdc.stdio; 256 257 enum defaultColor = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE; 258 259 ushort color; 260 switch (level) with (LogLevel) { 261 case Error: 262 case Fatal: 263 color = FOREGROUND_RED; 264 break; 265 case Warning: 266 color = FOREGROUND_GREEN | FOREGROUND_RED; 267 break; 268 case Info: 269 color = FOREGROUND_GREEN; 270 break; 271 default: 272 color = defaultColor; 273 } 274 275 SetConsoleTextAttribute(g_hout, color); 276 277 try { 278 printf("%s\n", toMBSz(msg)); 279 } catch (Exception) { 280 } 281 282 if (color != defaultColor) 283 SetConsoleTextAttribute(g_hout, defaultColor); 284 } 285 } 286 } 287 288 289 alias trace = ConsoleLogger.trace; 290 alias tracef = ConsoleLogger.tracef; 291 alias info = ConsoleLogger.info; 292 alias infof = ConsoleLogger.infof; 293 alias warning = ConsoleLogger.warning; 294 alias warningf = ConsoleLogger.warningf; 295 alias error = ConsoleLogger.error; 296 alias errorf = ConsoleLogger.errorf; 297 // alias critical = ConsoleLogger.critical; 298 // alias criticalf = ConsoleLogger.criticalf; 299 300 alias logDebug = trace; 301 alias logDebugf = tracef; 302 alias logInfo = info; 303 alias logInfof = infof; 304 alias logWarning = warning; 305 alias logWarningf = warningf; 306 alias logError = error; 307 alias logErrorf = errorf;