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

/**
* @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)