1 module des.log.logcls; 2 3 import std.traits : EnumMembers; 4 import std.string : toLower, format, split; 5 import std.stdio : stderr; 6 7 import des.log.base; 8 import des.log.output; 9 import des.log.rule; 10 11 /// base logger class 12 class Logger 13 { 14 /// 15 mixin( getLogFunctions ); 16 17 /// 18 static shared(OutputHandler) output() @property 19 out(o) { assert( o !is null, "log output handler is null" ); } 20 body { return g_output; } 21 22 /// 23 static shared(Rule) rule() @property 24 out(o) { assert( o !is null, "log rule handler is null" ); } 25 body { return g_rule; } 26 27 protected: 28 29 /// check log message level allowed with current rules for emmiter 30 final void procMessage( in LogMessage lm ) const nothrow 31 { 32 try if( rule.allowedLevel( lm.emitter ) >= lm.level ) writeLog( lm ); 33 catch( Exception e ) writeLogFailPrint(e); 34 } 35 36 /// exception processing 37 void writeLogFailPrint( Exception e ) const nothrow 38 { 39 try stderr.writefln( "[INTERNAL LOG EXCEPTION]: %s", e ); 40 catch(Exception){} 41 } 42 43 /// write log to logoutput 44 void writeLog( in LogMessage lm ) const 45 { output.write( chooseOutputName(lm), lm ); } 46 47 /// logger can chouse output name 48 string chooseOutputName( in LogMessage lvl ) const 49 { return OutputHandler.console_name; } 50 51 /// transform caller func name to emitter name 52 string getEmitterName( string func_name ) const nothrow 53 in{ assert( func_name.length ); } 54 out(ret){ assert( ret.length ); } 55 body { return func_name; } 56 57 private static string getLogFunctions() @property 58 { 59 string fnc = q{ 60 void %1$s( string fnc=__FUNCTION__, Args... )( Args args ) const nothrow 61 { 62 version(des_log_onlyerror) 63 { 64 static if( LogMessage.Level.%2$s <= LogMessage.Level.ERROR ) 65 procMessage( LogMessage( getEmitterName(fnc), __ts, LogMessage.Level.%2$s, ntFormat(args) ) ); 66 } 67 else procMessage( LogMessage( getEmitterName(fnc), __ts, LogMessage.Level.%2$s, ntFormat(args) ) ); 68 } 69 }; 70 71 string ret; 72 foreach( lvl; [EnumMembers!(LogMessage.Level)] ) 73 { 74 auto slvl = to!string(lvl); 75 auto fname = fixReservedName( slvl.toLower ); 76 ret ~= format( fnc, fname, slvl ); 77 } 78 return ret; 79 } 80 } 81 82 /// logger for class instances 83 class InstanceLogger : Logger 84 { 85 protected: 86 string class_name; /// 87 string inst_name; /// 88 89 public: 90 91 /// 92 this( Object obj, string inst="" ) 93 { 94 class_name = typeid(obj).name; 95 inst_name = inst; 96 } 97 98 /// 99 this( string obj, string inst="" ) 100 { 101 class_name = obj; 102 inst_name = inst; 103 } 104 105 nothrow @property 106 { 107 /// 108 void instance( string i ) { inst_name = i; } 109 110 /// 111 string instance() const { return inst_name; } 112 } 113 114 protected: 115 116 /// Returns: module + class_name + inst_name (if it exists) 117 override string getEmitterName( string name ) const nothrow 118 { 119 try return fullEmitterName ~ "." ~ name.split(".")[$-1]; 120 catch(Exception e) return fullEmitterName; 121 } 122 123 string fullEmitterName() const nothrow @property 124 { return class_name ~ (inst_name.length?".["~inst_name~"]":""); } 125 } 126 127 /// logger for class instances with extended emitter name 128 class InstanceFullLogger : InstanceLogger 129 { 130 /// 131 this( Object obj, string inst="" ) { super(obj,inst); } 132 133 /// 134 this( string obj, string inst="" ) { super(obj,inst); } 135 136 protected: 137 138 /// Returns: module + class_name + inst_name (if it exists) + call function name 139 override string getEmitterName( string name ) const nothrow 140 { return fullEmitterName ~ ".[" ~ name ~ "]"; } 141 }