1 module mecca.log; 2 3 // Licensed under the Boost license. Full copyright information in the AUTHORS file 4 5 version(MeccaAlternateLogger) { 6 mixin("public import " ~ import("MeccaAlternateLogger.txt") ~ ";"); 7 } else { 8 import std.stdio; 9 import std..string; 10 import std.datetime; 11 import mecca.lib.reflection: as; 12 import mecca.lib.console; 13 import mecca.lib.exception: extractStack, DefaultTraceInfoABI; 14 import mecca.log.impl; 15 16 /// Report whether the loggin infra has been initialized 17 enum loggingInitialized = true; 18 19 /** 20 * UDA for disabling auto tracing of a specific function 21 * 22 * Decorate functions that should not be traced with @notrace. 23 */ 24 enum notrace = "notrace"; 25 26 // All implementations must define this enum to say whether logs sent find their way to the console 27 enum LogToConsole = true; 28 29 // UDA for modifying a variable formatting (currently ignored) 30 struct FMT { 31 immutable string __log_customFormatString; 32 } 33 34 /* 35 These functions are mostly placeholders. Since we'd sometimes want to replace them with functions that 36 do binary logging, the format is part of the function's template. 37 */ 38 39 enum LEVEL_DEBUG = FG.grey; 40 enum LEVEL_INFO = FG.green; 41 enum LEVEL_WARN = FG.iyellow; 42 enum LEVEL_ERROR = FG.ired; 43 enum LEVEL_EXCEPTION = FG.iwhite | BG.red; 44 enum LEVEL_META = FG.iwhite | BG.magenta; 45 enum LEVEL_BT = FG.red; 46 47 private void internalLogOutput(ANSI level, T...)(string fmt, string file, size_t line, T args) nothrow @trusted @nogc { 48 as!"nothrow @nogc"({ 49 auto t = Clock.currTime(); 50 auto loc = "%s:%s".format(file.split("/")[$-1], line); 51 writefln(FG.grey("%02d:%02d:%02d.%03d") ~ "\u2502" ~ FG.cyan("%s") ~ "\u2502" ~ FG.grey("%-20s") ~ "\u2502" ~ level(fmt), 52 t.hour, t.minute, t.second, t.fracSecs.total!"msecs", logSource, loc[$ > 20 ? $ - 20 : 0 .. $], args); 53 }); 54 } 55 56 void DEBUG(string fmt, string file = __FILE_FULL_PATH__, string mod = __MODULE__, int line = __LINE__, T...)(T args) nothrow @safe @nogc { 57 internalLogOutput!LEVEL_DEBUG(fmt, file, line, args); 58 } 59 60 void INFO(string fmt, string file = __FILE_FULL_PATH__, string mod = __MODULE__, int line = __LINE__, T...)(T args) nothrow @safe @nogc { 61 internalLogOutput!LEVEL_INFO(fmt, file, line, args); 62 } 63 64 void WARN(string fmt, string file = __FILE_FULL_PATH__, string mod = __MODULE__, int line = __LINE__, T...)(T args) nothrow @safe @nogc { 65 internalLogOutput!LEVEL_WARN(fmt, file, line, args); 66 } 67 68 void ERROR(string fmt, string file = __FILE_FULL_PATH__, string mod = __MODULE__, int line = __LINE__, T...)(T args) nothrow @safe @nogc { 69 internalLogOutput!LEVEL_ERROR(fmt, file, line, args); 70 } 71 72 void LOG_EXCEPTION(Throwable ex) nothrow @trusted @nogc { 73 internalLogOutput!LEVEL_EXCEPTION("%s@%s(%s): %s", ex.file, ex.line, typeid(ex).name, ex.file, ex.line, ex.msg); 74 if (ex.info) { 75 foreach( ptr; DefaultTraceInfoABI.extract(ex.info).frames ) { 76 as!"nothrow @nogc"({ writefln("\t0x%x", ptr); }); 77 } 78 } 79 } 80 81 void META(string fmt, string file = __FILE_FULL_PATH__, string mod = __MODULE__, int line = __LINE__, T...)(T args) nothrow @safe @nogc { 82 internalLogOutput!LEVEL_META(fmt, file, line, args); 83 } 84 85 void LOG_TRACEBACK(void*[] bt, string msg, string file = __FILE_FULL_PATH__, size_t line = __LINE__) nothrow @trusted @nogc 86 { 87 internalLogOutput!LEVEL_BT(msg, file, line); 88 foreach( ptr; bt ) { 89 as!"nothrow @nogc"({ writefln("\t0x%x", ptr); }); 90 } 91 } 92 93 /* thread local */ static void*[128] btBuffer = void; 94 95 void dumpStackTrace(string msg = "Backtrace:", string file = __FILE_FULL_PATH__, size_t line = __LINE__) nothrow @trusted @nogc { 96 auto bt = extractStack(btBuffer); 97 LOG_TRACEBACK(bt, msg, file, line); 98 } 99 100 void flushLog() nothrow @trusted @nogc { 101 as!"nothrow @nogc"({ stdout.flush(); }); 102 } 103 104 unittest { 105 DEBUG!"Just some debug info %s"(42); 106 INFO!"Event worthy of run time mention %s"(100); 107 WARN!"Take heed, %s traveller, for something strange is a%s"("weary", "foot"); 108 ERROR!"2b || !2b == %s"('?'); 109 dumpStackTrace("Where am I?"); 110 try { 111 throw new Exception("inception"); 112 } 113 catch (Exception ex) { 114 LOG_EXCEPTION(ex); 115 } 116 } 117 }