1 module des.util.logsys.rule;
2 
3 import std.algorithm : min;
4 import std..string : split, join;
5 
6 import des.util.logsys.base;
7 
8 /// store rules for logging
9 package 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 
19 public:
20 
21     ///
22     this( shared Rule parent = null )
23     {
24         this.parent = parent;
25         if( parent )
26             this.level = parent.level;
27     }
28 
29     ///
30     @property bool useMinimal() const
31     {
32         if( parent !is null )
33             return parent.useMinimal();
34         else return use_minimal;
35     }
36 
37     /// setting allowed level for emitter (create new inner Rule), if emitter is "" sets self level
38     void setLevel( LogLevel lvl, string emitter="" )
39     {
40         auto addr = splitAddress( emitter );
41         if( addr[0].length == 0 ) { level = lvl; return; }
42         auto iname = addr[0];
43         if( iname !in inner ) inner[iname] = new shared Rule(this);
44         inner[iname].setLevel( lvl, addr[1] );
45     }
46 
47     /// if emitter is "" returns self level
48     LogLevel allowedLevel( string emitter="" )
49     {
50         auto addr = splitAddress( emitter );
51         if( addr[0].length == 0 ) return level;
52         auto iname = addr[0];
53         if( iname !in inner ) return level;
54         if( useMinimal )
55             return min( level, inner[iname].allowedLevel( addr[1] ) );
56         else
57             return inner[iname].allowedLevel( addr[1] );
58     }
59 
60     string print( string offset="" ) const
61     {
62         string ret = format( "%s", level );
63         foreach( key, val; inner )
64             ret ~= format( "\n%s%s : %s", offset, key, val.print( offset ~ mlt(" ",key.length) ) );
65         return ret;
66     }
67 
68 protected:
69 
70     ///
71     static string[2] splitAddress( string emitter )
72     {
73         auto addr = emitter.split(".");
74         if( addr.length == 0 ) return ["",""];
75         if( addr.length == 1 ) return [addr[0],""];
76         
77         return [ addr[0], addr[1..$].join(".") ];
78     }
79 }
80 
81 private T[] mlt(T)( T[] val, size_t cnt ) nothrow
82 {
83     T[] buf;
84     foreach( i; 0 .. cnt ) buf ~= val;
85     return buf;
86 }
87 
88 unittest { assert( "    ", mlt( " ", 4 ) ); }
89 
90 ///
91 unittest
92 {
93     auto r = new shared Rule;
94 
95     r.setLevel( LogLevel.INFO );
96     r.setLevel( LogLevel.TRACE, "des.gl" );
97     r.setLevel( LogLevel.WARN, "des" );
98 
99     assert( r.allowedLevel() == LogLevel.INFO );
100     assert( r.allowedLevel("des") == LogLevel.WARN );
101     assert( r.allowedLevel("des.gl") == LogLevel.WARN );
102 
103     r.use_minimal = false;
104 
105     assert( r.allowedLevel() == LogLevel.INFO );
106     assert( r.allowedLevel("des") == LogLevel.WARN );
107     assert( r.allowedLevel("des.gl") == LogLevel.TRACE );
108 }