1 /**
2  * Logger module.
3  *
4  * License:
5  *     MIT. See LICENSE for full details.
6  */
7 module tkd.interpreter.logger;
8 
9 /**
10  * Imports.
11  */
12 import std.datetime;
13 import std.process;
14 import std.stdio;
15 import std.string;
16 
17 /**
18  * A simple class to provide logging support.
19  */
20 class Logger
21 {
22 	/**
23 	 * Level of importance of the text to write to the logger.
24 	 */
25 	private enum Level
26 	{
27 		/**
28 		 * The eval level is for evaluated commands.
29 		 */
30 		eval,
31 
32 		/**
33 		 * The information level used for info messages.
34 		 */
35 		information,
36 
37 		/**
38 		 * The warning level used for warning messages.
39 		 */
40 		warning,
41 
42 		/**
43 		 * The error level used for error messages.
44 		 */
45 		error,
46 	}
47 
48 	/**
49 	 * The open log file.
50 	 */
51 	private File _log;
52 
53 	/**
54 	 * Constructor.
55 	 *
56 	 * If a log file is not passed, log instead to stdout.
57 	 *
58 	 * Params:
59 	 *     logFile = The log file for logging.
60 	 */
61 	final public this(string logFile = null) nothrow
62 	{
63 		try
64 		{
65 			if (logFile is null)
66 			{
67 				this._log = stdout;
68 			}
69 			else
70 			{
71 				this._log = File(logFile, "w");
72 			}
73 		}
74 		catch (Exception ex)
75 		{
76 			assert(false, ex.msg);
77 		}
78 	}
79 
80 	/**
81 	 * Get the current timestamp for the log.
82 	 *
83 	 * Returns:
84 	 *     The current timestamp.
85 	 */
86 	final private string getTimestamp() nothrow
87 	{
88 		try
89 		{
90 			auto time = Clock.currTime();
91 			return format("%d/%02d/%02d %d:%02d:%02d", time.year, time.month, time.day, time.hour, time.minute, time.second);
92 		}
93 		catch (Exception ex)
94 		{
95 			assert(false, ex.msg);
96 		}
97 	}
98 
99 	/**
100 	 * Write text to the log.
101 	 *
102 	 * Params:
103 	 *     text = The text to write to the log.
104 	 *     level = The level of the text.
105 	 */
106 	final private void log(A...)(Level level, string text, A args) nothrow
107 	{
108 		string levelText;
109 
110 		switch(level)
111 		{
112 			case Level.eval:
113 				levelText = "EVAL";
114 				break;
115 
116 			case Level.warning:
117 				levelText = "WARN";
118 				break;
119 
120 			case Level.error:
121 				levelText = "ERROR";
122 				break;
123 
124 			default:
125 				levelText = "INFO";
126 				break;
127 		}
128 
129 		try
130 		{
131 			static if (A.length)
132 			{
133 				text = format(text, args);
134 			}
135 
136 			this._log.writefln("%s %s: %s", this.getTimestamp(), levelText, text);
137 			this._log.flush();
138 		}
139 		catch (Exception ex)
140 		{
141 			assert(false, ex.msg);
142 		}
143 	}
144 
145 	/**
146 	 * Write eval text to the log.
147 	 *
148 	 * Params:
149 	 *     text = The format of the text to write to the log.
150 	 *     args = The arguments that the format defines (if any).
151 	 */
152 	final public void eval(A...)(string text, A args) nothrow
153 	{
154 		this.log(Level.eval, text, args);
155 	}
156 
157 	/**
158 	 * Write info text to the log.
159 	 *
160 	 * Params:
161 	 *     text = The format of the text to write to the log.
162 	 *     args = The arguments that the format defines (if any).
163 	 */
164 	final public void info(A...)(string text, A args) nothrow
165 	{
166 		this.log(Level.information, text, args);
167 	}
168 
169 	/**
170 	 * Write warning text to the log.
171 	 *
172 	 * Params:
173 	 *     text = The format of the text to write to the log.
174 	 *     args = The arguments that the format defines (if any).
175 	 */
176 	final public void warning(A...)(string text, A args) nothrow
177 	{
178 		this.log(Level.warning, text, args);
179 	}
180 
181 	/**
182 	 * Write error text to the log.
183 	 *
184 	 * Params:
185 	 *     text = The format of the text to write to the log.
186 	 *     args = The arguments that the format defines (if any).
187 	 */
188 	final public void error(A...)(string text, A args) nothrow
189 	{
190 		this.log(Level.error, text, args);
191 	}
192 
193 }