1 module des.util.logsys.logcls;
2 
3 import std.traits : EnumMembers;
4 import std..string : toLower, format, split;
5 import std.stdio : stderr;
6 
7 import des.util.logsys.base;
8 import des.util.logsys.output;
9 
10 /// base logger class
11 class Logger
12 {
13     ///
14     mixin( getLogFunctions );
15 
16 protected:
17 
18     /// check log message level allowed with current rules for emmiter
19     final void procMessage( in LogMessage lm ) const nothrow
20     {
21         try if( logrule.allowedLevel( lm.emitter ) >= lm.level ) writeLog( lm );
22         catch( Exception e ) writeLogFailPrint(e);
23     }
24 
25     /// exception processing
26     void writeLogFailPrint( Exception e ) const nothrow
27     {
28         try stderr.writefln( "[INTERNAL LOG EXCEPTION]: %s", e );
29         catch(Exception){}
30     }
31 
32     /// write log to logoutput
33     void writeLog( in LogMessage lm ) const
34     { logoutput( chooseOutputName(lm), lm ); }
35 
36     /// logger can chouse output name
37     string chooseOutputName( in LogMessage lvl ) const
38     { return LogOutputHandler.console_name; }
39 
40     /// transform caller func name to emitter name
41     string getEmitterName( string func_name ) const nothrow
42     in{ assert( func_name.length ); }
43     out(ret){ assert( ret.length ); }
44     body { return func_name; }
45 
46     private static string getLogFunctions() @property
47     {
48         string fnc = `
49         void %1$s( string fnc=__FUNCTION__, Args... )( Args args ) const nothrow
50         {
51             version(logonlyerror)
52             {
53                 static if( LogMessage.Level.%2$s <= LogMessage.Level.ERROR )
54                     procMessage( LogMessage( getEmitterName(fnc), __ts, LogMessage.Level.%2$s, ntFormat(args) ) );
55             }
56             else procMessage( LogMessage( getEmitterName(fnc), __ts, LogMessage.Level.%2$s, ntFormat(args) ) );
57         }
58         `;
59 
60         string ret;
61         foreach( lvl; [EnumMembers!(LogMessage.Level)] )
62         {
63             auto slvl = to!string(lvl);
64             auto fname = checkReservedName( slvl.toLower );
65             ret ~= format( fnc, fname, slvl );
66         }
67         return ret;
68     }
69 }
70 
71 /// logger for class instances
72 class InstanceLogger : Logger
73 {
74 protected:
75     string class_name; ///
76     string inst_name; ///
77 
78 public:
79 
80     ///
81     this( Object obj, string inst="" )
82     {
83         class_name = typeid(obj).name;
84         inst_name = inst;
85     }
86 
87     ///
88     this( string obj, string inst="" )
89     {
90         class_name = obj;
91         inst_name = inst;
92     }
93 
94     nothrow @property
95     {
96         ///
97         void instance( string i ) { inst_name = i; }
98 
99         ///
100         string instance() const { return inst_name; }
101     }
102 
103 protected:
104 
105     /// Returns: module + class_name + inst_name (if it exists)
106     override string getEmitterName( string name ) const nothrow
107     {
108         try return fullEmitterName ~ "." ~ name.split(".")[$-1];
109         catch(Exception e) return fullEmitterName;
110     }
111 
112     string fullEmitterName() const nothrow @property
113     { return class_name ~ (inst_name.length?".["~inst_name~"]":""); }
114 }
115 
116 /// logger for class instances with extended emitter name
117 class InstanceFullLogger : InstanceLogger
118 {
119     ///
120     this( Object obj, string inst="" ) { super(obj,inst); }
121 
122     ///
123     this( string obj, string inst="" ) { super(obj,inst); }
124 
125 protected:
126 
127     /// Returns: module + class_name + inst_name (if it exists) + call function name
128     override string getEmitterName( string name ) const nothrow
129     { return fullEmitterName ~ ".[" ~ name ~ "]"; }
130 }