[libcamera-devel] [PATCH v2 2/4] libcamera: log: Get log levels from the environment
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Tue Jan 22 15:22:18 CET 2019
Hi Jacopo,
On Tue, Jan 22, 2019 at 09:46:34AM +0100, Jacopo Mondi wrote:
> On Mon, Jan 21, 2019 at 09:56:04PM +0200, Laurent Pinchart wrote:
> > Set the log level for each log category from the environment variable
> > LIBCAMERA_LOG_LEVELS.
>
> Very nice indeed, but aren't log level numbers supposed to be used the
> other way around?
>
> Right now LIBCAMERA_LOG_LEVELS=0 is "DEBUG" and LIBCAMERA_LOG_LEVELS=4
> is "FATAL" only. I would have expect to have 4 = maximum debug, 0 =
> only fatal, right now is the other way around...
Patches are welcome :-) I don't mind handling numerical values the other
way around. Make sure that, whatever you do, you don't allow disabling
Fatal messages, those should always be preinted.
> Also, stupid thing but, isn't LIBCAMERA_LOG_LEVELS a bit long?
> gstreamer has a more compact GST_DBG which is shorter to type...
> LIBCAM_DBG maybe?
I think it's GST_DEBUG in gstreamer. I initially went with
LIBCAMERA_DEBUG, but having a common prefix for all log-related
environment variables also has value.
> The patch itself is good, please add my
> Reviewed-by: Jacopo Mondi <jacopo at jmondi.org>
>
> > The variable contains a comma-separated list of category:level pairs,
> > and category names can include wildcards.
> >
> > Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> > ---
> > src/libcamera/log.cpp | 202 ++++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 202 insertions(+)
> >
> > diff --git a/src/libcamera/log.cpp b/src/libcamera/log.cpp
> > index 20503fdcfcc1..23bb9edb9d14 100644
> > --- a/src/libcamera/log.cpp
> > +++ b/src/libcamera/log.cpp
> > @@ -9,7 +9,9 @@
> > #include <cstdlib>
> > #include <ctime>
> > #include <iomanip>
> > +#include <list>
> > #include <string.h>
> > +#include <unordered_set>
> >
> > #include "log.h"
> > #include "utils.h"
> > @@ -17,10 +19,208 @@
> > /**
> > * \file log.h
> > * \brief Logging infrastructure
> > + *
> > + * libcamera includes a logging infrastructure used through the library that
> > + * allows inspection of internal operation in a user-configurable way. The log
> > + * messages are grouped in categories that represent areas of libcamera, and
> > + * output of messages for each category can be controlled by independent log
> > + * levels.
> > + *
> > + * The levels are configurable through the LIBCAMERA_LOG_LEVELS environment
> > + * variable that contains a comma-separated list of 'category=level' pairs.
> > + *
> > + * The category names are strings and can include a wildcard ('*') character at
> > + * the end to match multiple categories.
> > + *
> > + * The level are either numeric values, or strings containing the log level
> > + * name. The available log levels are DEBUG, INFO, WARN, ERROR and FATAL. Log
> > + * message with a level higher than or equal to the configured log level for
> > + * their category are output to the log, while other messages are silently
> > + * discarded.
> > */
> >
> > namespace libcamera {
> >
> > +/**
> > + * \brief Message logger
> > + *
> > + * The Logger class handles log configuration.
> > + */
> > +class Logger
> > +{
> > +public:
> > + static Logger *instance();
> > +
> > +private:
> > + Logger();
> > +
> > + void parseLogLevels();
> > + static LogSeverity parseLogLevel(const std::string &level);
> > +
> > + friend LogCategory;
> > + void registerCategory(LogCategory *category);
> > + void unregisterCategory(LogCategory *category);
> > +
> > + std::unordered_set<LogCategory *> categories_;
> > + std::list<std::pair<std::string, LogSeverity>> levels_;
> > +};
> > +
> > +/**
> > + * \brief Retrieve the logger instance
> > + *
> > + * The Logger is a singleton and can't be constructed manually. This function
> > + * shall instead be used to retrieve the single global instance of the logger.
> > + *
> > + * \return The logger instance
> > + */
> > +Logger *Logger::instance()
> > +{
> > + static Logger instance;
> > + return &instance;
> > +}
> > +
> > +/**
> > + * \brief Construct a logger
> > + */
> > +Logger::Logger()
> > +{
> > + parseLogLevels();
> > +}
> > +
> > +/**
> > + * \brief Parse the log levels from the environment
> > + *
> > + * The logr levels are stored in LIBCAMERA_LOG_LEVELS environement variable as a list
> > + * of "category=level" pairs, separated by commas (','). Parse the variable and
> > + * store the levels to configure all log categories.
> > + */
> > +void Logger::parseLogLevels()
> > +{
> > + const char *debug = secure_getenv("LIBCAMERA_LOG_LEVELS");
> > + if (!debug)
> > + return;
> > +
> > + for (const char *pair = debug; *debug != '\0'; pair = debug) {
> > + const char *comma = strchrnul(debug, ',');
> > + size_t len = comma - pair;
> > +
> > + /* Skip over the comma. */
> > + debug = *comma == ',' ? comma + 1 : comma;
> > +
> > + /* Skip to the next pair if the pair is empty. */
> > + if (!len)
> > + continue;
> > +
> > + std::string category;
> > + std::string level;
> > +
> > + const char *colon = static_cast<const char *>(memchr(pair, ':', len));
> > + if (!colon) {
> > + /* 'x' is a shortcut for '*:x'. */
> > + category = "*";
> > + level = std::string(pair, len);
> > + } else {
> > + category = std::string(pair, colon - pair);
> > + level = std::string(colon + 1, comma - colon - 1);
> > + }
> > +
> > + /* Both the category and the level must be specified. */
> > + if (category.empty() || level.empty())
> > + continue;
> > +
> > + LogSeverity severity = parseLogLevel(level);
> > + if (severity == -1)
> > + continue;
> > +
> > + levels_.push_back({ category, severity });
> > + }
> > +}
> > +
> > +/**
> > + * \brief Parse a log level string into a LogSeverity
> > + * \param[in] level The log level string
> > + *
> > + * Log levels can be specified as an integer value in the range from LogDebug to
> > + * LogFatal, or as a string corresponding to the severity name in uppercase. Any
> > + * other value is invalid.
> > + *
> > + * \return The log severity, or -1 if the string is invalid
> > + */
> > +LogSeverity Logger::parseLogLevel(const std::string &level)
> > +{
> > + static const char *const names[] = {
> > + "DEBUG",
> > + "INFO",
> > + "WARN",
> > + "ERROR",
> > + "FATAL",
> > + };
> > +
> > + int severity;
> > +
> > + if (std::isdigit(level[0])) {
> > + char *endptr;
> > + severity = strtoul(level.c_str(), &endptr, 10);
> > + if (*endptr != '\0' || severity > LogFatal)
> > + severity = -1;
> > + } else {
> > + severity = -1;
> > + for (unsigned int i = 0; i < ARRAY_SIZE(names); ++i) {
> > + if (names[i] == level) {
> > + severity = i;
> > + break;
> > + }
> > + }
> > + }
> > +
> > + return static_cast<LogSeverity>(severity);
> > +}
> > +
> > +/**
> > + * \brief Register a log category with the logger
> > + * \param[in] category The log category
> > + *
> > + * Log categories must have unique names. If a category with the same name
> > + * already exists this function performs no operation.
> > + */
> > +void Logger::registerCategory(LogCategory *category)
> > +{
> > + categories_.insert(category);
> > +
> > + const std::string &name = category->name();
> > + for (const std::pair<std::string, LogSeverity> &level : levels_) {
> > + bool match = true;
> > +
> > + for (unsigned int i = 0; i < level.first.size(); ++i) {
> > + if (level.first[i] == '*')
> > + break;
> > +
> > + if (i >= name.size() ||
> > + name[i] != level.first[i]) {
> > + match = false;
> > + break;
> > + }
> > + }
> > +
> > + if (match) {
> > + category->setSeverity(level.second);
> > + break;
> > + }
> > + }
> > +}
> > +
> > +/**
> > + * \brief Unregister a log category from the logger
> > + * \param[in] category The log category
> > + *
> > + * If the \a category hasn't been registered with the logger this function
> > + * performs no operation.
> > + */
> > +void Logger::unregisterCategory(LogCategory *category)
> > +{
> > + categories_.erase(category);
> > +}
> > +
> > /**
> > * \enum LogSeverity
> > * Log message severity
> > @@ -52,10 +252,12 @@ namespace libcamera {
> > LogCategory::LogCategory(const char *name)
> > : name_(name), severity_(LogSeverity::LogInfo)
> > {
> > + Logger::instance()->registerCategory(this);
> > }
> >
> > LogCategory::~LogCategory()
> > {
> > + Logger::instance()->unregisterCategory(this);
> > }
> >
> > /**
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list