From patchwork Mon Jan 21 00:59:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 284 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 08C5260C9F for ; Mon, 21 Jan 2019 01:59:36 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 9C662D6C for ; Mon, 21 Jan 2019 01:59:35 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1548032375; bh=IWMcIicodphicWjbxTgofq5QSAykrLw6+S//uFpipas=; h=From:To:Subject:Date:In-Reply-To:References:From; b=pTRSy28Y4if1a4OgJCvcM9QFQ1phrljyt4ElTafB6GAVn78FYAhe+utb3s7ujKn8B yqnHpincx+hw7pwxDl/NEzRzchDR5MzxeaKN7cFHhbyQvDabCMvcM58qLyfgvHj/4c eGr7Y+ADbsLKDIlewXIWfnd9hdz3HQwN/n08+azY= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 21 Jan 2019 02:59:28 +0200 Message-Id: <20190121005930.10112-5-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20190121005930.10112-1-laurent.pinchart@ideasonboard.com> References: <20190121005930.10112-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 4/6] libcamera: log: Get log levels from the environment X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 21 Jan 2019 00:59:37 -0000 Set the log level for each log category from the environment variable LIBCAMERA_LOG_LEVELS. The variable contains a comma-separated list of category:level pairs, and category names can include wildcards. Signed-off-by: Laurent Pinchart --- src/libcamera/log.cpp | 202 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) diff --git a/src/libcamera/log.cpp b/src/libcamera/log.cpp index 8f3d1c181245..143029f19826 100644 --- a/src/libcamera/log.cpp +++ b/src/libcamera/log.cpp @@ -9,7 +9,9 @@ #include #include #include +#include #include +#include #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 categories_; + std::list> 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(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(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 &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); } /**