Leviathan  0.8.0.0
Leviathan game engine
Logger.cpp
Go to the documentation of this file.
1 #include "Include.h"
2 // ------------------------------------ //
3 #include "Logger.h"
4 
5 #include "Define.h"
6 #include "Common/ThreadSafe.h"
7 #ifndef ALTERNATIVE_EXCEPTIONS_FATAL
8 #include "Exceptions.h"
9 #endif //ALTERNATIVE_EXCEPTIONS_FATAL
10 #include "FileSystem.h"
11 
12 #ifdef _WIN32
13 #include "Utility/Convert.h"
14 #endif //_WIN32
15 
16 #include <chrono>
17 #include <fstream>
18 #include <ctime>
19 #include <iomanip>
20 #include <iostream>
21 #include <time.h>
22 #ifdef _WIN32
23 #include "WindowsInclude.h"
24 #endif //_WIN32
25 
26 #include <boost/filesystem.hpp>
27 
28 #include <stdlib.h>
29 
30 using namespace Leviathan;
31 using namespace std;
32 // ------------------------------------ //
33 DLLEXPORT Logger::Logger(const std::string &file):
34  Path(file)
35 {
36 
37  // Get time for putting to the beginning of the log file //
38  auto t = std::time(nullptr);
39 
40  std::stringstream formatedtime;
41 
42 #ifdef _WIN32
43  struct tm curtime;
44  localtime_s(&curtime, &t);
45  formatedtime << std::put_time(&curtime, "%H:%M:%S %A %d.%m.%Y (%Z)");
46 #else
47  struct tm* curtime = localtime(&t);
48  formatedtime << std::put_time(curtime, "%H:%M:%S %A %d.%m.%Y (%Z)");
49 #endif //_WIN32
50 
51  string write = "Start of Leviathan log for leviathan version: " + VERSIONS;
52 
53  write += "\nWriting to file \"" + file + "\"";
54  write += "\n------------------------TIME: " + formatedtime.str() + "------------------------\n";
55 
56  // Create the target folder if it doesn't exist
57  const auto path = boost::filesystem::path(file).parent_path();
58 
59  if(!path.empty()){
60  try{
61  boost::filesystem::create_directories(path);
62  } catch(const std::exception &e){
63 
64  SendDebugMessage("Failed to create folder for log file, exception: " +
65  std::string(e.what()));
66  }
67  }
68 
69  std::ofstream writer(Path);
70 
71  if (!writer.is_open()) {
72 
73  #ifndef ALTERNATIVE_EXCEPTIONS_FATAL
74  throw Exception("Cannot open log file");
75  #else
76  SendDebugMessage("Cannot open log file, quitting");
77  abort(6);
78  #endif //ALTERNATIVE_EXCEPTIONS_FATAL
79  }
80 
81  writer << write;
82 
83  writer.close();
84 
85 
86  PendingLog = "";
87  LatestLogger = this;
88 }
89 
92 
94  // Save if unsaved //
95  Lock lock(LoggerWriteMutex);
96 
97  _Save();
98 
99  // Reset latest logger (this allows to create new logger,
100  // which is quite bad, but won't crash
101  // There is also probably a race condition here
102  if(LatestLogger == this)
103  LatestLogger = nullptr;
104 }
105 
107 
108  return LatestLogger;
109 }
110 
111 Logger* Logger::LatestLogger = NULL;
112 // ------------------------------------ //
113 DLLEXPORT void Logger::Write(const std::string &data){
114 
115  const auto message = data+"\n";
116 
117  Lock lock(LoggerWriteMutex);
118 
119  SendDebugMessage(message);
120 
121  PendingLog += message;
122 
123  _LogUpdateEndPart();
124 }
125 
126 DLLEXPORT void Logger::WriteRaw(const std::string &data){
127 
128  Lock lock(LoggerWriteMutex);
129 
130  SendDebugMessage(data);
131 
132  PendingLog += data;
133 
134  _LogUpdateEndPart();
135 }
136 
137 void Logger::WriteLine(const std::string &Text) {
138 
139  Write(Text);
140 }
141 
142 void Logger::Fatal(const std::string &data) {
143 
144  const auto message = "[FATAL] " + data + "\n";
145 
146  {
147  Lock lock(LoggerWriteMutex);
148 
149  SendDebugMessage(message);
150 
151  PendingLog += message;
152 
153  _LogUpdateEndPart();
154 
155  // This might call Save for the second time, but better call
156  // it twice than miss saving the log before aborting
157  _Save();
158  }
159 
160  // Exit process //
161  abort();
162 }
163 // ------------------------------------ //
164 DLLEXPORT void Logger::Info(const std::string &data){
165 
166  const auto message = "[INFO] " + data + "\n";
167 
168  Lock lock(LoggerWriteMutex);
169 
170  SendDebugMessage(message);
171 
172  PendingLog += message;
173 
174  _LogUpdateEndPart();
175 }
176 // ------------------------------------ //
177 DLLEXPORT void Logger::Error(const std::string &data){
178 
179  const auto message = "[ERROR] " + data + "\n";
180 
181  Lock lock(LoggerWriteMutex);
182 
183  SendDebugMessage(message);
184 
185  PendingLog += message;
186 
187  _LogUpdateEndPart();
188 }
189 // ------------------------------------ //
190 DLLEXPORT void Logger::Warning(const std::string &data){
191 
192  const auto message = "[WARNING] " + data + "\n";
193 
194  Lock lock(LoggerWriteMutex);
195 
196  SendDebugMessage(message);
197 
198  PendingLog += message;
199 
200  _LogUpdateEndPart();
201 }
202 // ------------------------------------ //
204 
205  Lock lock(LoggerWriteMutex);
206 
207  _Save();
208 }
209 
210 void Logger::_Save(){
211 
212  if(PendingLog.empty())
213  return;
214 
215  std::ofstream file(Path, std::ofstream::out | std::ofstream::app);
216 
217  file << PendingLog;
218  file.close();
219 
220  PendingLog.clear();
221 }
222 // -------------------------------- //
223 void Logger::Print(const string &message){
224  Get()->Write(message);
225 }
226 
227 DLLEXPORT void Logger::SendDebugMessage(const string &str){
228 #ifdef _WIN32
229  const wstring converted = Convert::Utf8ToUtf16(str);
230  OutputDebugString(&*converted.begin());
231 #endif // _WIN32
232  // We also want standard output messages //
233  // Using cout should be fine for most other platforms //
234  std::cout << str;
235 }
236 // ------------------------------------ //
237 DLLEXPORT void Logger::DirectWriteBuffer(const std::string &data){
238 
239  Lock guard(LoggerWriteMutex);
240 
241  PendingLog += data;
242 }
243 // ------------------------------------ //
244 DLLEXPORT std::string Logger::GetLogFile() const{
245 
246  return Path;
247 }
248 // ------------------------------------ //
249 void Logger::_LogUpdateEndPart(){
250 
251  _Save();
252 }
253 // ------------------------------------ //
254 
255 
DLLEXPORT void Fatal(const std::string &Text) override
Quits the current game with an error message.
Definition: Logger.cpp:142
DLLEXPORT void Write(const std::string &data) override
Definition: Logger.cpp:113
DLLEXPORT std::string GetLogFile() const
Gets the file the log is being written to.
Definition: Logger.cpp:244
DLLEXPORT void Info(const std::string &data) override
Definition: Logger.cpp:164
virtual DLLEXPORT ~Logger()
Definition: Logger.cpp:93
DLLEXPORT void WriteLine(const std::string &Text) override
Definition: Logger.cpp:137
static DLLEXPORT std::wstring Utf8ToUtf16(const std::string &utf8str)
Decodes an UTF8 string to an UTF16 string (wide string/wstring)
Definition: Convert.cpp:76
static DLLEXPORT void SendDebugMessage(const std::string &str)
Definition: Logger.cpp:227
Base class for all exceptions thrown by Leviathan.
Definition: Exceptions.h:10
Logger class for all text output.
Definition: Logger.h:10
DLLEXPORT void Save()
Definition: Logger.cpp:203
DLLEXPORT void Warning(const std::string &data) override
Definition: Logger.cpp:190
DLLEXPORT void DirectWriteBuffer(const std::string &data)
Adds raw data to the queue unmodified.
Definition: Logger.cpp:237
std::mutex Mutex
Definition: ThreadSafe.h:16
DLLEXPORT Logger(const std::string &file)
Definition: Logger.cpp:33
DLLEXPORT void WriteRaw(const std::string &data)
Prints output without extra newlines (make sure to add them manually)
Definition: Logger.cpp:126
static DLLEXPORT Logger * Get()
Definition: Logger.cpp:106
static Mutex LoggerWriteMutex
Lock when using the logger singleton.
Definition: Logger.cpp:91
#define DLLEXPORT
Definition: Include.h:84
static DLLEXPORT void Print(const std::string &message)
Script wrapper.
Definition: Logger.cpp:223
The access mask controls which registered functions and classes a script sees.
Definition: GameModule.h:12
DLLEXPORT void Error(const std::string &data) override
Definition: Logger.cpp:177
std::unique_lock< std::mutex > Lock
Definition: ThreadSafe.h:18