You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							165 lines
						
					
					
						
							4.9 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							165 lines
						
					
					
						
							4.9 KiB
						
					
					
				
								/**
							 | 
						|
								 * @file l3pp.h
							 | 
						|
								 * @author Gereon Kremer <gereon.kremer@cs.rwth-aachen.de>
							 | 
						|
								 * @author Harold Bruintjes <h.bruintjes@cs.rwth-aachen.de>
							 | 
						|
								 *
							 | 
						|
								 * The lightweight logging library for C++.
							 | 
						|
								 *
							 | 
						|
								 * This logging facility is fairly generic and is used as a simple and
							 | 
						|
								 * header-only alternative to more advanced solutions like log4cplus or
							 | 
						|
								 * boost::log.
							 | 
						|
								 *
							 | 
						|
								 * The basic components are Sinks, Formatters and Loggers.
							 | 
						|
								 *
							 | 
						|
								 * A Sink represents a logging output like a terminal or a log file.
							 | 
						|
								 * This implementation provides a FileSink and a StreamSink, but the basic
							 | 
						|
								 * Sink class can be extended as necessary.
							 | 
						|
								 *
							 | 
						|
								 * A Formatter is associated with a Sink and produces the actual string that is
							 | 
						|
								 * sent to the Sink.
							 | 
						|
								 * Usually, it adds auxiliary information like the current time, LogLevel and
							 | 
						|
								 * source location to the string logged by the user.
							 | 
						|
								 * The Formatter implements a reasonable default behavior for simple logging,
							 | 
						|
								 * but it can be subclassed and modified as necessary.
							 | 
						|
								 *
							 | 
						|
								 * The Logger class finally plugs all these components together.
							 | 
						|
								 * Individual loggers can log to one or more sinks (inheritable) and are
							 | 
						|
								 * associated with an (inheritable) log level.
							 | 
						|
								 *
							 | 
						|
								 * Initial configuration may look like this:
							 | 
						|
								 * @code{.cpp}
							 | 
						|
								 * l3pp::Logger::initialize();
							 | 
						|
								 * l3pp::SinkPtr sink = l3pp::StreamSink::create(std::clog);
							 | 
						|
								 * l3pp::Logger::getRootLogger()->addSink(sink);
							 | 
						|
								 * l3pp::Logger::getRootLogger()->setLevel(l3pp::LogLevel::INFO);
							 | 
						|
								 * @endcode
							 | 
						|
								 * 
							 | 
						|
								 * Macro facilitate the usage:
							 | 
						|
								 * <ul>
							 | 
						|
								 * <li>`L3PP_LOG_<LVL>(logger, msg)` produces a normal log message where
							 | 
						|
								 * logger should be string identifying the logger (or a LogPtr) and msg is the
							 | 
						|
								 * message to be logged.</li>
							 | 
						|
								 * </ul>
							 | 
						|
								 * Any message (`msg`) can be an arbitrary expression that one would
							 | 
						|
								 * stream to an `std::ostream` like `stream << (msg);`. The default formatter
							 | 
						|
								 * adds newlines.
							 | 
						|
								 * Manipulators are generally supported. However, for performance avoid std::endl
							 | 
						|
								 * and use '\n' directly.
							 | 
						|
								 */
							 | 
						|
								
							 | 
						|
								#pragma once
							 | 
						|
								
							 | 
						|
								#include <chrono>
							 | 
						|
								#include <memory>
							 | 
						|
								
							 | 
						|
								namespace l3pp {
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Indicated which log messages should be forwarded to some sink.
							 | 
						|
								 * 
							 | 
						|
								 * All messages which have a level that is equal or greater than the specified
							 | 
						|
								 * value will be forwarded.
							 | 
						|
								 */
							 | 
						|
								enum class LogLevel {
							 | 
						|
									/// Log messages used for tracing the program flow in detail.
							 | 
						|
									TRACE,
							 | 
						|
									/// Log messages used for debugging.
							 | 
						|
									DEBUG,
							 | 
						|
									/// Log messages used for information.
							 | 
						|
									INFO,
							 | 
						|
									/// Log messages used to warn about an undesired state.
							 | 
						|
									WARN,
							 | 
						|
									/// Log messages used for errors that can be handled.
							 | 
						|
									ERR,
							 | 
						|
									/// Log messages used for errors that lead to program termination.
							 | 
						|
									FATAL,
							 | 
						|
									/// Log no messages.
							 | 
						|
									OFF,
							 | 
						|
									/// Parent level
							 | 
						|
									INHERIT,
							 | 
						|
									/// Default log level.
							 | 
						|
									DEFAULT = WARN,
							 | 
						|
									/// All log messages.
							 | 
						|
									ALL = TRACE
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Streaming operator for LogLevel.
							 | 
						|
								 * @param os Output stream.
							 | 
						|
								 * @param level LogLevel.
							 | 
						|
								 * @return os.
							 | 
						|
								 */
							 | 
						|
								inline std::ostream& operator<<(std::ostream& os, LogLevel level);
							 | 
						|
								
							 | 
						|
								class Logger;
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Contextual information for a new log entry, contains such this as location,
							 | 
						|
								 * log info (level, logger) and the time of the event.
							 | 
						|
								 * A context will be created automatically by using the macros
							 | 
						|
								 */
							 | 
						|
								struct EntryContext {
							 | 
						|
									// Program location
							 | 
						|
									const char* filename;
							 | 
						|
									size_t line;
							 | 
						|
									const char* funcname;
							 | 
						|
								
							 | 
						|
									// Time of entry
							 | 
						|
									std::chrono::system_clock::time_point timestamp;
							 | 
						|
								
							 | 
						|
									// Log event info
							 | 
						|
									Logger const* logger;
							 | 
						|
									LogLevel level;
							 | 
						|
								
							 | 
						|
									EntryContext(const char* filename, size_t line, const char* funcname) :
							 | 
						|
										filename(filename), line(line), funcname(funcname),
							 | 
						|
										timestamp(std::chrono::system_clock::now()), logger(nullptr),
							 | 
						|
										level(LogLevel::OFF)
							 | 
						|
									{
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									EntryContext() :
							 | 
						|
										filename(""), line(0), funcname(""),
							 | 
						|
										timestamp(std::chrono::system_clock::now()), logger(nullptr),
							 | 
						|
										level(LogLevel::OFF)
							 | 
						|
									{
							 | 
						|
									}
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								#include "formatter.h"
							 | 
						|
								#include "sink.h"
							 | 
						|
								#include "logger.h"
							 | 
						|
								
							 | 
						|
								#include "impl/logging.h"
							 | 
						|
								#include "impl/logger.h"
							 | 
						|
								#include "impl/formatter.h"
							 | 
						|
								#include "impl/sink.h"
							 | 
						|
								
							 | 
						|
								#ifdef _MSC_VER
							 | 
						|
								#define __func__ __FUNCTION__
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								/// Create a record info.
							 | 
						|
								#define __L3PP_LOG_RECORD l3pp::EntryContext(__FILE__, __LINE__, __func__)
							 | 
						|
								/// Basic logging macro.
							 | 
						|
								#define __L3PP_LOG(level, channel, expr) do { \
							 | 
						|
								    auto L3PP_channel = ::l3pp::Logger::getLogger(channel); \
							 | 
						|
								    if (L3PP_channel->getLevel() <= level) { \
							 | 
						|
								        L3PP_channel->log(level, __L3PP_LOG_RECORD) << expr; \
							 | 
						|
								    } \
							 | 
						|
								} while(false)
							 | 
						|
								
							 | 
						|
								/// Log with level TRACE.
							 | 
						|
								#define L3PP_LOG_TRACE(channel, expr) __L3PP_LOG(::l3pp::LogLevel::TRACE, channel, expr)
							 | 
						|
								/// Log with level DEBUG.
							 | 
						|
								#define L3PP_LOG_DEBUG(channel, expr) __L3PP_LOG(::l3pp::LogLevel::DEBUG, channel, expr)
							 | 
						|
								/// Log with level INFO.
							 | 
						|
								#define L3PP_LOG_INFO(channel, expr) __L3PP_LOG(::l3pp::LogLevel::INFO, channel, expr)
							 | 
						|
								/// Log with level WARN.
							 | 
						|
								#define L3PP_LOG_WARN(channel, expr) __L3PP_LOG(::l3pp::LogLevel::WARN, channel, expr)
							 | 
						|
								/// Log with level ERROR.
							 | 
						|
								#define L3PP_LOG_ERROR(channel, expr) __L3PP_LOG(::l3pp::LogLevel::ERR, channel, expr)
							 | 
						|
								/// Log with level FATAL.
							 | 
						|
								#define L3PP_LOG_FATAL(channel, expr) __L3PP_LOG(::l3pp::LogLevel::FATAL, channel, expr)
							 |