summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2021-02-03 19:17:46 +0100
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2022-06-06 15:09:42 +0300
commit575703894624306950c0540182afc48ba3732f8c (patch)
tree79970d8e30a48c3455cd80399690bb0993b3f610
parent7ee7dc3369ebf26d142b6352cb3d309f48600433 (diff)
libcamera: base: log: Add coloring to the log output
Extend the logger to support coloring messages. The log level is colorized with per-level colors, and the category with a fixed color. This makes the log output more readable. Coloring is enabled by default when logging to std::cerr, and can be disabled by setting the LIBCAMERA_LOG_NO_COLOR environment variable. When logging to a file with LIBCAMERA_LOG_FILE, coloring is disabled. It can be enabled for file logging using the logSetFile() function. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Umang Jain <umang.jain@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
-rw-r--r--Documentation/environment_variables.rst21
-rw-r--r--include/libcamera/logging.h4
-rw-r--r--src/libcamera/base/log.cpp110
3 files changed, 104 insertions, 31 deletions
diff --git a/Documentation/environment_variables.rst b/Documentation/environment_variables.rst
index fa703a72..0a7760cb 100644
--- a/Documentation/environment_variables.rst
+++ b/Documentation/environment_variables.rst
@@ -19,6 +19,9 @@ LIBCAMERA_LOG_LEVELS
Example value: ``*:DEBUG``
+LIBCAMERA_LOG_NO_COLOR
+ Disable coloring of log messages (`more <Notes about debugging_>`__).
+
LIBCAMERA_IPA_CONFIG_PATH
Define custom search locations for IPA configurations (`more <IPA configuration_>`__).
@@ -40,12 +43,20 @@ Further details
Notes about debugging
~~~~~~~~~~~~~~~~~~~~~
-The environment variables ``LIBCAMERA_LOG_FILE`` and ``LIBCAMERA_LOG_LEVELS``
-are used to modify the destination and verbosity of messages provided by
-libcamera.
+The environment variables ``LIBCAMERA_LOG_FILE``, ``LIBCAMERA_LOG_LEVELS`` and
+``LIBCAMERA_LOG_NO_COLOR`` are used to modify the default configuration of the
+libcamera logger.
+
+By default, libcamera logs all messages to the standard error (std::cerr).
+Messages are colored by default depending on the log level. Coloring can be
+disabled by setting the ``LIBCAMERA_LOG_NO_COLOR`` environment variable.
+
+The default log destination can also be directed to a file by setting the
+``LIBCAMERA_LOG_FILE`` environment variable to the log file name. This also
+disables coloring.
-The ``LIBCAMERA_LOG_LEVELS`` variable accepts a comma-separated list of
-'category:level' pairs.
+Log levels are controlled through the ``LIBCAMERA_LOG_LEVELS`` variable, which
+accepts a comma-separated list of 'category:level' pairs.
The `level <Log levels_>`__ part is mandatory and can either be specified by
name or by numerical index associated with each level.
diff --git a/include/libcamera/logging.h b/include/libcamera/logging.h
index c36882b9..cd842f67 100644
--- a/include/libcamera/logging.h
+++ b/include/libcamera/logging.h
@@ -16,8 +16,8 @@ enum LoggingTarget {
LoggingTargetStream,
};
-int logSetFile(const char *path);
-int logSetStream(std::ostream *stream);
+int logSetFile(const char *path, bool color = false);
+int logSetStream(std::ostream *stream, bool color = false);
int logSetTarget(LoggingTarget target);
void logSetLevel(const char *category, const char *level);
diff --git a/src/libcamera/base/log.cpp b/src/libcamera/base/log.cpp
index 26f14207..eefdda4b 100644
--- a/src/libcamera/base/log.cpp
+++ b/src/libcamera/base/log.cpp
@@ -104,8 +104,8 @@ static const char *log_severity_name(LogSeverity severity)
class LogOutput
{
public:
- LogOutput(const char *path);
- LogOutput(std::ostream *stream);
+ LogOutput(const char *path, bool color);
+ LogOutput(std::ostream *stream, bool color);
LogOutput();
~LogOutput();
@@ -119,14 +119,16 @@ private:
std::ostream *stream_;
LoggingTarget target_;
+ bool color_;
};
/**
* \brief Construct a log output based on a file
* \param[in] path Full path to log file
+ * \param[in] color True to output colored messages
*/
-LogOutput::LogOutput(const char *path)
- : target_(LoggingTargetFile)
+LogOutput::LogOutput(const char *path, bool color)
+ : target_(LoggingTargetFile), color_(color)
{
stream_ = new std::ofstream(path);
}
@@ -134,9 +136,10 @@ LogOutput::LogOutput(const char *path)
/**
* \brief Construct a log output based on a stream
* \param[in] stream Stream to send log output to
+ * \param[in] color True to output colored messages
*/
-LogOutput::LogOutput(std::ostream *stream)
- : stream_(stream), target_(LoggingTargetStream)
+LogOutput::LogOutput(std::ostream *stream, bool color)
+ : stream_(stream), target_(LoggingTargetStream), color_(color)
{
}
@@ -144,7 +147,7 @@ LogOutput::LogOutput(std::ostream *stream)
* \brief Construct a log output to syslog
*/
LogOutput::LogOutput()
- : stream_(nullptr), target_(LoggingTargetSyslog)
+ : stream_(nullptr), target_(LoggingTargetSyslog), color_(false)
{
openlog("libcamera", LOG_PID, 0);
}
@@ -179,28 +182,66 @@ bool LogOutput::isValid() const
}
}
+namespace {
+
+/*
+ * For more information about ANSI escape codes, see
+ * https://en.wikipedia.org/wiki/ANSI_escape_code#Colors.
+ */
+constexpr const char *kColorReset = "\033[0m";
+constexpr const char *kColorBrightRed = "\033[1;31m";
+constexpr const char *kColorBrightGreen = "\033[1;32m";
+constexpr const char *kColorBrightYellow = "\033[1;33m";
+constexpr const char *kColorBrightBlue = "\033[1;34m";
+constexpr const char *kColorBrightMagenta = "\033[1;35m";
+constexpr const char *kColorBrightCyan = "\033[1;36m";
+constexpr const char *kColorBrightWhite = "\033[1;37m";
+
+} /* namespace */
+
/**
* \brief Write message to log output
* \param[in] msg Message to write
*/
void LogOutput::write(const LogMessage &msg)
{
+ static const char *const severityColors[] = {
+ kColorBrightCyan,
+ kColorBrightGreen,
+ kColorBrightYellow,
+ kColorBrightRed,
+ kColorBrightMagenta,
+ };
+
+ const char *categoryColor = color_ ? kColorBrightWhite : "";
+ const char *fileColor = color_ ? kColorBrightBlue : "";
+ const char *resetColor = color_ ? kColorReset : "";
+ const char *severityColor = "";
+ LogSeverity severity = msg.severity();
std::string str;
+ if (color_) {
+ if (static_cast<unsigned int>(severity) < std::size(severityColors))
+ severityColor = severityColors[severity];
+ else
+ severityColor = kColorBrightWhite;
+ }
+
switch (target_) {
case LoggingTargetSyslog:
- str = std::string(log_severity_name(msg.severity())) + " "
+ str = std::string(log_severity_name(severity)) + " "
+ msg.category().name() + " " + msg.fileInfo() + " "
+ msg.msg();
- writeSyslog(msg.severity(), str);
+ writeSyslog(severity, str);
break;
case LoggingTargetStream:
case LoggingTargetFile:
str = "[" + utils::time_point_to_string(msg.timestamp()) + "] ["
+ std::to_string(Thread::currentId()) + "] "
- + log_severity_name(msg.severity()) + " "
- + msg.category().name() + " " + msg.fileInfo() + " "
- + msg.msg();
+ + severityColor + log_severity_name(severity) + " "
+ + categoryColor + msg.category().name() + " "
+ + fileColor + msg.fileInfo() + " "
+ + resetColor + msg.msg();
writeStream(str);
break;
default:
@@ -253,8 +294,8 @@ public:
void write(const LogMessage &msg);
void backtrace();
- int logSetFile(const char *path);
- int logSetStream(std::ostream *stream);
+ int logSetFile(const char *path, bool color);
+ int logSetStream(std::ostream *stream, bool color);
int logSetTarget(LoggingTarget target);
void logSetLevel(const char *category, const char *level);
@@ -298,35 +339,47 @@ bool Logger::destroyed_ = false;
/**
* \brief Direct logging to a file
* \param[in] path Full path to the log file
+ * \param[in] color True to output colored messages
*
* This function directs the log output to the file identified by \a path. The
* previous log target, if any, is closed, and all new log messages will be
* written to the new log file.
*
+ * \a color controls whether or not the messages will be colored with standard
+ * ANSI escape codes. This is done regardless of whether \a path refers to a
+ * standard file or a TTY, the caller is responsible for disabling coloring when
+ * not suitable for the log target.
+ *
* If the function returns an error, the log target is not changed.
*
* \return Zero on success, or a negative error code otherwise
*/
-int logSetFile(const char *path)
+int logSetFile(const char *path, bool color)
{
- return Logger::instance()->logSetFile(path);
+ return Logger::instance()->logSetFile(path, color);
}
/**
* \brief Direct logging to a stream
* \param[in] stream Stream to send log output to
+ * \param[in] color True to output colored messages
*
* This function directs the log output to \a stream. The previous log target,
* if any, is closed, and all new log messages will be written to the new log
* stream.
*
+ * \a color controls whether or not the messages will be colored with standard
+ * ANSI escape codes. This is done regardless of whether \a stream refers to a
+ * standard file or a TTY, the caller is responsible for disabling coloring when
+ * not suitable for the log target.
+ *
* If the function returns an error, the log file is not changed
*
* \return Zero on success, or a negative error code otherwise.
*/
-int logSetStream(std::ostream *stream)
+int logSetStream(std::ostream *stream, bool color)
{
- return Logger::instance()->logSetStream(stream);
+ return Logger::instance()->logSetStream(stream, color);
}
/**
@@ -437,14 +490,16 @@ void Logger::backtrace()
/**
* \brief Set the log file
* \param[in] path Full path to the log file
+ * \param[in] color True to output colored messages
*
* \sa libcamera::logSetFile()
*
* \return Zero on success, or a negative error code otherwise.
*/
-int Logger::logSetFile(const char *path)
+int Logger::logSetFile(const char *path, bool color)
{
- std::shared_ptr<LogOutput> output = std::make_shared<LogOutput>(path);
+ std::shared_ptr<LogOutput> output =
+ std::make_shared<LogOutput>(path, color);
if (!output->isValid())
return -EINVAL;
@@ -455,14 +510,16 @@ int Logger::logSetFile(const char *path)
/**
* \brief Set the log stream
* \param[in] stream Stream to send log output to
+ * \param[in] color True to output colored messages
*
* \sa libcamera::logSetStream()
*
* \return Zero on success, or a negative error code otherwise.
*/
-int Logger::logSetStream(std::ostream *stream)
+int Logger::logSetStream(std::ostream *stream, bool color)
{
- std::shared_ptr<LogOutput> output = std::make_shared<LogOutput>(stream);
+ std::shared_ptr<LogOutput> output =
+ std::make_shared<LogOutput>(stream, color);
std::atomic_store(&output_, output);
return 0;
}
@@ -514,10 +571,15 @@ void Logger::logSetLevel(const char *category, const char *level)
/**
* \brief Construct a logger
+ *
+ * If the environment variable is not set, log to std::cerr. The log messages
+ * are then colored by default. This can be overridden by setting the
+ * LIBCAMERA_LOG_NO_COLOR environment variable to disable coloring.
*/
Logger::Logger()
{
- logSetStream(&std::cerr);
+ bool color = !utils::secure_getenv("LIBCAMERA_LOG_NO_COLOR");
+ logSetStream(&std::cerr, color);
parseLogFile();
parseLogLevels();
@@ -543,7 +605,7 @@ void Logger::parseLogFile()
return;
}
- logSetFile(file);
+ logSetFile(file, false);
}
/**