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