@@ -19,26 +19,63 @@ 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_CATEGORY(name) logCategory##name
+
+#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()
+#define LOG(severity) \
+ LogMessage(__FILE__, __LINE__, Log##severity).stream()
+#define LOGC(category, severity) \
+ LogMessage(__FILE__, __LINE__, LOG_CATEGORY(category)(), Log##severity).stream()
#ifndef NDEBUG
#define ASSERT(condition) static_cast<void>(({ \
- if (!(condition)) \
+ if (!(condition)) \
LOG(Fatal) << "assertion \"" #condition "\" failed"; \
}))
#else
@@ -37,32 +37,64 @@ namespace libcamera {
*/
/**
- * \def LOG(severity)
- * \brief Log a message
+ * \class LogCategory
+ * \brief A category of log 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.
- *
- * 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,88 @@ LogMessage::~LogMessage()
* \return A reference to the log message stream
*/
+/**
+ * \def LOG_CATEGORY(name)
+ * \brief Name of the log category symbol for a category name
+ */
+
+/**
+ * \def LOG_DECLARE_CATEGORY(name)
+ * \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_DECLARE_CATEGORY(name)
+ * \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)
+ * \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(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
+ * discarded, depending on the global log level.
+ *
+ * If the severity is set to Fatal, execution is aborted and the program
+ * terminates immediately after printing the message.
+ */
+
+/**
+ * \def LOGC(category, severity)
+ * \brief Log a message with a category
+ *
+ * Return an std::ostream reference to which a message can be logged using the
+ * iostream API. The \a category and \a severity controls whether the message is
+ * printed or discarded, depending on if the \a category is enabled and on the
+ * log level for the \a 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 */
Log categories are used to group log messages by topic. Introduce support for categories with a new LOGC() macro. Support for configuring log level per category will be introduced in a subsequent commit. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> --- src/libcamera/include/log.h | 45 +++++++- src/libcamera/log.cpp | 217 ++++++++++++++++++++++++++++++------ 2 files changed, 222 insertions(+), 40 deletions(-)