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.util.ThreadHelper; 15 import hunt.util.ThreadHelper; 16 17 import core.stdc.stdlib; 18 import core.runtime; 19 import core.thread; 20 21 import std.conv; 22 import std.datetime; 23 import std.exception; 24 import std.format; 25 import std.range; 26 import std.regex; 27 import std.stdio; 28 import std.string; 29 import std.typecons; 30 import std.traits; 31 32 alias LogLayoutHandler = string delegate(string time_prior, string tid, string level, string myFunc, 33 string msg, string file, size_t line); 34 35 private { 36 __gshared LogLayoutHandler _layoutHandler; 37 38 LogLayoutHandler layoutHandler() { 39 if(_layoutHandler is null) { 40 _layoutHandler = (string time_prior, string tid, string level, string fun, 41 string msg, string file, size_t line) { 42 43 return time_prior ~ " | " ~ tid ~ " | " ~ level ~ " | " ~ fun ~ " | " ~ msg 44 ~ " | " ~ file ~ ":" ~ to!string(line); 45 }; 46 } 47 48 return _layoutHandler; 49 } 50 } 51 52 version (Windows) { 53 import core.sys.windows.wincon; 54 import core.sys.windows.winbase; 55 import core.sys.windows.windef; 56 import hunt.system.WindowsHelper; 57 58 } 59 60 version (Posix) { 61 enum PRINT_COLOR_NONE = "\033[m"; 62 enum PRINT_COLOR_RED = "\033[0;32;31m"; 63 enum PRINT_COLOR_GREEN = "\033[0;32;32m"; 64 enum PRINT_COLOR_YELLOW = "\033[1;33m"; 65 } 66 67 version (Android) { 68 import core.stdc.stdarg : va_end, va_list, va_start; 69 import core.sys.posix.sys.types; 70 71 enum { 72 AASSET_MODE_UNKNOWN, 73 AASSET_MODE_RANDOM, 74 AASSET_MODE_STREAMING, 75 AASSET_MODE_BUFFER 76 } 77 78 enum android_LogPriority { 79 ANDROID_LOG_UNKNOWN, 80 ANDROID_LOG_DEFAULT, 81 ANDROID_LOG_VERBOSE, 82 ANDROID_LOG_DEBUG, 83 ANDROID_LOG_INFO, 84 ANDROID_LOG_WARN, 85 ANDROID_LOG_ERROR, 86 ANDROID_LOG_FATAL, 87 ANDROID_LOG_SILENT 88 } 89 90 enum LOG_TAG = "HUNT"; 91 92 // dfmt off 93 extern (C): 94 @system: 95 nothrow: 96 @nogc: 97 // dfmt on 98 99 struct AAssetManager; 100 struct AAssetDir; 101 struct AAsset; 102 103 AAssetDir* AAssetManager_openDir(AAssetManager* mgr, const(char)* dirName); 104 AAsset* AAssetManager_open(AAssetManager* mgr, const(char)* filename, int mode); 105 const(char)* AAssetDir_getNextFileName(AAssetDir* assetDir); 106 void AAssetDir_rewind(AAssetDir* assetDir); 107 void AAssetDir_close(AAssetDir* assetDir); 108 int AAsset_read(AAsset* asset, void* buf, size_t count); 109 off_t AAsset_seek(AAsset* asset, off_t offset, int whence); 110 void AAsset_close(AAsset* asset); 111 const(void)* AAsset_getBuffer(AAsset* asset); 112 off_t AAsset_getLength(AAsset* asset); 113 off_t AAsset_getRemainingLength(AAsset* asset); 114 int AAsset_openFileDescriptor(AAsset* asset, off_t* outStart, off_t* outLength); 115 int AAsset_isAllocated(AAsset* asset); 116 117 int __android_log_write(int prio, const(char)* tag, const(char)* text); 118 int __android_log_print(int prio, const(char)* tag, const(char)* fmt, ...); 119 int __android_log_vprint(int prio, const(char)* tag, const(char)* fmt, va_list ap); 120 void __android_log_assert(const(char)* cond, const(char)* tag, const(char)* fmt, ...); 121 122 } 123 124 enum LogLevel { 125 Trace = 0, 126 Info = 1, 127 Warning = 2, 128 Error = 3, 129 Fatal = 4, 130 Off = 5 131 } 132 133 /** 134 * 135 */ 136 class ConsoleLogger { 137 private __gshared LogLevel g_logLevel = LogLevel.Trace; 138 private enum traceLevel = toString(LogLevel.Trace); 139 private enum infoLevel = toString(LogLevel.Info); 140 private enum warningLevel = toString(LogLevel.Warning); 141 private enum errorLevel = toString(LogLevel.Error); 142 private enum fatalLevel = toString(LogLevel.Fatal); 143 private enum offlLevel = toString(LogLevel.Off); 144 145 static void setLogLevel(LogLevel level) { 146 g_logLevel = level; 147 } 148 149 static void trace(string file = __FILE__, size_t line = __LINE__, 150 string func = __FUNCTION__, A...)(lazy A args) nothrow { 151 writeFormatColor(LogLevel.Trace, layout!(file, line, func)(logFormat(args), traceLevel)); 152 } 153 154 static void tracef(string file = __FILE__, size_t line = __LINE__, 155 string func = __FUNCTION__, A...)(lazy A args) nothrow { 156 writeFormatColor(LogLevel.Trace, layout!(file, line, func)(logFormatf(args), traceLevel)); 157 } 158 159 static void info(string file = __FILE__, size_t line = __LINE__, 160 string func = __FUNCTION__, A...)(lazy A args) nothrow { 161 writeFormatColor(LogLevel.Info, layout!(file, line, func)(logFormat(args), infoLevel)); 162 } 163 164 static void infof(string file = __FILE__, size_t line = __LINE__, 165 string func = __FUNCTION__, A...)(lazy A args) nothrow { 166 writeFormatColor(LogLevel.Info, layout!(file, line, func)(logFormatf(args), infoLevel)); 167 } 168 169 static void warning(string file = __FILE__, size_t line = __LINE__, 170 string func = __FUNCTION__, A...)(lazy A args) nothrow { 171 writeFormatColor(LogLevel.Warning, layout!(file, line, 172 func)(logFormat(args), warningLevel)); 173 } 174 175 static void warningf(string file = __FILE__, size_t line = __LINE__, 176 string func = __FUNCTION__, A...)(lazy A args) nothrow { 177 writeFormatColor(LogLevel.Warning, layout!(file, line, 178 func)(logFormatf(args), warningLevel)); 179 } 180 181 static void error(string file = __FILE__, size_t line = __LINE__, 182 string func = __FUNCTION__, A...)(lazy A args) nothrow { 183 writeFormatColor(LogLevel.Error, layout!(file, line, func)(logFormat(args), errorLevel)); 184 } 185 186 static void errorf(string file = __FILE__, size_t line = __LINE__, 187 string func = __FUNCTION__, A...)(lazy A args) nothrow { 188 writeFormatColor(LogLevel.Error, layout!(file, line, func)(logFormatf(args), errorLevel)); 189 } 190 191 static void fatal(string file = __FILE__, size_t line = __LINE__, 192 string func = __FUNCTION__, A...)(lazy A args) nothrow { 193 writeFormatColor(LogLevel.Fatal, layout!(file, line, func)(logFormat(args), fatalLevel)); 194 } 195 196 static void fatalf(string file = __FILE__, size_t line = __LINE__, 197 string func = __FUNCTION__, A...)(lazy A args) nothrow { 198 writeFormatColor(LogLevel.Fatal, layout!(file, line, func)(logFormatf(args), fatalLevel)); 199 } 200 201 private static string logFormatf(A...)(A args) { 202 Appender!string buffer; 203 formattedWrite(buffer, args); 204 return buffer.data; 205 } 206 207 private static string logFormat(A...)(A args) { 208 auto w = appender!string(); 209 foreach (arg; args) { 210 alias A = typeof(arg); 211 static if (isAggregateType!A || is(A == enum)) { 212 import std.format : formattedWrite; 213 214 formattedWrite(w, "%s", arg); 215 } else static if (isSomeString!A) { 216 put(w, arg); 217 } else static if (isIntegral!A) { 218 import std.conv : toTextRange; 219 220 toTextRange(arg, w); 221 } else static if (isBoolean!A) { 222 put(w, arg ? "true" : "false"); 223 } else static if (isSomeChar!A) { 224 put(w, arg); 225 } else { 226 import std.format : formattedWrite; 227 228 // Most general case 229 formattedWrite(w, "%s", arg); 230 } 231 } 232 return w.data; 233 } 234 235 private static string layout(string file = __FILE__, size_t line = __LINE__, 236 string func = __FUNCTION__)(string msg, string level) { 237 enum lineNum = std.conv.to!string(line); 238 string time_prior = Clock.currTime.toString(); 239 string tid = std.conv.to!string(cast(size_t)getTid()); 240 241 // writeln("fullname: ",func); 242 string fun = func; 243 ptrdiff_t index = lastIndexOf(func, '.'); 244 if (index != -1) { 245 if (func[index - 1] != ')') { 246 ptrdiff_t idx = lastIndexOf(func, '.', index); 247 if (idx != -1) 248 index = idx; 249 } 250 fun = func[index + 1 .. $]; 251 } 252 253 LogLayoutHandler handler = layoutHandler(); 254 if(handler !is null) { 255 return handler(time_prior, tid, level, fun, msg, file, line); 256 } else { 257 return time_prior ~ " | " ~ tid ~ " | " ~ level ~ " | " ~ fun ~ " | " ~ msg 258 ~ " | " ~ file ~ ":" ~ lineNum; 259 } 260 } 261 262 // private static string defaultLayout(string context, string msg, string level) 263 // { 264 // string time_prior = Clock.currTime.toString(); 265 // string tid = std.conv.to!string(getTid()); 266 267 // return time_prior ~ " | " ~ tid ~ " | " ~ level ~ context ~ msg; 268 // } 269 270 static string toString(LogLevel level) nothrow { 271 string r; 272 final switch (level) with (LogLevel) { 273 case Trace: 274 r = "trace"; 275 break; 276 case Info: 277 r = "info"; 278 break; 279 case Warning: 280 r = "warning"; 281 break; 282 case Error: 283 r = "error"; 284 break; 285 case Fatal: 286 r = "fatal"; 287 break; 288 case Off: 289 r = "off"; 290 break; 291 } 292 return r; 293 } 294 295 private static void writeFormatColor(LogLevel level, lazy string msg) nothrow { 296 if (level < g_logLevel) 297 return; 298 299 version (Posix) { 300 version (Android) { 301 string prior_color; 302 android_LogPriority logPrioity = android_LogPriority.ANDROID_LOG_INFO; 303 switch (level) with (LogLevel) { 304 case Error: 305 case Fatal: 306 prior_color = PRINT_COLOR_RED; 307 logPrioity = android_LogPriority.ANDROID_LOG_ERROR; 308 break; 309 case Warning: 310 prior_color = PRINT_COLOR_YELLOW; 311 logPrioity = android_LogPriority.ANDROID_LOG_WARN; 312 break; 313 case Info: 314 prior_color = PRINT_COLOR_GREEN; 315 break; 316 default: 317 prior_color = string.init; 318 } 319 320 try { 321 __android_log_write(logPrioity, 322 LOG_TAG, toStringz(prior_color ~ msg ~ PRINT_COLOR_NONE)); 323 } catch(Exception ex) { 324 collectException( { 325 write(PRINT_COLOR_RED); 326 write(ex); 327 writeln(PRINT_COLOR_NONE); 328 }()); 329 } 330 331 } else { 332 string prior_color; 333 switch (level) with (LogLevel) { 334 case Error: 335 case Fatal: 336 prior_color = PRINT_COLOR_RED; 337 break; 338 case Warning: 339 prior_color = PRINT_COLOR_YELLOW; 340 break; 341 case Info: 342 prior_color = PRINT_COLOR_GREEN; 343 break; 344 default: 345 prior_color = string.init; 346 } 347 try { 348 writeln(prior_color ~ msg ~ PRINT_COLOR_NONE); 349 } catch(Exception ex) { 350 collectException( { 351 write(PRINT_COLOR_RED); 352 write(ex); 353 writeln(PRINT_COLOR_NONE); 354 }()); 355 } 356 } 357 358 } else version (Windows) { 359 enum defaultColor = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE; 360 361 ushort color; 362 switch (level) with (LogLevel) { 363 case Error: 364 case Fatal: 365 color = FOREGROUND_RED; 366 break; 367 case Warning: 368 color = FOREGROUND_GREEN | FOREGROUND_RED; 369 break; 370 case Info: 371 color = FOREGROUND_GREEN; 372 break; 373 default: 374 color = defaultColor; 375 } 376 377 ConsoleHelper.writeWithAttribute(msg, color); 378 } else { 379 assert(false, "Unsupported OS."); 380 } 381 } 382 } 383 384 385 void setLogLayout(LogLayoutHandler handler) { 386 _layoutHandler = handler; 387 } 388 389 390 alias trace = ConsoleLogger.trace; 391 alias tracef = ConsoleLogger.tracef; 392 alias info = ConsoleLogger.info; 393 alias infof = ConsoleLogger.infof; 394 alias warning = ConsoleLogger.warning; 395 alias warningf = ConsoleLogger.warningf; 396 alias error = ConsoleLogger.error; 397 alias errorf = ConsoleLogger.errorf; 398 // alias critical = ConsoleLogger.critical; 399 // alias criticalf = ConsoleLogger.criticalf; 400 401 alias logDebug = trace; 402 alias logDebugf = tracef; 403 alias logInfo = info; 404 alias logInfof = infof; 405 alias logWarning = warning; 406 alias logWarningf = warningf; 407 alias logError = error; 408 alias logErrorf = errorf;