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.isAllowed(lm) ) 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.writeMessage( chooseOutputName(lm), lm ); } 46 47 /// logger can chouse output name, empty (default) for broadcast 48 string chooseOutputName( in LogMessage lvl ) const { return ""; } 49 50 /// transform caller func name to emitter name 51 string getEmitterName( string func_name ) const nothrow 52 in{ assert( func_name.length ); } 53 out(ret){ assert( ret.length ); } 54 body { return func_name; } 55 56 private static string getLogFunctions() @property 57 { 58 string fnc = q{ 59 void %1$s( string fnc=__FUNCTION__, Args... )( Args args ) const nothrow 60 { 61 version(des_log_onlyerror) 62 { 63 static if( LogMessage.Level.%2$s <= LogMessage.Level.ERROR ) 64 procMessage( LogMessage( getEmitterName(fnc), __ts, LogMessage.Level.%2$s, ntFormat(args) ) ); 65 } 66 else procMessage( LogMessage( getEmitterName(fnc), __ts, LogMessage.Level.%2$s, ntFormat(args) ) ); 67 } 68 }; 69 70 string ret; 71 foreach( lvl; [EnumMembers!(LogMessage.Level)] ) 72 { 73 auto slvl = to!string(lvl); 74 auto fname = fixReservedName( slvl.toLower ); 75 ret ~= format( fnc, fname, slvl ); 76 } 77 return ret; 78 } 79 } 80 81 /// logger for class instances 82 class InstanceLogger : Logger 83 { 84 protected: 85 string class_name; /// 86 string inst_name; /// 87 88 public: 89 90 /// 91 this( Object obj, string inst="" ) 92 { 93 class_name = typeid(obj).name; 94 inst_name = inst; 95 } 96 97 /// 98 this( string obj, string inst="" ) 99 { 100 class_name = obj; 101 inst_name = inst; 102 } 103 104 nothrow @property 105 { 106 /// 107 void instance( string i ) { inst_name = i; } 108 109 /// 110 string instance() const { return inst_name; } 111 } 112 113 protected: 114 115 /// Returns: module + class_name + inst_name (if it exists) 116 override string getEmitterName( string name ) const nothrow 117 { 118 try return fullEmitterName ~ "." ~ name.split(".")[$-1]; 119 catch(Exception e) return fullEmitterName; 120 } 121 122 string fullEmitterName() const nothrow @property 123 { return class_name ~ (inst_name.length?".["~inst_name~"]":""); } 124 } 125 126 /// logger for class instances with extended emitter name 127 class InstanceFullLogger : InstanceLogger 128 { 129 /// 130 this( Object obj, string inst="" ) { super(obj,inst); } 131 132 /// 133 this( string obj, string inst="" ) { super(obj,inst); } 134 135 protected: 136 137 /// Returns: module + class_name + inst_name (if it exists) + call function name 138 override string getEmitterName( string name ) const nothrow 139 { return fullEmitterName ~ ".[" ~ name ~ "]"; } 140 }