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;