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.

179 lines
4.8 KiB

  1. /**
  2. * @file logger.h
  3. *
  4. * Defines the base Logger class
  5. */
  6. #pragma once
  7. #include <vector>
  8. #include <sstream>
  9. namespace l3pp {
  10. /**
  11. * LogStream is a logger object that can be streamed into, writing an entry
  12. * to the logger associated upon destruction. Instances of this classer are
  13. * returned by Logger log() functions, so they can be used as such:
  14. * logger->debug() << "Message";
  15. */
  16. class LogStream {
  17. friend class Logger;
  18. Logger& logger;
  19. LogLevel level;
  20. EntryContext context;
  21. mutable std::ostringstream stream;
  22. LogStream(Logger& logger, LogLevel level, EntryContext context) :
  23. logger(logger), level(level), context(context)
  24. {
  25. }
  26. LogStream(const LogStream&) = delete;
  27. LogStream& operator=(const LogStream&) = delete;
  28. public:
  29. LogStream(LogStream&& other) :
  30. logger(other.logger), level(other.level), context(std::move(other.context))/*,
  31. stream(std::move(other.stream))*/
  32. {
  33. stream.str(other.stream.str());
  34. }
  35. ~LogStream();
  36. template<typename T>
  37. friend LogStream const& operator<<(LogStream const& stream, T const& val);
  38. friend LogStream const& operator<<(LogStream const& stream, std::ostream& (*F)(std::ostream&));
  39. };
  40. /**
  41. * Main logger class. Keeps track of all Logger instances, and can be used to
  42. * log various messages. Before the logging library is used, make sure to
  43. * call Logger::initialize(). Loggers are hierarchically nested, by means of
  44. * names separated by a period. All loggers are a (indirect) child of the root
  45. * logger, see Logger::getRootLogger() and Logger::getLogger().
  46. * A logger is associated with a LogLevel. Any entry with a level below this
  47. * level will be filtered out. A LogLevel of INHERIT means the parent log
  48. * level will be compared against instead.
  49. * A logger can be associated with 1 or more Sinks. A log entry is printed to
  50. * each associated sink. If the Logger is set additive (see getAdditive(),
  51. * setAdditive()) parent sinks are logged to as well (by default true).
  52. * Logging can be performed either as a single string message, or by using a
  53. * stream. The latter requires the end() method to be called before the entry
  54. * is logged. For convenience, various logging macros are defined at the end
  55. * of this header.
  56. */
  57. class Logger {
  58. friend class Formatter;
  59. typedef std::shared_ptr<Logger> LogPtr;
  60. LogPtr parent;
  61. std::string name;
  62. LogLevel level;
  63. std::vector<SinkPtr> sinks;
  64. bool additive;
  65. // Logger constructors are private
  66. Logger() : parent(nullptr), name(""), level(LogLevel::DEFAULT),
  67. additive(true)
  68. {
  69. }
  70. Logger(std::string const& name, LogPtr parent) : parent(parent), name(name),
  71. level(LogLevel::INHERIT), additive(true)
  72. {
  73. }
  74. void logEntry(EntryContext const& context, std::string const& msg);
  75. public:
  76. void addSink(SinkPtr sink) {
  77. sinks.push_back(sink);
  78. }
  79. void removeSink(SinkPtr sink);
  80. void setLevel(LogLevel level) {
  81. if (level == LogLevel::INHERIT && !parent) {
  82. return;
  83. }
  84. this->level = level;
  85. }
  86. LogLevel getLevel() const {
  87. if (level == LogLevel::INHERIT) {
  88. return parent->getLevel();
  89. }
  90. return level;
  91. }
  92. std::string const& getName() const {
  93. return name;
  94. }
  95. bool getAdditive() const {
  96. return additive;
  97. }
  98. void setAdditive(bool additive) {
  99. this->additive = additive;
  100. }
  101. void log(LogLevel level, std::string const& msg, EntryContext context = EntryContext());
  102. void trace(std::string const& msg, EntryContext context = EntryContext()) {
  103. log(LogLevel::TRACE, msg, context);
  104. }
  105. void debug(std::string const& msg, EntryContext context = EntryContext()) {
  106. log(LogLevel::DEBUG, msg, context);
  107. }
  108. void info(std::string const& msg, EntryContext context = EntryContext()) {
  109. log(LogLevel::INFO, msg, context);
  110. }
  111. void warn(std::string const& msg, EntryContext context = EntryContext()) {
  112. log(LogLevel::WARN, msg, context);
  113. }
  114. void error(std::string const& msg, EntryContext context = EntryContext()) {
  115. log(LogLevel::ERR, msg, context);
  116. }
  117. void fatal(std::string const& msg, EntryContext context = EntryContext()) {
  118. log(LogLevel::FATAL, msg, context);
  119. }
  120. LogStream log(LogLevel level, EntryContext context = EntryContext());
  121. LogStream trace(EntryContext context = EntryContext()) {
  122. return log(LogLevel::TRACE, context);
  123. }
  124. LogStream debug(EntryContext context = EntryContext()) {
  125. return log(LogLevel::DEBUG, context);
  126. }
  127. LogStream info(EntryContext context = EntryContext()) {
  128. return log(LogLevel::INFO, context);
  129. }
  130. LogStream warn(EntryContext context = EntryContext()) {
  131. return log(LogLevel::WARN, context);
  132. }
  133. LogStream error(EntryContext context = EntryContext()) {
  134. return log(LogLevel::ERR, context);
  135. }
  136. LogStream fatal(EntryContext context = EntryContext()) {
  137. return log(LogLevel::FATAL, context);
  138. }
  139. static void initialize();
  140. static void deinitialize();
  141. static LogPtr getRootLogger();
  142. static LogPtr getLogger(LogPtr logger) {
  143. return logger;
  144. }
  145. static LogPtr getLogger(std::string name);
  146. };
  147. typedef std::shared_ptr<Logger> LogPtr;
  148. }