1 // Written in the D programming language. 2 /++ 3 + Authors: KanzakiKino 4 + Copyright: KanzakiKino 2018 5 + License: LGPL-3.0 6 ++/ 7 module w4d.log; 8 import w4d.exception; 9 import std.conv, 10 std.format, 11 std.stdio, 12 std..string; 13 14 /// An enum of log levels. 15 /// The uint value is priority of the level. 16 enum LogLevel : uint 17 { 18 Trace = 0, 19 Info, 20 Warn, 21 Error, 22 Fatal, 23 } 24 25 /// Converts LogLevel to string. 26 @property toString ( LogLevel lv, bool colored ) 27 { 28 string result = ""; 29 final switch ( lv ) with ( LogLevel ) 30 { 31 case Trace: result = "trace"; 32 break; 33 case Info : result = "info"; 34 break; 35 case Warn : result = "warn"; 36 break; 37 case Error: result = "error"; 38 break; 39 case Fatal: result = "fatal"; 40 break; 41 } 42 if ( colored ) { 43 result = lv.toColorCode ~ result ~ "\x1b[39m"; 44 } 45 return result; 46 } 47 /// Converts LogLevel to color code in terminal. 48 @property toColorCode ( LogLevel lv ) 49 { 50 final switch ( lv ) with ( LogLevel ) 51 { 52 case Trace: return "\x1b[37m"; // white 53 case Info : return "\x1b[36m"; // cyan 54 case Warn : return "\x1b[33m"; // yellow 55 case Error: return "\x1b[35m"; // magenta 56 case Fatal: return "\x1b[31m"; // red 57 } 58 } 59 60 /// A logger used in w4d library. 61 class W4dLogger 62 { 63 protected __gshared W4dLogger _instance; 64 /// 65 shared static this () 66 { 67 new W4dLogger; 68 } 69 /// An unique instance of W4dLogger. 70 static @property instance () 71 { 72 enforce( _instance, "W4dLogger isn't created yet." ); 73 return _instance; 74 } 75 76 protected File _output; 77 protected bool _colored; 78 79 protected LogLevel _outputThreshold; 80 protected LogLevel _throwThreshold; 81 82 /// 83 this () 84 { 85 enforce( !_instance, "W4dLogger is created already." ); 86 _instance = this; 87 88 _output = stdout; 89 _colored = true; 90 91 _outputThreshold = LogLevel.Trace; 92 _throwThreshold = LogLevel.Fatal; 93 94 trace( "W4dLogger has been initialized." ); 95 } 96 ~this () 97 { 98 trace( "W4dLogger has been deleted." ); 99 } 100 101 /// Changes output file. Specify stdout to output to the terminal. 102 /// When colored is true, logs will be colored for the terminal. 103 void setOutputFile ( File f, bool colored = false ) 104 { 105 _output = f; 106 _colored = colored; 107 } 108 /// Changes threshold levels for handling logs. 109 void setThreshold ( LogLevel out_, LogLevel throw_ ) 110 { 111 _outputThreshold = out_; 112 _throwThreshold = throw_; 113 } 114 115 protected string formatLog ( LogLevel lv, string text, 116 string file, size_t line, string func ) 117 { 118 return ("[%s] %s\n"~ 119 " %s at %d (%s)"). 120 format( lv.toString(_colored), text, file, line, func ); 121 } 122 123 protected void writeLog 124 ( string file = __FILE__, size_t line = __LINE__, string func = __FUNCTION__, Args... ) 125 ( LogLevel lv, Args args ) 126 { 127 if ( lv < _outputThreshold ) return; 128 129 string text; 130 foreach ( arg; args ) { 131 text ~= arg.to!string ~ " "; 132 } 133 text = text.chop; 134 135 auto formattedText = formatLog( 136 lv, text, file, line, func ); 137 _output.writeln( formattedText ); 138 139 if ( lv >= _throwThreshold ) { 140 auto msg = "%s (%s)".format( text, func ); 141 throw new W4dException( msg, file, line ); 142 } 143 } 144 145 /// Makes new trace log. 146 void trace 147 ( string file = __FILE__, size_t line = __LINE__, string func = __FUNCTION__, Args... ) 148 ( Args args ) 149 { 150 writeLog!( file, line, func )( LogLevel.Trace, args ); 151 } 152 /// Makes new info log. 153 void info 154 ( string file = __FILE__, size_t line = __LINE__, string func = __FUNCTION__, Args... ) 155 ( Args args ) 156 { 157 writeLog!( file, line, func )( LogLevel.Info, args ); 158 } 159 /// Makes new warning log. 160 void warn 161 ( string file = __FILE__, size_t line = __LINE__, string func = __FUNCTION__, Args... ) 162 ( Args args ) 163 { 164 writeLog!( file, line, func )( LogLevel.Warn, args ); 165 } 166 /// Makes new error log. 167 void error 168 ( string file = __FILE__, size_t line = __LINE__, string func = __FUNCTION__, Args... ) 169 ( Args args ) 170 { 171 writeLog!( file, line, func )( LogLevel.Error, args ); 172 } 173 /// Makes new fatal log. 174 void fatal 175 ( string file = __FILE__, size_t line = __LINE__, string func = __FUNCTION__, Args... ) 176 ( Args args ) 177 { 178 writeLog!( file, line, func )( LogLevel.Fatal, args ); 179 } 180 } 181 182 /// Alias for the instance of W4dLogger. 183 alias Log = W4dLogger.instance;