1 module des.log.rule; 2 3 import std.algorithm : min; 4 import std..string : split, join; 5 6 import des.log.base; 7 8 /// store rules for logging 9 synchronized class Rule 10 { 11 package: 12 shared Rule parent; /// 13 14 LogLevel level = LogLevel.ERROR; /// 15 shared Rule[string] inner; /// 16 17 bool use_minimal = true; 18 bool only_register = false; 19 bool registred = false; 20 21 public: 22 23 /// 24 this( shared Rule parent = null ) 25 { 26 this.parent = parent; 27 if( parent ) this.level = parent.level; 28 } 29 30 @property 31 { 32 /// 33 bool useMinimal() const 34 { 35 if( parent !is null ) return parent.useMinimal; 36 else return use_minimal; 37 } 38 39 /// 40 bool useMinimal( bool v ) 41 { 42 if( parent !is null ) return parent.useMinimal = v; 43 else return use_minimal = v; 44 } 45 46 /// 47 bool onlyRegister() const 48 { 49 if( parent !is null ) return parent.onlyRegister; 50 else return only_register; 51 } 52 53 /// 54 bool onlyRegister( bool v ) 55 { 56 if( parent !is null ) return parent.onlyRegister = v; 57 else return only_register = v; 58 } 59 } 60 61 /// setting allowed level for emitter (create new inner Rule), if emitter is "" sets self level 62 void setLevel( LogLevel lvl, string emitter="" ) 63 { setLevelImpl( lvl, emitter.split(".") ); } 64 65 /// if emitter is "" returns self level 66 LogLevel allowedLevel( string emitter="" ) const 67 { return allowedLevelImpl( emitter.split(".") ); } 68 69 /// test is message allowed for this rule 70 bool isAllowed( in LogMessage lm ) const 71 { return allowedLevel( lm.emitter ) >= lm.level; } 72 73 /// return string what represent of rule structure 74 string strRepresent() const { return strRepresentImpl(); } 75 76 protected: 77 78 void setLevelImpl( LogLevel lvl, string[] emitter ) 79 { 80 if( emitter.length == 0 || emitter[0].length == 0 ) 81 { 82 level = lvl; 83 registred = true; 84 return; 85 } 86 87 auto iname = emitter[0]; 88 89 if( iname !in inner ) 90 inner[iname] = new shared Rule(this); 91 92 inner[iname].setLevelImpl( lvl, emitter.length > 1 ? emitter[1..$] : [] ); 93 } 94 95 /// if emitter is "" returns self level 96 LogLevel allowedLevelImpl( string[] emitter ) const 97 { 98 if( emitter.length == 0 || emitter[0].length == 0 ) 99 return level; 100 101 auto iname = emitter[0]; 102 103 if( iname !in inner ) 104 { 105 if( onlyRegister ) 106 { 107 if( !(registred && parent !is null) ) 108 return LogLevel.OFF; 109 else 110 return level; 111 } 112 else return level; 113 } 114 115 auto childnames = emitter.length > 1 ? emitter[1..$] : []; 116 117 if( useMinimal ) 118 return min( level, inner[iname].allowedLevelImpl( childnames ) ); 119 else 120 return inner[iname].allowedLevelImpl( childnames ); 121 } 122 123 string strRepresentImpl( string offset="", bool first=true ) const 124 { 125 string ret = format( "%s%s", level, registred ? " [reg]" : "" ); 126 if( first ) 127 ret ~= format( "%s%s", useMinimal ? " use minimal" : "", 128 onlyRegister ? " only register" : "" ); 129 foreach( key, val; inner ) 130 ret ~= format( "\n%s%s : %s", offset, key, 131 val.strRepresentImpl( offset ~ mlt(" ",key.length), false ) ); 132 return ret; 133 } 134 } 135 136 private T[] mlt(T)( T[] val, size_t cnt ) nothrow 137 { 138 T[] buf; 139 foreach( i; 0 .. cnt ) buf ~= val; 140 return buf; 141 } 142 143 unittest { assert( " ", mlt( " ", 4 ) ); } 144 145 /// 146 unittest 147 { 148 auto r = new shared Rule; 149 150 r.setLevel( LogLevel.INFO ); 151 r.setLevel( LogLevel.TRACE, "des.gl" ); 152 r.setLevel( LogLevel.WARN, "des" ); 153 154 assert( r.allowedLevel() == LogLevel.INFO ); 155 assert( r.allowedLevel("des") == LogLevel.WARN ); 156 assert( r.allowedLevel("des.gl") == LogLevel.WARN ); 157 158 r.use_minimal = false; 159 160 assert( r.allowedLevel() == LogLevel.INFO ); 161 assert( r.allowedLevel("des") == LogLevel.WARN ); 162 assert( r.allowedLevel("des.gl") == LogLevel.TRACE ); 163 }