logger.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. // This file is part of OpenCV project.
  2. // It is subject to the license terms in the LICENSE file found in the top-level directory
  3. // of this distribution and at http://opencv.org/license.html.
  4. #ifndef OPENCV_LOGGER_HPP
  5. #define OPENCV_LOGGER_HPP
  6. #include <iostream>
  7. #include <sstream>
  8. #include <limits.h> // INT_MAX
  9. #include "logger.defines.hpp"
  10. #include "logtag.hpp"
  11. namespace cv {
  12. namespace utils {
  13. namespace logging {
  14. //! @addtogroup core_logging
  15. //! @{
  16. /** Set global logging level
  17. @return previous logging level
  18. */
  19. CV_EXPORTS LogLevel setLogLevel(LogLevel logLevel);
  20. /** Get global logging level */
  21. CV_EXPORTS LogLevel getLogLevel();
  22. CV_EXPORTS void registerLogTag(cv::utils::logging::LogTag* plogtag);
  23. CV_EXPORTS void setLogTagLevel(const char* tag, cv::utils::logging::LogLevel level);
  24. CV_EXPORTS cv::utils::logging::LogLevel getLogTagLevel(const char* tag);
  25. namespace internal {
  26. /** Get global log tag */
  27. CV_EXPORTS cv::utils::logging::LogTag* getGlobalLogTag();
  28. /** Write log message */
  29. CV_EXPORTS void writeLogMessage(LogLevel logLevel, const char* message);
  30. /** Write log message */
  31. CV_EXPORTS void writeLogMessageEx(LogLevel logLevel, const char* tag, const char* file, int line, const char* func, const char* message);
  32. /**
  33. * @brief Function pointer type for writeLogMessage. Used by replaceWriteLogMessage.
  34. */
  35. typedef void (*WriteLogMessageFuncType)(LogLevel, const char*);
  36. /**
  37. * @brief Function pointer type for writeLogMessageEx. Used by replaceWriteLogMessageEx.
  38. */
  39. typedef void (*WriteLogMessageExFuncType)(LogLevel, const char*, const char*, int, const char*, const char*);
  40. /**
  41. * @brief Replaces the OpenCV writeLogMessage function with a user-defined function.
  42. * @note The user-defined function must have the same signature as writeLogMessage.
  43. * @note The user-defined function must accept arguments that can be potentially null.
  44. * @note The user-defined function must be thread-safe, as OpenCV logging may be called
  45. * from multiple threads.
  46. * @note The user-defined function must not perform any action that can trigger
  47. * deadlocks or infinite loop. Many OpenCV functions are not re-entrant.
  48. * @note Once replaced, logs will not go through the OpenCV writeLogMessage function.
  49. * @note To restore, call this function with a nullptr.
  50. */
  51. CV_EXPORTS void replaceWriteLogMessage(WriteLogMessageFuncType f);
  52. /**
  53. * @brief Replaces the OpenCV writeLogMessageEx function with a user-defined function.
  54. * @note The user-defined function must have the same signature as writeLogMessage.
  55. * @note The user-defined function must accept arguments that can be potentially null.
  56. * @note The user-defined function must be thread-safe, as OpenCV logging may be called
  57. * from multiple threads.
  58. * @note The user-defined function must not perform any action that can trigger
  59. * deadlocks or infinite loop. Many OpenCV functions are not re-entrant.
  60. * @note Once replaced, logs will not go through any of the OpenCV logging functions
  61. * such as writeLogMessage or writeLogMessageEx, until their respective restore
  62. * methods are called.
  63. * @note To restore, call this function with a nullptr.
  64. */
  65. CV_EXPORTS void replaceWriteLogMessageEx(WriteLogMessageExFuncType f);
  66. } // namespace
  67. struct LogTagAuto
  68. : public LogTag
  69. {
  70. inline LogTagAuto(const char* _name, LogLevel _level)
  71. : LogTag(_name, _level)
  72. {
  73. registerLogTag(this);
  74. }
  75. };
  76. /**
  77. * \def CV_LOG_STRIP_LEVEL
  78. *
  79. * Define CV_LOG_STRIP_LEVEL=CV_LOG_LEVEL_[DEBUG|INFO|WARN|ERROR|FATAL|SILENT] to compile out anything at that and before that logging level
  80. */
  81. #ifndef CV_LOG_STRIP_LEVEL
  82. # if defined NDEBUG
  83. # define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_DEBUG
  84. # else
  85. # define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_VERBOSE
  86. # endif
  87. #endif
  88. #define CV_LOGTAG_PTR_CAST(expr) static_cast<const cv::utils::logging::LogTag*>(expr)
  89. // CV_LOGTAG_EXPAND_NAME is intended to be re-defined (undef and then define again)
  90. // to allows logging users to use a shorter name argument when calling
  91. // CV_LOG_WITH_TAG or its related macros such as CV_LOG_INFO.
  92. //
  93. // This macro is intended to modify the tag argument as a string (token), via
  94. // preprocessor token pasting or metaprogramming techniques. A typical usage
  95. // is to apply a prefix, such as
  96. // ...... #define CV_LOGTAG_EXPAND_NAME(tag) cv_logtag_##tag
  97. //
  98. // It is permitted to re-define to a hard-coded expression, ignoring the tag.
  99. // This would work identically like the CV_LOGTAG_FALLBACK macro.
  100. //
  101. // Important: When the logging macro is called with tag being NULL, a user-defined
  102. // CV_LOGTAG_EXPAND_NAME may expand it into cv_logtag_0, cv_logtag_NULL, or
  103. // cv_logtag_nullptr. Use with care. Also be mindful of C++ symbol redefinitions.
  104. //
  105. // If there is significant amount of logging code with tag being NULL, it is
  106. // recommended to use (re-define) CV_LOGTAG_FALLBACK to inject locally a default
  107. // tag at the beginning of a compilation unit, to minimize lines of code changes.
  108. //
  109. #define CV_LOGTAG_EXPAND_NAME(tag) tag
  110. // CV_LOGTAG_FALLBACK is intended to be re-defined (undef and then define again)
  111. // by any other compilation units to provide a log tag when the logging statement
  112. // does not specify one. The macro needs to expand into a C++ expression that can
  113. // be static_cast into (cv::utils::logging::LogTag*). Null (nullptr) is permitted.
  114. #define CV_LOGTAG_FALLBACK nullptr
  115. // CV_LOGTAG_GLOBAL is the tag used when a log tag is not specified in the logging
  116. // statement nor the compilation unit. The macro needs to expand into a C++
  117. // expression that can be static_cast into (cv::utils::logging::LogTag*). Must be
  118. // non-null. Do not re-define.
  119. #define CV_LOGTAG_GLOBAL cv::utils::logging::internal::getGlobalLogTag()
  120. #define CV_LOG_WITH_TAG(tag, msgLevel, extra_check0, extra_check1, ...) \
  121. for(;;) { \
  122. extra_check0; \
  123. const auto cv_temp_msglevel = (cv::utils::logging::LogLevel)(msgLevel); \
  124. if (cv_temp_msglevel >= (CV_LOG_STRIP_LEVEL)) break; \
  125. auto cv_temp_logtagptr = CV_LOGTAG_PTR_CAST(CV_LOGTAG_EXPAND_NAME(tag)); \
  126. if (!cv_temp_logtagptr) cv_temp_logtagptr = CV_LOGTAG_PTR_CAST(CV_LOGTAG_FALLBACK); \
  127. if (!cv_temp_logtagptr) cv_temp_logtagptr = CV_LOGTAG_PTR_CAST(CV_LOGTAG_GLOBAL); \
  128. if (cv_temp_logtagptr && (cv_temp_msglevel > cv_temp_logtagptr->level)) break; \
  129. extra_check1; \
  130. std::stringstream cv_temp_logstream; \
  131. cv_temp_logstream << __VA_ARGS__; \
  132. cv::utils::logging::internal::writeLogMessageEx( \
  133. cv_temp_msglevel, \
  134. (cv_temp_logtagptr ? cv_temp_logtagptr->name : nullptr), \
  135. __FILE__, \
  136. __LINE__, \
  137. CV_Func, \
  138. cv_temp_logstream.str().c_str()); \
  139. break; \
  140. }
  141. #define CV_LOG_FATAL(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_FATAL, , , __VA_ARGS__)
  142. #define CV_LOG_ERROR(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_ERROR, , , __VA_ARGS__)
  143. #define CV_LOG_WARNING(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_WARNING, , , __VA_ARGS__)
  144. #define CV_LOG_INFO(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_INFO, , , __VA_ARGS__)
  145. #define CV_LOG_DEBUG(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_DEBUG, , , __VA_ARGS__)
  146. #define CV_LOG_VERBOSE(tag, v, ...) CV_LOG_WITH_TAG(tag, (cv::utils::logging::LOG_LEVEL_VERBOSE + (int)(v)), , , __VA_ARGS__)
  147. #if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_INFO
  148. #undef CV_LOG_INFO
  149. #define CV_LOG_INFO(tag, ...)
  150. #endif
  151. #if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_DEBUG
  152. #undef CV_LOG_DEBUG
  153. #define CV_LOG_DEBUG(tag, ...)
  154. #endif
  155. #if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_VERBOSE
  156. #undef CV_LOG_VERBOSE
  157. #define CV_LOG_VERBOSE(tag, v, ...)
  158. #endif
  159. //! @cond IGNORED
  160. #define CV__LOG_ONCE_CHECK_PRE \
  161. static bool _cv_log_once_ ## __LINE__ = false; \
  162. if (_cv_log_once_ ## __LINE__) break;
  163. #define CV__LOG_ONCE_CHECK_POST \
  164. _cv_log_once_ ## __LINE__ = true;
  165. #define CV__LOG_IF_CHECK(logging_cond) \
  166. if (!(logging_cond)) break;
  167. //! @endcond
  168. // CV_LOG_ONCE_XXX macros
  169. #define CV_LOG_ONCE_ERROR(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_ERROR, CV__LOG_ONCE_CHECK_PRE, CV__LOG_ONCE_CHECK_POST, __VA_ARGS__)
  170. #define CV_LOG_ONCE_WARNING(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_WARNING, CV__LOG_ONCE_CHECK_PRE, CV__LOG_ONCE_CHECK_POST, __VA_ARGS__)
  171. #define CV_LOG_ONCE_INFO(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_INFO, CV__LOG_ONCE_CHECK_PRE, CV__LOG_ONCE_CHECK_POST, __VA_ARGS__)
  172. #define CV_LOG_ONCE_DEBUG(tag, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_DEBUG, CV__LOG_ONCE_CHECK_PRE, CV__LOG_ONCE_CHECK_POST, __VA_ARGS__)
  173. #define CV_LOG_ONCE_VERBOSE(tag, v, ...) CV_LOG_WITH_TAG(tag, (cv::utils::logging::LOG_LEVEL_VERBOSE + (int)(v)), CV__LOG_ONCE_CHECK_PRE, CV__LOG_ONCE_CHECK_POST, __VA_ARGS__)
  174. #if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_INFO
  175. #undef CV_LOG_ONCE_INFO
  176. #define CV_LOG_ONCE_INFO(tag, ...)
  177. #endif
  178. #if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_DEBUG
  179. #undef CV_LOG_ONCE_DEBUG
  180. #define CV_LOG_ONCE_DEBUG(tag, ...)
  181. #endif
  182. #if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_VERBOSE
  183. #undef CV_LOG_ONCE_VERBOSE
  184. #define CV_LOG_ONCE_VERBOSE(tag, v, ...)
  185. #endif
  186. // CV_LOG_IF_XXX macros
  187. #define CV_LOG_IF_FATAL(tag, logging_cond, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_FATAL, , CV__LOG_IF_CHECK(logging_cond), __VA_ARGS__)
  188. #define CV_LOG_IF_ERROR(tag, logging_cond, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_ERROR, , CV__LOG_IF_CHECK(logging_cond), __VA_ARGS__)
  189. #define CV_LOG_IF_WARNING(tag, logging_cond, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_WARNING, , CV__LOG_IF_CHECK(logging_cond), __VA_ARGS__)
  190. #define CV_LOG_IF_INFO(tag, logging_cond, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_INFO, , CV__LOG_IF_CHECK(logging_cond), __VA_ARGS__)
  191. #define CV_LOG_IF_DEBUG(tag, logging_cond, ...) CV_LOG_WITH_TAG(tag, cv::utils::logging::LOG_LEVEL_DEBUG, , CV__LOG_IF_CHECK(logging_cond), __VA_ARGS__)
  192. #define CV_LOG_IF_VERBOSE(tag, v, logging_cond, ...) CV_LOG_WITH_TAG(tag, (cv::utils::logging::LOG_LEVEL_VERBOSE + (int)(v)), , CV__LOG_IF_CHECK(logging_cond), __VA_ARGS__)
  193. #if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_INFO
  194. #undef CV_LOG_IF_INFO
  195. #define CV_LOG_IF_INFO(tag, logging_cond, ...)
  196. #endif
  197. #if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_DEBUG
  198. #undef CV_LOG_IF_DEBUG
  199. #define CV_LOG_IF_DEBUG(tag, logging_cond, ...)
  200. #endif
  201. #if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_VERBOSE
  202. #undef CV_LOG_IF_VERBOSE
  203. #define CV_LOG_IF_VERBOSE(tag, v, logging_cond, ...)
  204. #endif
  205. //! @}
  206. }}} // namespace
  207. #endif // OPENCV_LOGGER_HPP