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 }