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