1 /**
2  * Copyright:       Copyright (C) 2018 Gabriel Gheorghe, All Rights Reserved
3  * Authors:         $(Gabriel Gheorghe)
4  * License:         $(LINK2 https://www.gnu.org/licenses/gpl-3.0.txt, GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007)
5  * Source:          $(LINK2 https://github.com/GabyForceQ/LibertyEngine/blob/master/source/liberty/logger/impl.d)
6  * Documentation:
7  * Coverage:
8  *
9  * TODO:
10  *  - Add 'current platform' on log message.
11 **/
12 module liberty.logger.impl;
13 
14 import std.stdio : writeln, File;
15 import std.datetime.systime : SysTime, Clock;
16 import std.array : split;
17 
18 import liberty.core.engine;
19 import liberty.logger.constants;
20 
21 /**
22  * Logger class is used for logging a message.
23  * You can log a message to the system console or to a file: "logs.txt".
24  * You can change the log file name.
25  * You can activate or deactivate logger any time.
26 **/
27 final abstract class Logger {
28   private {
29     static File logFile;
30     
31     version (Win32)
32       static string platformName = " [Win_x86]";
33     else version (Win64)
34       static string platformName = " [Win_x64]";
35   }
36 
37   /**
38    *
39   **/
40   static void initialize() {
41     logFile = File(logFileName, "a");
42   }
43 
44   /**
45    *
46   **/
47   static void deinitialize() {
48     logFile.close();
49   }
50   
51   /**
52    * Set false if you don't want logger to run.
53   **/
54   static bool isActive = true;
55   
56   /**
57    * Log file name.
58   **/
59   static string logFileName = "logs.txt";
60 
61   /**
62    * Log an information message. 
63    * It starts with the current time + " -> LOG_INFO: "
64    * Params:
65    *      message = the information message
66    *      obj = current class reference, mostly you pass 'this'
67   **/
68   static void info(string message, string objectName, bool onlyToConsole = false) {
69     log(LogType.Info, objectName ~ " -> " ~ message, onlyToConsole);
70   }
71   
72   /**
73    * Log a warning message. 
74    * It starts with the current time + " -> LOG_WARNING: "
75    * Params:
76    *      message = the warning message
77    *      obj = current class reference, mostly you pass 'this'
78   **/
79   static void warning(string message, string objectName, bool onlyToConsole = false) {
80     log(LogType.Warning, objectName ~ " -> " ~ message, onlyToConsole);
81   }
82 
83   /**
84    * Log an error message.
85    * The type of the error is fatal so the program will exit with a status code of 1.
86    * It starts with the current time + " -> LOG_ERROR: "
87    * Params:
88    *      message = the error message
89    *      obj = current class reference, mostly you pass 'this'
90   **/
91   static void error(string message, string objectName, bool onlyToConsole = false) {
92     log(LogType.Error, objectName ~ " -> " ~ message, onlyToConsole);
93     version (unittest) {}
94     else
95       CoreEngine.forceShutDown(true);
96   }
97 
98   /**
99    * Log an exception message. 
100    * It starts with the current time + " -> LOG_EXCEPTION: "
101    * Params:
102    *      message = the exception message
103   **/
104   static void exception(string message, bool onlyToConsole = false) {
105     log(LogType.Exception, message, onlyToConsole);
106   }
107 
108   /**
109    * Log a debug information message. 
110    * It starts with the current time + " -> LOG_DEBUG: "
111    * Only works in debug mode.
112    * Params:
113    *      message = the debug information message
114    *      obj = current class reference, mostly you pass 'this'
115   **/
116   static void console(string message, string objectName, bool onlyToConsole = false) {
117     log(LogType.Debug, objectName ~ " -> " ~ message, onlyToConsole);
118   }
119 
120   /**
121    * Log a todo message. 
122    * It starts with the current time + " -> LOG_TODO: " 
123    * Params:
124    *      message = the todo message
125    *      obj = current class reference, mostly you pass 'this'
126   **/
127   static void todo(string message, string objectName, bool onlyToConsole = false) {
128     log(LogType.Todo, objectName ~ " -> " ~ message, onlyToConsole);
129   }
130 
131   /**
132    * Log a message using LogType.
133   **/
134   static void log(LogType type, string message, bool onlyToConsole = false) {
135     if (isActive) {
136       string currentTime = Clock.currTime().toString().split(".")[0] ~ platformName;
137       final switch (type) with (LogType) {
138         case Info:
139           debug writeln(currentTime ~ " -> LOG_INFO: " ~ message);
140           if (!onlyToConsole)
141             logFile.writeln(currentTime ~ " -> LOG_INFO: " ~ message);
142           break;
143         case Warning:
144           debug writeln(currentTime ~ " -> LOG_WARNING: " ~ message);
145           if (!onlyToConsole)
146             logFile.writeln(currentTime ~ " -> LOG_WARNING: " ~ message);
147           break;
148         case Error:
149           debug writeln(currentTime ~ " -> LOG_ERROR: " ~ message);
150           if (!onlyToConsole)
151             logFile.writeln(currentTime ~ " -> LOG_ERROR: " ~ message);
152           break;
153         case Exception:
154           debug writeln(currentTime ~ " -> LOG_EXCEPTION: " ~ message);
155           if (!onlyToConsole)
156             logFile.writeln(currentTime ~ " -> LOG_EXCEPTION: " ~ message);
157           break;
158         case Debug:
159           debug writeln(currentTime ~ " -> LOG_DEBUG: " ~ message);
160           if (!onlyToConsole)
161             debug logFile.writeln(currentTime ~ " -> LOG_DEBUG: " ~ message);
162           break;
163         case Todo:
164           debug writeln(currentTime ~ " -> LOG_TODO: " ~ message);
165           if (!onlyToConsole)
166             logFile.writeln(currentTime ~ " -> LOG_TODO: " ~ message);
167           break;
168       }
169     }
170   }
171 }
172 
173 /**
174  * Example for Logger usage:
175 **/
176 unittest {
177   class LogClass {
178     this() {
179       Logger.initialize();
180       scope(exit) Logger.deinitialize();
181       Logger.console("Test message!", typeof(this).stringof);
182       Logger.info("Info test message!", typeof(this).stringof);
183       Logger.warning("Warning test message!", typeof(this).stringof);
184       Logger.error("Error test message!", typeof(this).stringof);
185       try {
186         immutable int x = 5;
187         if (x == 5)
188           throw new Exception("x cannot be 5!");
189       } catch (Exception e) {
190         Logger.exception("Exception test message!");
191       }
192       Logger.todo("Todo test message!", typeof(this).stringof);
193     }
194   }
195 
196   new LogClass();
197 }