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

2 months ago
  1. /**
  2. * @file l3pp.h
  3. * @author Gereon Kremer <gereon.kremer@cs.rwth-aachen.de>
  4. * @author Harold Bruintjes <h.bruintjes@cs.rwth-aachen.de>
  5. *
  6. * The lightweight logging library for C++.
  7. *
  8. * This logging facility is fairly generic and is used as a simple and
  9. * header-only alternative to more advanced solutions like log4cplus or
  10. * boost::log.
  11. *
  12. * The basic components are Sinks, Formatters and Loggers.
  13. *
  14. * A Sink represents a logging output like a terminal or a log file.
  15. * This implementation provides a FileSink and a StreamSink, but the basic
  16. * Sink class can be extended as necessary.
  17. *
  18. * A Formatter is associated with a Sink and produces the actual string that is
  19. * sent to the Sink.
  20. * Usually, it adds auxiliary information like the current time, LogLevel and
  21. * source location to the string logged by the user.
  22. * The Formatter implements a reasonable default behavior for simple logging,
  23. * but it can be subclassed and modified as necessary.
  24. *
  25. * The Logger class finally plugs all these components together.
  26. * Individual loggers can log to one or more sinks (inheritable) and are
  27. * associated with an (inheritable) log level.
  28. *
  29. * Initial configuration may look like this:
  30. * @code{.cpp}
  31. * l3pp::Logger::initialize();
  32. * l3pp::SinkPtr sink = l3pp::StreamSink::create(std::clog);
  33. * l3pp::Logger::getRootLogger()->addSink(sink);
  34. * l3pp::Logger::getRootLogger()->setLevel(l3pp::LogLevel::INFO);
  35. * @endcode
  36. *
  37. * Macro facilitate the usage:
  38. * <ul>
  39. * <li>`L3PP_LOG_<LVL>(logger, msg)` produces a normal log message where
  40. * logger should be string identifying the logger (or a LogPtr) and msg is the
  41. * message to be logged.</li>
  42. * </ul>
  43. * Any message (`msg`) can be an arbitrary expression that one would
  44. * stream to an `std::ostream` like `stream << (msg);`. The default formatter
  45. * adds newlines.
  46. * Manipulators are generally supported. However, for performance avoid std::endl
  47. * and use '\n' directly.
  48. */
  49. #pragma once
  50. #include <chrono>
  51. #include <memory>
  52. namespace l3pp {
  53. /**
  54. * Indicated which log messages should be forwarded to some sink.
  55. *
  56. * All messages which have a level that is equal or greater than the specified
  57. * value will be forwarded.
  58. */
  59. enum class LogLevel {
  60. /// Log messages used for tracing the program flow in detail.
  61. TRACE,
  62. /// Log messages used for debugging.
  63. DEBUG,
  64. /// Log messages used for information.
  65. INFO,
  66. /// Log messages used to warn about an undesired state.
  67. WARN,
  68. /// Log messages used for errors that can be handled.
  69. ERR,
  70. /// Log messages used for errors that lead to program termination.
  71. FATAL,
  72. /// Log no messages.
  73. OFF,
  74. /// Parent level
  75. INHERIT,
  76. /// Default log level.
  77. DEFAULT = WARN,
  78. /// All log messages.
  79. ALL = TRACE
  80. };
  81. /**
  82. * Streaming operator for LogLevel.
  83. * @param os Output stream.
  84. * @param level LogLevel.
  85. * @return os.
  86. */
  87. inline std::ostream& operator<<(std::ostream& os, LogLevel level);
  88. class Logger;
  89. /**
  90. * Contextual information for a new log entry, contains such this as location,
  91. * log info (level, logger) and the time of the event.
  92. * A context will be created automatically by using the macros
  93. */
  94. struct EntryContext {
  95. // Program location
  96. const char* filename;
  97. size_t line;
  98. const char* funcname;
  99. // Time of entry
  100. std::chrono::system_clock::time_point timestamp;
  101. // Log event info
  102. Logger const* logger;
  103. LogLevel level;
  104. EntryContext(const char* filename, size_t line, const char* funcname) :
  105. filename(filename), line(line), funcname(funcname),
  106. timestamp(std::chrono::system_clock::now()), logger(nullptr),
  107. level(LogLevel::OFF)
  108. {
  109. }
  110. EntryContext() :
  111. filename(""), line(0), funcname(""),
  112. timestamp(std::chrono::system_clock::now()), logger(nullptr),
  113. level(LogLevel::OFF)
  114. {
  115. }
  116. };
  117. }
  118. #include "formatter.h"
  119. #include "sink.h"
  120. #include "logger.h"
  121. #include "impl/logging.h"
  122. #include "impl/logger.h"
  123. #include "impl/formatter.h"
  124. #include "impl/sink.h"
  125. #ifdef _MSC_VER
  126. #define __func__ __FUNCTION__
  127. #endif
  128. /// Create a record info.
  129. #define __L3PP_LOG_RECORD l3pp::EntryContext(__FILE__, __LINE__, __func__)
  130. /// Basic logging macro.
  131. #define __L3PP_LOG(level, channel, expr) do { \
  132. auto L3PP_channel = ::l3pp::Logger::getLogger(channel); \
  133. if (L3PP_channel->getLevel() <= level) { \
  134. L3PP_channel->log(level, __L3PP_LOG_RECORD) << expr; \
  135. } \
  136. } while(false)
  137. /// Log with level TRACE.
  138. #define L3PP_LOG_TRACE(channel, expr) __L3PP_LOG(::l3pp::LogLevel::TRACE, channel, expr)
  139. /// Log with level DEBUG.
  140. #define L3PP_LOG_DEBUG(channel, expr) __L3PP_LOG(::l3pp::LogLevel::DEBUG, channel, expr)
  141. /// Log with level INFO.
  142. #define L3PP_LOG_INFO(channel, expr) __L3PP_LOG(::l3pp::LogLevel::INFO, channel, expr)
  143. /// Log with level WARN.
  144. #define L3PP_LOG_WARN(channel, expr) __L3PP_LOG(::l3pp::LogLevel::WARN, channel, expr)
  145. /// Log with level ERROR.
  146. #define L3PP_LOG_ERROR(channel, expr) __L3PP_LOG(::l3pp::LogLevel::ERR, channel, expr)
  147. /// Log with level FATAL.
  148. #define L3PP_LOG_FATAL(channel, expr) __L3PP_LOG(::l3pp::LogLevel::FATAL, channel, expr)