log.h 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /*************************************************************************
  2. * Copyright (C) 2019 by Cambricon, Inc. All rights reserved
  3. *
  4. * This source code is licensed under the Apache-2.0 license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. *
  7. * A part of this source code is referenced from glog project.
  8. * https://github.com/google/glog/blob/master/src/logging.cc
  9. *
  10. * Copyright (c) 1999, Google Inc.
  11. *
  12. * This source code is licensed under the BSD 3-Clause license found in the
  13. * LICENSE file in the root directory of this source tree.
  14. *
  15. *************************************************************************/
  16. #ifndef EDK_CXXUTIL_LOG_H_
  17. #define EDK_CXXUTIL_LOG_H_
  18. #include <string>
  19. #include <streambuf>
  20. #include <ostream>
  21. /*
  22. * Log filter.
  23. *
  24. * Environment variable: EDK_LOG_FILTER
  25. * Default: ""
  26. *
  27. * Usage:
  28. * export EDK_LOG_FILTER=BANG:2,DEVICE:3 ...
  29. */
  30. /*
  31. * Min category log level
  32. *
  33. * Environment variable: EDK_LOG_LEVEL
  34. * Default: 2 (LOG_WARNING)
  35. */
  36. #define STRINGIFY(src) #src
  37. #define _EDK_LOG_IS_ON(cate, sev) edk::log::LogActivated(STRINGIFY(cate), sev)
  38. #define _EDK_LOG_STREAM(cate, sev) edk::log::LogMessage(STRINGIFY(cate), __FILE__, __LINE__, sev).stream()
  39. #define _EDK_LOG(cate, sev) \
  40. !(_EDK_LOG_IS_ON(cate, sev)) ? (void)0 : edk::log::LogMessageVoidify() & _EDK_LOG_STREAM(cate, sev)
  41. #define _EDK_LOG_IF(cate, sev, condition) \
  42. !(_EDK_LOG_IS_ON(cate, sev) && (condition)) ? (void)0 : edk::log::LogMessageVoidify() & _EDK_LOG_STREAM(cate, sev)
  43. #define _EDK_LOG_CONCAT(lhs, rhs) lhs##_##rhs
  44. #define _EDK_LOG_COUNTER_NAME(name, line) _EDK_LOG_CONCAT(name, line)
  45. #define _EDK_LOG_COUNTER _EDK_LOG_COUNTER_NAME(_log_counter, __LINE__)
  46. #define LOG_EVERY_N(category, severity, N) \
  47. static int _EDK_LOG_COUNTER = 0; \
  48. ++_EDK_LOG_COUNTER > N ? _EDK_LOG_COUNTER -= N : 0; \
  49. _EDK_LOG_IF(category, edk::log::severity, (_EDK_LOG_COUNTER == 1))
  50. #define LOG_FIRST_N(category, severity, N) \
  51. static int _EDK_LOG_COUNTER = 0; \
  52. ++_EDK_LOG_COUNTER > N + 1 ? --_EDK_LOG_COUNTER : 0; \
  53. _EDK_LOG_IF(category, edk::log::severity, (_EDK_LOG_COUNTER <= N))
  54. // LOGF is on regardless of severity
  55. #define LOGF(category) _EDK_LOG_STREAM(category, edk::log::LOG_FATAL)
  56. #define LOGF_IF(category, condition) \
  57. !(condition) ? (void)0 : edk::log::LogMessageVoidify() & _EDK_LOG_STREAM(category, edk::log::LOG_FATAL)
  58. #define LOGE(category) _EDK_LOG(category, edk::log::LOG_ERROR)
  59. #define LOGE_IF(category, condition) _EDK_LOG_IF(category, edk::log::LOG_ERROR, condition)
  60. #define LOGW(category) _EDK_LOG(category, edk::log::LOG_WARNING)
  61. #define LOGW_IF(category, condition) _EDK_LOG_IF(category, edk::log::LOG_WARNING, condition)
  62. #define LOGI(category) _EDK_LOG(category, edk::log::LOG_INFO)
  63. #define LOGI_IF(category, condition) _EDK_LOG_IF(category, edk::log::LOG_INFO, condition)
  64. #define LOGD(category) _EDK_LOG(category, edk::log::LOG_DEBUG)
  65. #define LOGD_IF(category, condition) _EDK_LOG_IF(category, edk::log::LOG_DEBUG, condition)
  66. #define LOGT(category) _EDK_LOG(category, edk::log::LOG_TRACE)
  67. #define LOGT_IF(category, condition) _EDK_LOG_IF(category, edk::log::LOG_TRACE, condition)
  68. #define LOGA(category) _EDK_LOG(category, edk::log::LOG_ALL)
  69. #define LOGA_IF(category, condition) _EDK_LOG_IF(category, edk::log::LOG_ALL, condition)
  70. #define CHECK(category, condition) \
  71. LOGF_IF((category), !(condition)) << "Check condition (" << STRINGIFY(condition) ") failed"
  72. namespace edk {
  73. namespace log {
  74. /**
  75. * @brief log severity
  76. * 0, FATAL
  77. * 1, LOG_ERROR
  78. * 2, WARNING
  79. * 3, INFO
  80. * 4, DEBUG
  81. * 5, TRACE
  82. * 6, ALL
  83. */
  84. enum LogSeverity {
  85. LOG_FATAL = 0,
  86. LOG_ERROR,
  87. LOG_WARNING,
  88. LOG_INFO,
  89. LOG_DEBUG,
  90. LOG_TRACE,
  91. LOG_ALL
  92. };
  93. class LogSink {
  94. public:
  95. virtual ~LogSink() { }
  96. virtual void Send(LogSeverity severity, const char* category,
  97. const char* filename, int line,
  98. const struct ::tm* tm_time, int32_t usecs,
  99. const char* message, size_t message_len) = 0;
  100. virtual void WaitTillSent() { } // noop default
  101. static std::string ToString(LogSeverity severity, const char* category,
  102. const char* filename, int line,
  103. const struct ::tm* tm_time, int32_t usecs,
  104. const char* message, size_t message_len);
  105. }; // class LogSink
  106. class LogMessageVoidify {
  107. public:
  108. LogMessageVoidify() { }
  109. // This has to be an operator with a precedence lower than << but
  110. // higher than ?:
  111. void operator&(std::ostream&) { }
  112. };
  113. class LogMessage {
  114. public:
  115. class LogStreamBuf : public std::streambuf {
  116. public:
  117. // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\0'.
  118. LogStreamBuf(char *buf, int len) {
  119. setp(buf, buf + len - 2);
  120. }
  121. // This effectively ignores overflow.
  122. virtual int_type overflow(int_type ch) {
  123. return ch;
  124. }
  125. // Legacy public ostrstream method.
  126. size_t pcount() const { return pptr() - pbase(); }
  127. char* pbase() const { return std::streambuf::pbase(); }
  128. }; // class LogStreamBuf
  129. class LogStream : public std::ostream {
  130. public:
  131. LogStream(char *buf, int len)
  132. : std::ostream(NULL),
  133. streambuf_(buf, len) {
  134. rdbuf(&streambuf_);
  135. }
  136. // Legacy std::streambuf methods.
  137. size_t pcount() const { return streambuf_.pcount(); }
  138. char* pbase() const { return streambuf_.pbase(); }
  139. char* str() const { return pbase(); }
  140. private:
  141. LogStream(const LogStream&) = delete;
  142. LogStream& operator=(const LogStream&) = delete;
  143. LogStreamBuf streambuf_;
  144. }; // class LogStream
  145. LogMessage(const char* category, const char* file, int line, LogSeverity severity);
  146. ~LogMessage();
  147. void Init(const char* category, const char* file, int line, LogSeverity severity);
  148. std::ostream& stream();
  149. struct LogMessageData;
  150. private:
  151. LogMessage(const LogMessage&) = delete;
  152. LogMessage& operator=(const LogMessage&) = delete;
  153. void Flush();
  154. void SendToLog();
  155. LogMessageData* data_;
  156. LogMessageData* allocated_;
  157. static const size_t MaxLogMsgLen;
  158. }; // class LogMessage
  159. namespace detail {
  160. bool CategoryActivated(const char* category, LogSeverity severity) noexcept;
  161. } // namespace detail
  162. extern const int g_min_log_level;
  163. extern const bool g_enable_category_filter;
  164. inline bool LogActivated(const char* category, LogSeverity severity) noexcept {
  165. if (g_enable_category_filter) {
  166. return detail::CategoryActivated(category, severity);
  167. }
  168. return g_min_log_level >= severity;
  169. }
  170. /**
  171. * @brief Init log system
  172. *
  173. * @note Only log to stderr as default if not init
  174. *
  175. * @param log_to_stderr Log messages go to stderr
  176. * @param log_to_file Log messages go to log file
  177. * @param log_dir Directory to store log file
  178. */
  179. void InitLogging(bool log_to_stderr, bool log_to_file, const std::string& log_dir = "") noexcept;
  180. /**
  181. * @brief Shutdown log output
  182. */
  183. void ShutdownLogging() noexcept;
  184. /**
  185. * @brief Flush log file interval, in second
  186. *
  187. * @note Using 30s as default if not set
  188. *
  189. * @param time Flush interval
  190. */
  191. void SetFileFlushInterval(uint32_t time) noexcept;
  192. /**
  193. * @brief Add customized log sink to logger
  194. *
  195. * @param log_sink Customized log sink
  196. */
  197. void AddLogSink(LogSink* log_sink) noexcept;
  198. /**
  199. * @brief Remove customized log sink
  200. *
  201. * @param log_sink Customized log sink
  202. */
  203. void RemoveLogSink(LogSink* log_sink) noexcept;
  204. } // namespace log
  205. } // namespace edk
  206. #endif // EDK_CXXUTIL_LOG_H_