From b450811e4b34f87320e4ab8fe968923f3cfbcd1c Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Sun, 17 Dec 2017 22:28:33 +0000 Subject: [PATCH] core(logger): add log level configuration option --- .../opencv2/core/utils/logger.defines.hpp | 22 +++++ .../include/opencv2/core/utils/logger.hpp | 40 ++++----- modules/core/src/logger.cpp | 85 +++++++++++++++++++ 3 files changed, 128 insertions(+), 19 deletions(-) create mode 100644 modules/core/include/opencv2/core/utils/logger.defines.hpp create mode 100644 modules/core/src/logger.cpp diff --git a/modules/core/include/opencv2/core/utils/logger.defines.hpp b/modules/core/include/opencv2/core/utils/logger.defines.hpp new file mode 100644 index 0000000000..b2dfc41704 --- /dev/null +++ b/modules/core/include/opencv2/core/utils/logger.defines.hpp @@ -0,0 +1,22 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_LOGGER_DEFINES_HPP +#define OPENCV_LOGGER_DEFINES_HPP + +//! @addtogroup core_logging +//! @{ + +// Supported logging levels and their semantic +#define CV_LOG_LEVEL_SILENT 0 //!< for using in setLogLevel() call +#define CV_LOG_LEVEL_FATAL 1 //!< Fatal (critical) error (unrecoverable internal error) +#define CV_LOG_LEVEL_ERROR 2 //!< Error message +#define CV_LOG_LEVEL_WARN 3 //!< Warning message +#define CV_LOG_LEVEL_INFO 4 //!< Info message +#define CV_LOG_LEVEL_DEBUG 5 //!< Debug message. Disabled in the "Release" build. +#define CV_LOG_LEVEL_VERBOSE 6 //!< Verbose (trace) messages. Requires verbosity level. Disabled in the "Release" build. + +//! @} + +#endif // OPENCV_LOGGER_DEFINES_HPP diff --git a/modules/core/include/opencv2/core/utils/logger.hpp b/modules/core/include/opencv2/core/utils/logger.hpp index 4f70355e4d..47094f994d 100644 --- a/modules/core/include/opencv2/core/utils/logger.hpp +++ b/modules/core/include/opencv2/core/utils/logger.hpp @@ -2,14 +2,14 @@ // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html. -#ifndef OPENCV_LOGGING_HPP -#define OPENCV_LOGGING_HPP +#ifndef OPENCV_LOGGER_HPP +#define OPENCV_LOGGER_HPP #include #include #include // INT_MAX -// TODO This file contains just interface part with implementation stubs. +#include "logger.defines.hpp" //! @addtogroup core_logging // This section describes OpenCV logging utilities. @@ -20,15 +20,6 @@ namespace cv { namespace utils { namespace logging { -// Supported logging levels and their semantic -#define CV_LOG_LEVEL_SILENT 0 //!< for using in setLogVevel() call -#define CV_LOG_LEVEL_FATAL 1 //!< Fatal (critical) error (unrecoverable internal error) -#define CV_LOG_LEVEL_ERROR 2 //!< Error message -#define CV_LOG_LEVEL_WARN 3 //!< Warning message -#define CV_LOG_LEVEL_INFO 4 //!< Info message -#define CV_LOG_LEVEL_DEBUG 5 //!< Debug message. Disabled in the "Release" build. -#define CV_LOG_LEVEL_VERBOSE 6 //!< Verbose (trace) messages. Requires verbosity level. Disabled in the "Release" build. - //! Supported logging levels and their semantic enum LogLevel { LOG_LEVEL_SILENT = 0, //!< for using in setLogVevel() call @@ -43,6 +34,17 @@ enum LogLevel { #endif }; +/** Set global logging level +@return previous logging level +*/ +CV_EXPORTS LogLevel setLogLevel(LogLevel logLevel); +/** Get global logging level */ +CV_EXPORTS LogLevel getLogLevel(); + +namespace internal { +/** Write log message */ +CV_EXPORTS void writeLogMessage(LogLevel logLevel, const char* message); +} // namespace /** * \def CV_LOG_STRIP_LEVEL @@ -58,23 +60,23 @@ enum LogLevel { #endif -#define CV_LOG_FATAL(tag, ...) for(;;) { std::stringstream ss; ss << "[FATAL:" << cv::utils::getThreadID() << "] " << __VA_ARGS__ << std::endl; std::cerr << ss.str() << std::flush; break; } -#define CV_LOG_ERROR(tag, ...) for(;;) { std::stringstream ss; ss << "[ERROR:" << cv::utils::getThreadID() << "] " << __VA_ARGS__ << std::endl; std::cerr << ss.str() << std::flush; break; } -#define CV_LOG_WARNING(tag, ...) for(;;) { std::stringstream ss; ss << "[ WARN:" << cv::utils::getThreadID() << "] " << __VA_ARGS__ << std::endl; std::cout << ss.str() << std::flush; break; } +#define CV_LOG_FATAL(tag, ...) for(;;) { if (cv::utils::logging::getLogLevel() < cv::utils::logging::LOG_LEVEL_FATAL) break; std::stringstream ss; ss << __VA_ARGS__; cv::utils::logging::internal::writeLogMessage(cv::utils::logging::LOG_LEVEL_FATAL, ss.str().c_str()); break; } +#define CV_LOG_ERROR(tag, ...) for(;;) { if (cv::utils::logging::getLogLevel() < cv::utils::logging::LOG_LEVEL_ERROR) break; std::stringstream ss; ss << __VA_ARGS__; cv::utils::logging::internal::writeLogMessage(cv::utils::logging::LOG_LEVEL_ERROR, ss.str().c_str()); break; } +#define CV_LOG_WARNING(tag, ...) for(;;) { if (cv::utils::logging::getLogLevel() < cv::utils::logging::LOG_LEVEL_WARNING) break; std::stringstream ss; ss << __VA_ARGS__; cv::utils::logging::internal::writeLogMessage(cv::utils::logging::LOG_LEVEL_WARNING, ss.str().c_str()); break; } #if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_INFO #define CV_LOG_INFO(tag, ...) #else -#define CV_LOG_INFO(tag, ...) for(;;) { std::stringstream ss; ss << "[ INFO:" << cv::utils::getThreadID() << "] " << __VA_ARGS__ << std::endl; std::cout << ss.str(); break; } +#define CV_LOG_INFO(tag, ...) for(;;) { if (cv::utils::logging::getLogLevel() < cv::utils::logging::LOG_LEVEL_INFO) break; std::stringstream ss; ss << __VA_ARGS__; cv::utils::logging::internal::writeLogMessage(cv::utils::logging::LOG_LEVEL_INFO, ss.str().c_str()); break; } #endif #if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_DEBUG #define CV_LOG_DEBUG(tag, ...) #else -#define CV_LOG_DEBUG(tag, ...) for(;;) { std::stringstream ss; ss << "[DEBUG:" << cv::utils::getThreadID() << "] " << __VA_ARGS__ << std::endl; std::cout << ss.str(); break; } +#define CV_LOG_DEBUG(tag, ...) for(;;) { if (cv::utils::logging::getLogLevel() < cv::utils::logging::LOG_LEVEL_DEBUG) break; std::stringstream ss; ss << __VA_ARGS__; cv::utils::logging::internal::writeLogMessage(cv::utils::logging::LOG_LEVEL_DEBUG, ss.str().c_str()); break; } #endif #if CV_LOG_STRIP_LEVEL <= CV_LOG_LEVEL_VERBOSE #define CV_LOG_VERBOSE(tag, v, ...) #else -#define CV_LOG_VERBOSE(tag, v, ...) for(;;) { std::stringstream ss; ss << "[VERB" << v << ":" << cv::utils::getThreadID() << "] " << __VA_ARGS__ << std::endl; std::cout << ss.str(); break; } +#define CV_LOG_VERBOSE(tag, v, ...) for(;;) { if (cv::utils::logging::getLogLevel() < cv::utils::logging::LOG_LEVEL_VERBOSE) break; std::stringstream ss; ss << "[VERB" << v << ":" << cv::utils::getThreadID() << "] " << __VA_ARGS__; cv::utils::logging::internal::writeLogMessage(cv::utils::logging::LOG_LEVEL_VERBOSE, ss.str().c_str()); break; } #endif @@ -82,4 +84,4 @@ enum LogLevel { //! @} -#endif // OPENCV_LOGGING_HPP +#endif // OPENCV_LOGGER_HPP diff --git a/modules/core/src/logger.cpp b/modules/core/src/logger.cpp new file mode 100644 index 0000000000..b390a2538e --- /dev/null +++ b/modules/core/src/logger.cpp @@ -0,0 +1,85 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#include + +#include +#include + +#include +#include +#include + +namespace cv { +namespace utils { +namespace logging { + +static LogLevel parseLogLevelConfiguration() +{ + static cv::String param_log_level = utils::getConfigurationParameterString("OPENCV_LOG_LEVEL", "INFO"); + if (param_log_level == "DISABLED" || param_log_level == "disabled" || + param_log_level == "0" || param_log_level == "OFF" || param_log_level == "off") + return LOG_LEVEL_SILENT; + if (param_log_level == "FATAL" || param_log_level == "fatal") + return LOG_LEVEL_FATAL; + if (param_log_level == "ERROR" || param_log_level == "error") + return LOG_LEVEL_ERROR; + if (param_log_level == "WARNING" || param_log_level == "warning" || + param_log_level == "WARNINGS" || param_log_level == "warnings" || + param_log_level == "WARN" || param_log_level == "warn") + return LOG_LEVEL_WARNING; + if (param_log_level == "INFO" || param_log_level == "info") + return LOG_LEVEL_INFO; + if (param_log_level == "DEBUG" || param_log_level == "debug") + return LOG_LEVEL_DEBUG; + if (param_log_level == "VERBOSE" || param_log_level == "verbose") + return LOG_LEVEL_VERBOSE; + std::cerr << "ERROR: Unexpected logging level value: " << param_log_level << std::endl; + return LOG_LEVEL_INFO; +} + +static LogLevel& getLogLevelVariable() +{ + static LogLevel g_logLevel = parseLogLevelConfiguration(); + return g_logLevel; +} + +LogLevel setLogLevel(LogLevel logLevel) +{ + LogLevel old = getLogLevelVariable(); + getLogLevelVariable() = logLevel; + return old; +} + +LogLevel getLogLevel() +{ + return getLogLevelVariable(); +} + +namespace internal { + +void writeLogMessage(LogLevel logLevel, const char* message) +{ + const int threadID = cv::utils::getThreadID(); + std::ostream* out = (logLevel <= LOG_LEVEL_WARNING) ? &std::cerr : &std::cout; + std::stringstream ss; + switch (logLevel) + { + case LOG_LEVEL_FATAL: ss << "[FATAL:" << threadID << "] " << message << std::endl; break; + case LOG_LEVEL_ERROR: ss << "[ERROR:" << threadID << "] " << message << std::endl; break; + case LOG_LEVEL_WARNING: ss << "[ WARN:" << threadID << "] " << message << std::endl; break; + case LOG_LEVEL_INFO: ss << "[ INFO:" << threadID << "] " << message << std::endl; break; + case LOG_LEVEL_DEBUG: ss << "[DEBUG:" << threadID << "] " << message << std::endl; break; + case LOG_LEVEL_VERBOSE: ss << message << std::endl; break; + default: + return; + } + (*out) << ss.str(); + if (logLevel <= LOG_LEVEL_WARNING) + (*out) << std::flush; +} + +} // namespace + +}}} // namespace