From patchwork Mon Jan 21 00:59:25 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 281 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 23F3560C82 for ; Mon, 21 Jan 2019 01:59:35 +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 B2487D80 for ; Mon, 21 Jan 2019 01:59:34 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1548032374; bh=JHXITrYgTIpvNyao7vFSpf4PhKqGA7PwqPtbJzNUobg=; h=From:To:Subject:Date:In-Reply-To:References:From; b=IM/9jJAXLtixLO9ffmFis5z5Qa4t6sRvyTNYDFlh3CEbV71tVMUzrgBhrLQjpunxH 92ihGhc8jXQZ+wxqpAkwaRhA5eZ/98La2KErcO3txjiYef5sYATSfwZEOAW0gz0ndb RnAnZZDj6bciYUaPQmVvxrc8P9YpLA3uoa3g2FGg= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 21 Jan 2019 02:59:25 +0200 Message-Id: <20190121005930.10112-2-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 1/6] Documentation: coding_style: Add move semantics to C++11 features 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:35 -0000 Add the move semantics (move constructor and move assignment) to the allowed C++11 features, as we extensively use them for the unique and shared pointers. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- Documentation/coding-style.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/coding-style.rst b/Documentation/coding-style.rst index 66db3cebe132..30a1455d8c65 100644 --- a/Documentation/coding-style.rst +++ b/Documentation/coding-style.rst @@ -80,6 +80,7 @@ C++-11-specific features: Smart pointers, as well as shared pointers and weak pointers, shall not be overused. * Variadic class and function templates +* rvalue references, move constructor and move assignment Object Ownership ~~~~~~~~~~~~~~~~ From patchwork Mon Jan 21 00:59:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 282 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6A60F60C82 for ; Mon, 21 Jan 2019 01:59:35 +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 05F02D6C for ; Mon, 21 Jan 2019 01:59:34 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1548032375; bh=SSg+uD/M/Tn60iEfEpLbWzTa2ETlruAkJTBcXQAM2bA=; h=From:To:Subject:Date:In-Reply-To:References:From; b=pgW7ddT8EDuzdD+hSGPJ9/R5hUODYlxJo2/ZpVfGJZ6EZC8AchYo7OAmqAOyRUrro fkY/VtKH4Yyy0ASpgSZhDktnwe9KC5gVw8eTWEXNCdKZKeqmZvJkB4gDYYXEqvNRi5 A1sl2jLmcQa4iVEy8K4zP9Uee7LjbtQ+MbPr6yKg= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 21 Jan 2019 02:59:26 +0200 Message-Id: <20190121005930.10112-3-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 2/6] libcamera: signal: Enable documentation generation from signal.h file 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:35 -0000 signal.cpp is missing a \file signal.h Doxygen directive, preventing documentation from being generated for the Signal class. Fix it. Signed-off-by: Laurent Pinchart Acked-by: Jacopo Mondi Reviewed-by: Niklas Söderlund --- src/libcamera/signal.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libcamera/signal.cpp b/src/libcamera/signal.cpp index 51536dc5fdd0..8d62b5beeeac 100644 --- a/src/libcamera/signal.cpp +++ b/src/libcamera/signal.cpp @@ -5,6 +5,11 @@ * signal.cpp - Signal & slot implementation */ +/** + * \file signal.h + * \brief Signal & slot implementation + */ + namespace libcamera { /** From patchwork Mon Jan 21 00:59:27 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 283 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AFA3F60C82 for ; Mon, 21 Jan 2019 01:59:35 +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 4E2B8D80 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=mEuK0o21xBH6Uqfcuz+k921mCyRQmJY5dm7UkPI1dl8=; h=From:To:Subject:Date:In-Reply-To:References:From; b=kDtY3MpO/0Euag3EzHI+eHspAxDXsLBzySJRWho9izCWzv8yZ4+HJl9IkImmz+ZFm JTkOXzzyB/exgjJ1oJ85M8qhWYjoDwbf+SDI3l2b+nVqyp1YHXq+k2fNFqwpezQafj iCQB4TNkpEPysd6d+3Bx+OMNyghp9n+BD3teZyGQ= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 21 Jan 2019 02:59:27 +0200 Message-Id: <20190121005930.10112-4-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 3/6] libcamera: log: Add log categories 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:36 -0000 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 --- src/libcamera/include/log.h | 45 +++++++- src/libcamera/log.cpp | 217 ++++++++++++++++++++++++++++++------ 2 files changed, 222 insertions(+), 40 deletions(-) diff --git a/src/libcamera/include/log.h b/src/libcamera/include/log.h index cc3f9404a3d4..c7644291724d 100644 --- a/src/libcamera/include/log.h +++ b/src/libcamera/include/log.h @@ -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(({ \ - if (!(condition)) \ + if (!(condition)) \ LOG(Fatal) << "assertion \"" #condition "\" failed"; \ })) #else diff --git a/src/libcamera/log.cpp b/src/libcamera/log.cpp index 74cba383363d..8f3d1c181245 100644 --- a/src/libcamera/log.cpp +++ b/src/libcamera/log.cpp @@ -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 */ 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); } /** From patchwork Mon Jan 21 00:59:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 285 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4DF8260C82 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 E40BAD80 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=1548032376; bh=vsAxlJR9u+NKGSOLJzHa2NWn1kqMCcBH9/tflkbD8zE=; h=From:To:Subject:Date:In-Reply-To:References:From; b=JosVeN9UQ2tvI/iQCj55jlIpXDDa2S+UMh+mm23XYFT4bkJONTGeLXBghsfNoggCP h9QUgJ+hm11pRTojq9SBu9wXGaGjR6z6k01X0ear6Snx0kD48ByIl2QH0fUBJ3TsCj J1JrqpUNrE2D7c3lmM5u4bjo1Q+sszFMpkzIlVeM= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 21 Jan 2019 02:59:29 +0200 Message-Id: <20190121005930.10112-6-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 5/6] libcamera: log: Get log output file 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 If the LIBCAMERA_LOG_FILE environment variable is set, open the file it points to and redirect the logger output to it. Signed-off-by: Laurent Pinchart --- src/libcamera/log.cpp | 47 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/src/libcamera/log.cpp b/src/libcamera/log.cpp index 143029f19826..805612d3e17e 100644 --- a/src/libcamera/log.cpp +++ b/src/libcamera/log.cpp @@ -8,7 +8,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -37,6 +39,12 @@ * 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. + * + * By default log messages are output to stderr. They can be redirected to a log + * file by setting the LIBCAMERA_LOG_FILE environment variable to the name of + * the file. The file must be writable and is truncated if it exists. If any + * error occurs when opening the file, the file is ignored and the log is output + * to stderr. */ namespace libcamera { @@ -51,9 +59,12 @@ class Logger public: static Logger *instance(); + void write(const std::string &msg); + private: Logger(); + void parseLogFile(); void parseLogLevels(); static LogSeverity parseLogLevel(const std::string &level); @@ -63,6 +74,9 @@ private: std::unordered_set categories_; std::list> levels_; + + std::ofstream file_; + std::ostream *output_; }; /** @@ -79,14 +93,44 @@ Logger *Logger::instance() return &instance; } +/** + * \brief Write a message to the configured logger output + * \param[in] msg The message string + */ +void Logger::write(const std::string &msg) +{ + output_->write(msg.c_str(), msg.size()); + output_->flush(); +} + /** * \brief Construct a logger */ Logger::Logger() + : output_(&std::cerr) { + parseLogFile(); parseLogLevels(); } +/** + * \brief Parse the log output file from the environment + * + * If the LIBCAMERA_LOG_FILE environment variable is set, open the file it + * points to and redirect the logger output to it. Errors are silently ignored + * and don't affect the logger output (set to stderr). + */ +void Logger::parseLogFile() +{ + const char *file = secure_getenv("LIBCAMERA_LOG_FILE"); + if (!file) + return; + + file_.open(file); + if (file_.good()) + output_ = &file_; +} + /** * \brief Parse the log levels from the environment * @@ -384,8 +428,7 @@ LogMessage::~LogMessage() if (severity_ >= category_.severity()) { std::string msg(msgStream_.str()); - fwrite(msg.data(), msg.size(), 1, stderr); - fflush(stderr); + Logger::instance()->write(msg); } if (severity_ == LogSeverity::LogFatal) From patchwork Mon Jan 21 00:59:30 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 286 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A316360CA2 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 3A14BD6C for ; Mon, 21 Jan 2019 01:59:36 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1548032376; bh=W4TNRPJjGe2m171Wr95ZskWWtBs9asvIaKg/wUicXtg=; h=From:To:Subject:Date:In-Reply-To:References:From; b=V+lZUm+PD4WK5HVY+9FbirkBoZUrKGDQw6x+AKjN2hVAC0hyf/z1yZrV+y0tZ9PiI QHkCFeeyYyPN7cH83jwi9f41WgGcHUR9PI6uZRIOedQz83jd3k4HkUiQmL+3gXleDa Itf8Y8YIJoaSgsSxeowYFr6dFNudGofVa6hHO5mY= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 21 Jan 2019 02:59:30 +0200 Message-Id: <20190121005930.10112-7-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 6/6] libcamera: Use log categories 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 Use log categories in all the existing code base. Signed-off-by: Laurent Pinchart --- src/libcamera/camera_manager.cpp | 14 +++++--- src/libcamera/device_enumerator.cpp | 25 ++++++++----- src/libcamera/event_dispatcher.cpp | 4 +++ src/libcamera/event_dispatcher_poll.cpp | 28 +++++++++------ src/libcamera/media_device.cpp | 48 ++++++++++++++----------- src/libcamera/media_object.cpp | 7 ++-- src/libcamera/pipeline_handler.cpp | 5 ++- src/libcamera/timer.cpp | 6 ++-- src/libcamera/v4l2_device.cpp | 25 +++++++------ 9 files changed, 102 insertions(+), 60 deletions(-) diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index d76eaa7ace86..f9085f45e331 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -21,6 +21,8 @@ namespace libcamera { +LOG_DEFINE_CATEGORY(Camera) + /** * \class CameraManager * \brief Provide access and manage all cameras in the system @@ -101,8 +103,9 @@ int CameraManager::start() break; } - LOG(Debug) << "Pipeline handler \"" << factory->name() - << "\" matched"; + LOGC(Camera, Debug) + << "Pipeline handler \"" << factory->name() + << "\" matched"; pipes_.push_back(pipe); } } @@ -176,8 +179,9 @@ void CameraManager::addCamera(std::shared_ptr camera) { for (std::shared_ptr c : cameras_) { if (c->name() == camera->name()) { - LOG(Warning) << "Registering camera with duplicate name '" - << camera->name() << "'"; + LOGC(Camera, Warning) + << "Registering camera with duplicate name '" + << camera->name() << "'"; break; } } @@ -216,7 +220,7 @@ CameraManager *CameraManager::instance() void CameraManager::setEventDispatcher(std::unique_ptr dispatcher) { if (dispatcher_) { - LOG(Warning) << "Event dispatcher is already set"; + LOGC(Camera, Warning) << "Event dispatcher is already set"; return; } diff --git a/src/libcamera/device_enumerator.cpp b/src/libcamera/device_enumerator.cpp index 55c510e3b79a..c2493e921e87 100644 --- a/src/libcamera/device_enumerator.cpp +++ b/src/libcamera/device_enumerator.cpp @@ -42,6 +42,8 @@ namespace libcamera { +LOG_DEFINE_CATEGORY(DeviceEnumerator) + /** * \class DeviceMatch * \brief Description of a media device search pattern @@ -155,7 +157,8 @@ DeviceEnumerator::~DeviceEnumerator() { for (MediaDevice *dev : devices_) { if (dev->busy()) - LOG(Error) << "Removing media device while still in use"; + LOGC(DeviceEnumerator, Error) + << "Removing media device while still in use"; delete dev; } @@ -205,13 +208,15 @@ int DeviceEnumerator::addDevice(const std::string &devnode) ret = media->populate(); if (ret < 0) { - LOG(Info) << "Unable to populate media device " << devnode << - " (" << strerror(-ret) << "), skipping"; + LOGC(DeviceEnumerator, Info) + << "Unable to populate media device " << devnode + << " (" << strerror(-ret) << "), skipping"; return ret; } - LOG(Debug) << "New media device \"" << media->driver() - << "\" created from " << devnode; + LOGC(DeviceEnumerator, Debug) + << "New media device \"" << media->driver() + << "\" created from " << devnode; /* Associate entities to device node paths. */ for (MediaEntity *entity : media->entities()) { @@ -251,8 +256,9 @@ MediaDevice *DeviceEnumerator::search(const DeviceMatch &dm) continue; if (dm.match(dev)) { - LOG(Debug) << "Successful match for media device \"" - << dev->driver() << "\""; + LOGC(DeviceEnumerator, Debug) + << "Successful match for media device \"" + << dev->driver() << "\""; return dev; } } @@ -330,8 +336,9 @@ int DeviceEnumeratorUdev::enumerate() dev = udev_device_new_from_syspath(udev_, syspath); if (!dev) { - LOG(Warning) << "Failed to get device for '" << - syspath << "', skipping"; + LOGC(DeviceEnumerator, Warning) + << "Failed to get device for '" + << syspath << "', skipping"; continue; } diff --git a/src/libcamera/event_dispatcher.cpp b/src/libcamera/event_dispatcher.cpp index 5462730214d6..f7c40734095e 100644 --- a/src/libcamera/event_dispatcher.cpp +++ b/src/libcamera/event_dispatcher.cpp @@ -7,12 +7,16 @@ #include +#include "log.h" + /** * \file event_dispatcher.h */ namespace libcamera { +LOG_DEFINE_CATEGORY(Event) + /** * \class EventDispatcher * \brief Interface to manage the libcamera events and timers diff --git a/src/libcamera/event_dispatcher_poll.cpp b/src/libcamera/event_dispatcher_poll.cpp index 2072ae0aa3da..14e98a788909 100644 --- a/src/libcamera/event_dispatcher_poll.cpp +++ b/src/libcamera/event_dispatcher_poll.cpp @@ -22,6 +22,8 @@ namespace libcamera { +LOG_DECLARE_CATEGORY(Event) + static const char *notifierType(EventNotifier::Type type) { if (type == EventNotifier::Read) @@ -53,8 +55,9 @@ void EventDispatcherPoll::registerEventNotifier(EventNotifier *notifier) EventNotifier::Type type = notifier->type(); if (set.notifiers[type] && set.notifiers[type] != notifier) { - LOG(Warning) << "Ignoring duplicate " << notifierType(type) - << " notifier for fd " << notifier->fd(); + LOGC(Event, Warning) + << "Ignoring duplicate " << notifierType(type) + << " notifier for fd " << notifier->fd(); return; } @@ -74,8 +77,9 @@ void EventDispatcherPoll::unregisterEventNotifier(EventNotifier *notifier) return; if (set.notifiers[type] != notifier) { - LOG(Warning) << notifierType(type) << " notifier for fd " - << notifier->fd() << " is not registered"; + LOGC(Event, Warning) + << notifierType(type) << " notifier for fd " + << notifier->fd() << " is not registered"; return; } @@ -141,9 +145,10 @@ void EventDispatcherPoll::processEvents() timeout.tv_nsec = 0; } - LOG(Debug) << "timeout " << timeout.tv_sec << "." - << std::setfill('0') << std::setw(9) - << timeout.tv_nsec; + LOGC(Event, Debug) + << "timeout " << timeout.tv_sec << "." + << std::setfill('0') << std::setw(9) + << timeout.tv_nsec; } /* Wait for events and process notifiers and timers. */ @@ -151,7 +156,7 @@ void EventDispatcherPoll::processEvents() nextTimer ? &timeout : nullptr, nullptr); if (ret < 0) { ret = -errno; - LOG(Warning) << "poll() failed with " << strerror(-ret); + LOGC(Event, Warning) << "poll() failed with " << strerror(-ret); } else if (ret > 0) { processNotifiers(pollfds); } @@ -201,9 +206,10 @@ void EventDispatcherPoll::processNotifiers(const std::vector &pol * notifier immediately. */ if (pfd.revents & POLLNVAL) { - LOG(Warning) << "Disabling " << notifierType(event.type) - << " due to invalid file descriptor " - << pfd.fd; + LOGC(Event, Warning) + << "Disabling " << notifierType(event.type) + << " due to invalid file descriptor " + << pfd.fd; unregisterEventNotifier(notifier); continue; } diff --git a/src/libcamera/media_device.cpp b/src/libcamera/media_device.cpp index 0ee55060aa9b..3f431accfc69 100644 --- a/src/libcamera/media_device.cpp +++ b/src/libcamera/media_device.cpp @@ -27,6 +27,8 @@ namespace libcamera { +LOG_DEFINE_CATEGORY(MediaDevice) + /** * \class MediaDevice * \brief The MediaDevice represents a Media Controller device with its full @@ -139,15 +141,15 @@ bool MediaDevice::acquire() int MediaDevice::open() { if (fd_ != -1) { - LOG(Error) << "MediaDevice already open"; + LOGC(MediaDevice, Error) << "MediaDevice already open"; return -EBUSY; } int ret = ::open(devnode_.c_str(), O_RDWR); if (ret < 0) { ret = -errno; - LOG(Error) << "Failed to open media device at " << devnode_ - << ": " << strerror(-ret); + LOGC(MediaDevice, Error) << "Failed to open media device at " + << devnode_ << ": " << strerror(-ret); return ret; } fd_ = ret; @@ -156,8 +158,8 @@ int MediaDevice::open() ret = ioctl(fd_, MEDIA_IOC_DEVICE_INFO, &info); if (ret) { ret = -errno; - LOG(Error) << "Failed to get media device info " - << ": " << strerror(-ret); + LOGC(MediaDevice, Error) << "Failed to get media device info " + << ": " << strerror(-ret); return ret; } @@ -227,8 +229,9 @@ int MediaDevice::populate() ret = ioctl(fd_, MEDIA_IOC_G_TOPOLOGY, &topology); if (ret < 0) { ret = -errno; - LOG(Error) << "Failed to enumerate topology: " - << strerror(-ret); + LOGC(MediaDevice, Error) + << "Failed to enumerate topology: " + << strerror(-ret); return ret; } @@ -445,8 +448,8 @@ bool MediaDevice::addObject(MediaObject *object) { if (objects_.find(object->id()) != objects_.end()) { - LOG(Error) << "Element with id " << object->id() - << " already enumerated."; + LOGC(MediaDevice, Error) << "Element with id " << object->id() + << " already enumerated."; return false; } @@ -568,8 +571,9 @@ bool MediaDevice::populatePads(const struct media_v2_topology &topology) MediaEntity *mediaEntity = dynamic_cast (object(entity_id)); if (!mediaEntity) { - LOG(Error) << "Failed to find entity with id: " - << entity_id; + LOGC(MediaDevice, Error) + << "Failed to find entity with id: " + << entity_id; return false; } @@ -604,8 +608,9 @@ bool MediaDevice::populateLinks(const struct media_v2_topology &topology) MediaPad *source = dynamic_cast (object(source_id)); if (!source) { - LOG(Error) << "Failed to find pad with id: " - << source_id; + LOGC(MediaDevice, Error) + << "Failed to find pad with id: " + << source_id; return false; } @@ -613,8 +618,9 @@ bool MediaDevice::populateLinks(const struct media_v2_topology &topology) MediaPad *sink = dynamic_cast (object(sink_id)); if (!sink) { - LOG(Error) << "Failed to find pad with id: " - << sink_id; + LOGC(MediaDevice, Error) + << "Failed to find pad with id: " + << sink_id; return false; } @@ -665,14 +671,16 @@ int MediaDevice::setupLink(const MediaLink *link, unsigned int flags) int ret = ioctl(fd_, MEDIA_IOC_SETUP_LINK, &linkDesc); if (ret) { ret = -errno; - LOG(Error) << "Failed to setup link: " << strerror(-ret); + LOGC(MediaDevice, Error) << "Failed to setup link: " + << strerror(-ret); return ret; } - LOG(Debug) << source->entity()->name() << "[" - << source->index() << "] -> " - << sink->entity()->name() << "[" - << sink->index() << "]: " << flags; + LOGC(MediaDevice, Debug) + << source->entity()->name() << "[" + << source->index() << "] -> " + << sink->entity()->name() << "[" + << sink->index() << "]: " << flags; return 0; } diff --git a/src/libcamera/media_object.cpp b/src/libcamera/media_object.cpp index cb3af85e217e..70983ba1f257 100644 --- a/src/libcamera/media_object.cpp +++ b/src/libcamera/media_object.cpp @@ -39,6 +39,8 @@ namespace libcamera { +LOG_DECLARE_CATEGORY(MediaDevice) + /** * \class MediaObject * \brief Base class for all media objects @@ -317,8 +319,9 @@ int MediaEntity::setDeviceNode(const std::string &devnode) int ret = ::access(devnode.c_str(), R_OK | W_OK); if (ret < 0) { ret = -errno; - LOG(Error) << "Device node " << devnode << " can't be accessed: " - << strerror(-ret); + LOGC(MediaDevice, Error) + << "Device node " << devnode << " can't be accessed: " + << strerror(-ret); return ret; } diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index f2e08a6a7315..33e35791161a 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -24,6 +24,8 @@ namespace libcamera { +LOG_DEFINE_CATEGORY(Pipeline) + /** * \class PipelineHandler * \brief Create and manage cameras based on a set of media devices @@ -120,7 +122,8 @@ void PipelineHandlerFactory::registerType(PipelineHandlerFactory *factory) factories.push_back(factory); - LOG(Debug) << "Registered pipeline handler \"" << factory->name() << "\""; + LOGC(Pipeline, Debug) + << "Registered pipeline handler \"" << factory->name() << "\""; } /** diff --git a/src/libcamera/timer.cpp b/src/libcamera/timer.cpp index 306825fde3c0..849eeba6ca24 100644 --- a/src/libcamera/timer.cpp +++ b/src/libcamera/timer.cpp @@ -20,6 +20,8 @@ namespace libcamera { +LOG_DEFINE_CATEGORY(Timer) + /** * \class Timer * \brief Single-shot timer interface @@ -54,8 +56,8 @@ void Timer::start(unsigned int msec) interval_ = msec; deadline_ = tp.tv_sec * 1000000000ULL + tp.tv_nsec + msec * 1000000ULL; - LOG(Debug) << "Starting timer " << this << " with interval " << msec - << ": deadline " << deadline_; + LOGC(Timer, Debug) << "Starting timer " << this << " with interval " + << msec << ": deadline " << deadline_; CameraManager::instance()->eventDispatcher()->registerTimer(this); } diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp index 54b53de37510..17b73de30995 100644 --- a/src/libcamera/v4l2_device.cpp +++ b/src/libcamera/v4l2_device.cpp @@ -20,6 +20,8 @@ */ namespace libcamera { +LOG_DEFINE_CATEGORY(V4L2) + /** * \struct V4L2Capability * \brief struct v4l2_capability object wrapper and helpers @@ -106,15 +108,16 @@ int V4L2Device::open() int ret; if (isOpen()) { - LOG(Error) << "Device already open"; + LOGC(V4L2, Error) << "Device already open"; return -EBUSY; } ret = ::open(devnode_.c_str(), O_RDWR); if (ret < 0) { ret = -errno; - LOG(Error) << "Failed to open V4L2 device '" << devnode_ - << "': " << strerror(-ret); + LOGC(V4L2, Error) + << "Failed to open V4L2 device '" << devnode_ + << "': " << strerror(-ret); return ret; } fd_ = ret; @@ -122,22 +125,24 @@ int V4L2Device::open() ret = ioctl(fd_, VIDIOC_QUERYCAP, &caps_); if (ret < 0) { ret = -errno; - LOG(Error) << "Failed to query device capabilities: " - << strerror(-ret); + LOGC(V4L2, Error) + << "Failed to query device capabilities: " + << strerror(-ret); return ret; } - LOG(Debug) << "Opened '" << devnode_ << "' " - << caps_.bus_info() << ": " << caps_.driver() - << ": " << caps_.card(); + LOGC(V4L2, Debug) + << "Opened '" << devnode_ << "' " + << caps_.bus_info() << ": " << caps_.driver() + << ": " << caps_.card(); if (!caps_.isCapture() && !caps_.isOutput()) { - LOG(Debug) << "Device is not a supported type"; + LOGC(V4L2, Debug) << "Device is not a supported type"; return -EINVAL; } if (!caps_.hasStreaming()) { - LOG(Error) << "Device does not support streaming I/O"; + LOGC(V4L2, Error) << "Device does not support streaming I/O"; return -EINVAL; }