20 #ifndef _MALMO_LOGGER_H_
21 #define _MALMO_LOGGER_H_
49 #include <boost/date_time/posix_time/posix_time_types.hpp>
50 #include <boost/date_time/posix_time/posix_time_io.hpp>
71 #define LOG_COMPONENT Logger::LOG_OBJECTLIFETIME
73 #define LOGERROR(...) Logger::getLogger().print<Logger::LOG_ERRORS, LOG_COMPONENT>(__VA_ARGS__)
74 #define LOGWARNING(...) Logger::getLogger().print<Logger::LOG_WARNINGS, LOG_COMPONENT>(__VA_ARGS__)
75 #define LOGINFO(...) Logger::getLogger().print<Logger::LOG_INFO, LOG_COMPONENT>(__VA_ARGS__)
76 #define LOGFINE(...) Logger::getLogger().print<Logger::LOG_FINE, LOG_COMPONENT>(__VA_ARGS__)
77 #define LOGTRACE(...) Logger::getLogger().print<Logger::LOG_TRACE, LOG_COMPONENT>(__VA_ARGS__)
78 #define LOGSIMPLE(level, message) Logger::getLogger().print<Logger:: level , LOG_COMPONENT >(std::string(message))
79 #define LOGSECTION(level, message) LogSection<Logger:: level , LOG_COMPONENT> log_section(message);
80 #define LT(x) std::string(x)
81 #define MALMO_LOGGABLE_OBJECT(name) LoggerLifetimeTracker log_tracker{ #name };
103 , LOG_OBJECTLIFETIME = 16
104 , LOG_ALL_COMPONENTS = 31
107 Logger() : line_number(0), indentation(0)
109 this->has_backend =
false;
110 this->is_spooling.clear();
111 this->logger_backend =
new std::thread{ Logger::log_spooler,
this };
116 this->severity_level = LOG_OFF;
118 this->is_spooling.clear();
126 auto start = std::chrono::system_clock::now();
127 while (this->has_backend && (std::chrono::system_clock::now() - start).count() < 2.0);
135 this->logger_backend->detach();
137 if (this->writer.is_open())
138 this->writer.close();
142 static Logger& getLogger()
144 static Logger the_logger;
149 void print(Args&&...args);
151 void setFilename(
const std::string& file)
153 std::lock_guard< std::timed_mutex > lock(this->write_guard);
154 if (this->writer.is_open())
155 this->writer.close();
156 this->writer.open(file, std::ofstream::out | std::ofstream::app);
161 this->logging_components |= component;
163 this->logging_components &= ~component;
171 Logger::getLogger().setFilename(filename);
172 Logger::getLogger().setSeverityLevel(severity_level);
177 Logger::getLogger().setComponent(component, enable_logging);
188 switch (severity_level)
191 Logger::getLogger().print<LOG_OFF, LOG_ALL_COMPONENTS>(message);
break;
193 Logger::getLogger().print<LOG_ERRORS, LOG_ALL_COMPONENTS>(message);
break;
195 Logger::getLogger().print<LOG_WARNINGS, LOG_ALL_COMPONENTS>(message);
break;
197 Logger::getLogger().print<LOG_INFO, LOG_ALL_COMPONENTS>(message);
break;
199 Logger::getLogger().print<LOG_FINE, LOG_ALL_COMPONENTS>(message);
break;
201 Logger::getLogger().print<LOG_TRACE, LOG_ALL_COMPONENTS>(message);
break;
203 Logger::getLogger().print<LOG_ALL, LOG_ALL_COMPONENTS>(message);
break;
208 template<LoggingSeverityLevel level, Logger::LoggingComponent component>
friend class LogSection;
213 std::lock_guard< std::timed_mutex > lock(write_guard);
218 std::lock_guard< std::timed_mutex > lock(write_guard);
222 static void log_spooler(Logger* logger)
224 logger->has_backend =
true;
225 logger->is_spooling.test_and_set();
226 std::unique_lock<std::timed_mutex> writing_lock{ logger->write_guard, std::defer_lock };
230 std::this_thread::sleep_for(std::chrono::milliseconds{ 100 });
231 if (logger->log_buffer.size())
234 logger->clear_backlog();
235 writing_lock.unlock();
237 }
while (logger->is_spooling.test_and_set());
239 logger->has_backend =
false;
263 std::this_thread::sleep_for(std::chrono::milliseconds(100000));
269 for (
auto& item : this->log_buffer)
273 this->log_buffer.clear();
276 void performWrite(
const std::string& logline)
278 std::string str(logline);
279 str.erase(std::remove(str.begin(), str.end(),
'\n'), str.end());
280 if (this->writer.is_open())
281 this->writer << str << std::endl;
283 std::cout << str << std::endl;
287 friend void log_spooler(Logger* logger);
289 template<
typename First,
typename... Others>
void print_impl(std::stringstream&& message_stream, First&& param1, Others&&... params)
291 message_stream << param1;
292 print_impl(std::forward<std::stringstream>(message_stream), std::move(params)...);
295 void print_impl(std::stringstream&& message_stream)
297 std::lock_guard< std::timed_mutex > lock(this->write_guard);
298 this->log_buffer.push_back(message_stream.str());
302 unsigned int logging_components{ LOG_ALL_COMPONENTS };
305 std::timed_mutex write_guard;
306 std::vector<std::string> log_buffer;
308 std::atomic_bool has_backend;
309 std::atomic_flag is_spooling;
311 std::ofstream writer;
312 std::thread *logger_backend;
317 if (level > this->severity_level)
319 if (!(this->logging_components & component))
321 std::stringstream message_stream;
322 auto now = boost::posix_time::microsec_clock::universal_time();
323 message_stream << now <<
" P ";
326 case LoggingSeverityLevel::LOG_ALL:
327 case LoggingSeverityLevel::LOG_ERRORS:
328 message_stream <<
"ERROR ";
330 case LoggingSeverityLevel::LOG_WARNINGS:
331 message_stream <<
"WARNING ";
333 case LoggingSeverityLevel::LOG_INFO:
334 message_stream <<
"INFO ";
336 case LoggingSeverityLevel::LOG_FINE:
337 message_stream <<
"FINE ";
339 case LoggingSeverityLevel::LOG_TRACE:
340 case LoggingSeverityLevel::LOG_OFF:
341 message_stream <<
"TRACE ";
344 for (
int i = 0; i < this->indentation; i++)
345 message_stream <<
" ";
347 print_impl(std::forward<std::stringstream>(message_stream), std::move(args)...);
351 template<Logger::LoggingSeverityLevel level, Logger::LoggingComponent component>
357 Logger::getLogger().print<level, component>(title);
358 Logger::getLogger().print<level, component>(std::string(
"{"));
359 Logger::getLogger().indent();
363 Logger::getLogger().unindent();
364 Logger::getLogger().print<level, component>(std::string(
"}"));
381 int prev_val = object_count.fetch_add(-1);
382 LOGFINE(LT(
"Destructing "), this->name, LT(
" (object count now "), prev_val - 1, LT(
")"));
388 int prev_val = object_count.fetch_add(1);
389 LOGFINE(LT(
"Constructing "), this->name, LT(
" (object count now "), prev_val + 1, LT(
")"));
391 static std::atomic<int> object_count;
static void setLogging(const std::string &filename, LoggingSeverityLevel severity_level)
Sets logging options for debugging.
Definition: Logger.h:169
LoggingComponent
Specifies the components that will output logging information.
Definition: Logger.h:98
LoggingSeverityLevel
Specifies the detail that will be logged, if logging is enabled.
Definition: Logger.h:87
static void appendToLog(LoggingSeverityLevel severity_level, const std::string &message)
Add a single line to the log.
Definition: Logger.h:185
static void setLoggingComponent(LoggingComponent component, bool enable_logging)
Switches on/off logging for a particular component. All components are enabled by default....
Definition: Logger.h:175