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 }