diff options
-rw-r--r-- | Documentation/Doxyfile.in | 2 | ||||
-rw-r--r-- | src/libcamera/include/log.h | 56 | ||||
-rw-r--r-- | src/libcamera/log.cpp | 193 |
3 files changed, 210 insertions, 41 deletions
diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in index dd74b729..b78fb3a0 100644 --- a/Documentation/Doxyfile.in +++ b/Documentation/Doxyfile.in @@ -2050,7 +2050,7 @@ INCLUDE_FILE_PATTERNS = *.h # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = +PREDEFINED = __DOXYGEN__ # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/src/libcamera/include/log.h b/src/libcamera/include/log.h index cc3f9404..ad8f8452 100644 --- a/src/libcamera/include/log.h +++ b/src/libcamera/include/log.h @@ -19,26 +19,74 @@ enum LogSeverity { LogFatal, }; +class LogCategory +{ +public: + explicit LogCategory(const char *name); + ~LogCategory(); + + const char *name() const { return name_; } + LogSeverity severity() const { return severity_; } + void setSeverity(LogSeverity severity); + + static const LogCategory &defaultCategory(); + +private: + const char *name_; + LogSeverity severity_; +}; + +#define LOG_DECLARE_CATEGORY(name) \ +extern const LogCategory &_LOG_CATEGORY(name)(); + +#define LOG_DEFINE_CATEGORY(name) \ +const LogCategory &_LOG_CATEGORY(name)() \ +{ \ + static LogCategory category(#name); \ + return category; \ +} + class LogMessage { public: LogMessage(const char *fileName, unsigned int line, LogSeverity severity); + LogMessage(const char *fileName, unsigned int line, + const LogCategory &category, LogSeverity severity); LogMessage(const LogMessage &) = delete; ~LogMessage(); - std::ostream &stream() { return msgStream; } + std::ostream &stream() { return msgStream_; } private: - std::ostringstream msgStream; + void init(const char *fileName, unsigned int line); + + std::ostringstream msgStream_; + const LogCategory &category_; LogSeverity severity_; }; -#define LOG(severity) LogMessage(__FILE__, __LINE__, Log##severity).stream() +#ifndef __DOXYGEN__ +#define _LOG_CATEGORY(name) logCategory##name + +#define _LOG1(severity) \ + LogMessage(__FILE__, __LINE__, Log##severity).stream() +#define _LOG2(category, severity) \ + LogMessage(__FILE__, __LINE__, _LOG_CATEGORY(category)(), Log##severity).stream() + +/* + * Expand the LOG() macro to _LOG1() or _LOG2() based on the number of + * arguments. + */ +#define _LOG_MACRO(_1, _2, NAME, ...) NAME +#define LOG(...) _LOG_MACRO(__VA_ARGS__, _LOG2, _LOG1)(__VA_ARGS__) +#else /* __DOXYGEN___ */ +#define LOG(category, severity) +#endif /* __DOXYGEN__ */ #ifndef NDEBUG #define ASSERT(condition) static_cast<void>(({ \ - if (!(condition)) \ + if (!(condition)) \ LOG(Fatal) << "assertion \"" #condition "\" failed"; \ })) #else diff --git a/src/libcamera/log.cpp b/src/libcamera/log.cpp index 74cba383..20503fdc 100644 --- a/src/libcamera/log.cpp +++ b/src/libcamera/log.cpp @@ -37,32 +37,64 @@ namespace libcamera { */ /** - * \def LOG(severity) - * \brief Log a message - * - * Return an std::ostream reference to which a message can be logged using the - * iostream API. The \a severity controls whether the message is printed or - * dropped, depending on the global log level. + * \class LogCategory + * \brief A category of log message * - * If the severity is set to Fatal, execution is aborted and the program - * terminates immediately after printing the message. + * The LogCategory class represents a category of log messages, related to an + * area of the library. It groups all messages belonging to the same category, + * and is used to control the log level per group. */ /** - * \def ASSERT(condition) - * \brief Abort program execution if assertion fails + * \brief Construct a log category + * \param[in] name The category name + */ +LogCategory::LogCategory(const char *name) + : name_(name), severity_(LogSeverity::LogInfo) +{ +} + +LogCategory::~LogCategory() +{ +} + +/** + * \fn LogCategory::name() + * \brief Retrieve the log category name + * \return The log category name + */ + +/** + * \fn LogCategory::severity() + * \brief Retrieve the severity of the log category + * \sa setSeverity() + * \return Return the severity of the log category + */ + +/** + * \brief Set the severity of the log category * - * If \a condition is false, ASSERT() logs an error message with the Fatal log - * level and aborts program execution. + * Messages of severity higher than or equal to the severity of the log category + * are printed, other messages are discarded. + */ +void LogCategory::setSeverity(LogSeverity severity) +{ + severity_ = severity; +} + +/** + * \brief Retrieve the default log category * - * If the macro NDEBUG is defined before including log.h, ASSERT() generates no - * code. + * The default log category is named "default" and is used by the LOG() macro + * when no log category is specified. * - * Using conditions that have side effects with ASSERT() is not recommended, as - * these effects would depend on whether NDEBUG is defined or not. Similarly, - * ASSERT() should not be used to check for errors that can occur under normal - * conditions as those checks would then be removed when compiling with NDEBUG. + * \return A pointer to the default log category */ +const LogCategory &LogCategory::defaultCategory() +{ + static LogCategory category("default"); + return category; +} static const char *log_severity_name(LogSeverity severity) { @@ -90,10 +122,11 @@ static const char *log_severity_name(LogSeverity severity) */ /** - * \param fileName The file name where the message is logged from - * \param line The line number where the message is logged from - * \param severity The log message severity, controlling how the message will be - * displayed + * \brief Construct a log message for the default category + * \param[in] fileName The file name where the message is logged from + * \param[in] line The line number where the message is logged from + * \param[in] severity The log message severity, controlling how the message + * will be displayed * * Create a log message pertaining to line \a line of file \a fileName. The * \a severity argument sets the message severity to control whether it will be @@ -101,29 +134,57 @@ static const char *log_severity_name(LogSeverity severity) */ LogMessage::LogMessage(const char *fileName, unsigned int line, LogSeverity severity) - : severity_(severity) + : category_(LogCategory::defaultCategory()), severity_(severity) +{ + init(fileName, line); +} + +/** + * \brief Construct a log message for a given category + * \param[in] fileName The file name where the message is logged from + * \param[in] line The line number where the message is logged from + * \param[in] category The log message category, controlling how the message + * will be displayed + * \param[in] severity The log message severity, controlling how the message + * will be displayed + * + * Create a log message pertaining to line \a line of file \a fileName. The + * \a severity argument sets the message severity to control whether it will be + * output or dropped. + */ +LogMessage::LogMessage(const char *fileName, unsigned int line, + const LogCategory &category, LogSeverity severity) + : category_(category), severity_(severity) +{ + init(fileName, line); +} + +void LogMessage::init(const char *fileName, unsigned int line) { /* Log the timestamp, severity and file information. */ struct timespec timestamp; clock_gettime(CLOCK_MONOTONIC, ×tamp); - msgStream.fill('0'); - msgStream << "[" << timestamp.tv_sec / (60 * 60) << ":" - << std::setw(2) << (timestamp.tv_sec / 60) % 60 << ":" - << std::setw(2) << timestamp.tv_sec % 60 << "." - << std::setw(9) << timestamp.tv_nsec << "]"; - msgStream.fill(' '); - - msgStream << " " << log_severity_name(severity); - msgStream << " " << basename(fileName) << ":" << line << " "; + msgStream_.fill('0'); + msgStream_ << "[" << timestamp.tv_sec / (60 * 60) << ":" + << std::setw(2) << (timestamp.tv_sec / 60) % 60 << ":" + << std::setw(2) << timestamp.tv_sec % 60 << "." + << std::setw(9) << timestamp.tv_nsec << "]"; + msgStream_.fill(' '); + + msgStream_ << " " << log_severity_name(severity_); + msgStream_ << " " << category_.name(); + msgStream_ << " " << basename(fileName) << ":" << line << " "; } LogMessage::~LogMessage() { - msgStream << std::endl; + msgStream_ << std::endl; - std::string msg(msgStream.str()); - fwrite(msg.data(), msg.size(), 1, stderr); - fflush(stderr); + if (severity_ >= category_.severity()) { + std::string msg(msgStream_.str()); + fwrite(msg.data(), msg.size(), 1, stderr); + fflush(stderr); + } if (severity_ == LogSeverity::LogFatal) std::abort(); @@ -139,4 +200,64 @@ LogMessage::~LogMessage() * \return A reference to the log message stream */ +/** + * \def LOG_DECLARE_CATEGORY(name) + * \hideinitializer + * \brief Declare a category of log messages + * + * This macro is used to declare a log category defined in another compilation + * unit by the LOG_DEFINE_CATEGORY() macro. + * + * The LOG_DECLARE_CATEGORY() macro must be used in the libcamera namespace. + * + * \sa LogCategory + */ + +/** + * \def LOG_DEFINE_CATEGORY(name) + * \hideinitializer + * \brief Define a category of log messages + * + * This macro is used to define a log category that can then be used with the + * LOGC() macro. Category names shall be unique, if a category is shared between + * compilation units, it shall be defined in one compilation unit only and + * declared with LOG_DECLARE_CATEGORY() in the other compilation units. + * + * The LOG_DEFINE_CATEGORY() macro must be used in the libcamera namespace. + * + * \sa LogCategory + */ + +/** + * \def LOG(category, severity) + * \hideinitializer + * \brief Log a message + * \param[in] category Category (optional) + * \param[in] severity Severity + * + * Return an std::ostream reference to which a message can be logged using the + * iostream API. The \a category, if specified, sets the message category. When + * absent the default category is used. The \a severity controls whether the + * message is printed or discarded, depending on the log level for the category. + * + * If the severity is set to Fatal, execution is aborted and the program + * terminates immediately after printing the message. + */ + +/** + * \def ASSERT(condition) + * \brief Abort program execution if assertion fails + * + * If \a condition is false, ASSERT() logs an error message with the Fatal log + * level and aborts program execution. + * + * If the macro NDEBUG is defined before including log.h, ASSERT() generates no + * code. + * + * Using conditions that have side effects with ASSERT() is not recommended, as + * these effects would depend on whether NDEBUG is defined or not. Similarly, + * ASSERT() should not be used to check for errors that can occur under normal + * conditions as those checks would then be removed when compiling with NDEBUG. + */ + } /* namespace libcamera */ |