Patch Detail
Show a patch.
GET /api/patches/313/?format=api
{ "id": 313, "url": "https://patchwork.libcamera.org/api/patches/313/?format=api", "web_url": "https://patchwork.libcamera.org/patch/313/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20190121195606.8526-3-laurent.pinchart@ideasonboard.com>", "date": "2019-01-21T19:56:04", "name": "[libcamera-devel,v2,2/4] libcamera: log: Get log levels from the environment", "commit_ref": "747ace042cc10267f02fb190b35dc0188d662691", "pull_url": null, "state": "accepted", "archived": false, "hash": "60af28dcfc8db4111c775cddeda988499b80a4a9", "submitter": { "id": 2, "url": "https://patchwork.libcamera.org/api/people/2/?format=api", "name": "Laurent Pinchart", "email": "laurent.pinchart@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/313/mbox/", "series": [ { "id": 108, "url": "https://patchwork.libcamera.org/api/series/108/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=108", "date": "2019-01-21T19:56:02", "name": "Extend the logger with categories and configuration", "version": 2, "mbox": "https://patchwork.libcamera.org/series/108/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/313/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/313/checks/", "tags": {}, "headers": { "Return-Path": "<laurent.pinchart@ideasonboard.com>", "Received": [ "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 4992860C80\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 21 Jan 2019 20:56:12 +0100 (CET)", "from pendragon.bb.dnainternet.fi\n\t(dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi\n\t[IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id DD49A53E\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 21 Jan 2019 20:56:11 +0100 (CET)" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1548100572;\n\tbh=dmViCUYBJ4hTrZt5n/jXyOvaBhWx3PVqButVID1Lw4c=;\n\th=From:To:Subject:Date:In-Reply-To:References:From;\n\tb=S2IEuYNE9uTSq59FVWRkXCOWUloc6SmoNRVtqznJKLr29gSQ+Jz3s4oik+vZsWgQj\n\tkqQFQSDWJLkU4l8ZjdXS4hQrq/EGuie4qLTxJjKKTMEtgRTUiLpGszvjqcqrdEh4cP\n\tKt4GZTNBdjw8VgrS5YSCX5lZpvZabi+tPFmL6vRo=", "From": "Laurent Pinchart <laurent.pinchart@ideasonboard.com>", "To": "libcamera-devel@lists.libcamera.org", "Date": "Mon, 21 Jan 2019 21:56:04 +0200", "Message-Id": "<20190121195606.8526-3-laurent.pinchart@ideasonboard.com>", "X-Mailer": "git-send-email 2.19.2", "In-Reply-To": "<20190121195606.8526-1-laurent.pinchart@ideasonboard.com>", "References": "<20190121195606.8526-1-laurent.pinchart@ideasonboard.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Subject": "[libcamera-devel] [PATCH v2 2/4] libcamera: log: Get log levels\n\tfrom the environment", "X-BeenThere": "libcamera-devel@lists.libcamera.org", "X-Mailman-Version": "2.1.23", "Precedence": "list", "List-Id": "<libcamera-devel.lists.libcamera.org>", "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>", "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>", "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>", "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>", "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>", "X-List-Received-Date": "Mon, 21 Jan 2019 19:56:12 -0000" }, "content": "Set the log level for each log category from the environment variable\nLIBCAMERA_LOG_LEVELS.\n\nThe variable contains a comma-separated list of category:level pairs,\nand category names can include wildcards.\n\nSigned-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n---\n src/libcamera/log.cpp | 202 ++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 202 insertions(+)", "diff": "diff --git a/src/libcamera/log.cpp b/src/libcamera/log.cpp\nindex 20503fdcfcc1..23bb9edb9d14 100644\n--- a/src/libcamera/log.cpp\n+++ b/src/libcamera/log.cpp\n@@ -9,7 +9,9 @@\n #include <cstdlib>\n #include <ctime>\n #include <iomanip>\n+#include <list>\n #include <string.h>\n+#include <unordered_set>\n \n #include \"log.h\"\n #include \"utils.h\"\n@@ -17,10 +19,208 @@\n /**\n * \\file log.h\n * \\brief Logging infrastructure\n+ *\n+ * libcamera includes a logging infrastructure used through the library that\n+ * allows inspection of internal operation in a user-configurable way. The log\n+ * messages are grouped in categories that represent areas of libcamera, and\n+ * output of messages for each category can be controlled by independent log\n+ * levels.\n+ *\n+ * The levels are configurable through the LIBCAMERA_LOG_LEVELS environment\n+ * variable that contains a comma-separated list of 'category=level' pairs.\n+ *\n+ * The category names are strings and can include a wildcard ('*') character at\n+ * the end to match multiple categories.\n+ *\n+ * The level are either numeric values, or strings containing the log level\n+ * name. The available log levels are DEBUG, INFO, WARN, ERROR and FATAL. Log\n+ * message with a level higher than or equal to the configured log level for\n+ * their category are output to the log, while other messages are silently\n+ * discarded.\n */\n \n namespace libcamera {\n \n+/**\n+ * \\brief Message logger\n+ *\n+ * The Logger class handles log configuration.\n+ */\n+class Logger\n+{\n+public:\n+\tstatic Logger *instance();\n+\n+private:\n+\tLogger();\n+\n+\tvoid parseLogLevels();\n+\tstatic LogSeverity parseLogLevel(const std::string &level);\n+\n+\tfriend LogCategory;\n+\tvoid registerCategory(LogCategory *category);\n+\tvoid unregisterCategory(LogCategory *category);\n+\n+\tstd::unordered_set<LogCategory *> categories_;\n+\tstd::list<std::pair<std::string, LogSeverity>> levels_;\n+};\n+\n+/**\n+ * \\brief Retrieve the logger instance\n+ *\n+ * The Logger is a singleton and can't be constructed manually. This function\n+ * shall instead be used to retrieve the single global instance of the logger.\n+ *\n+ * \\return The logger instance\n+ */\n+Logger *Logger::instance()\n+{\n+\tstatic Logger instance;\n+\treturn &instance;\n+}\n+\n+/**\n+ * \\brief Construct a logger\n+ */\n+Logger::Logger()\n+{\n+\tparseLogLevels();\n+}\n+\n+/**\n+ * \\brief Parse the log levels from the environment\n+ *\n+ * The logr levels are stored in LIBCAMERA_LOG_LEVELS environement variable as a list\n+ * of \"category=level\" pairs, separated by commas (','). Parse the variable and\n+ * store the levels to configure all log categories.\n+ */\n+void Logger::parseLogLevels()\n+{\n+\tconst char *debug = secure_getenv(\"LIBCAMERA_LOG_LEVELS\");\n+\tif (!debug)\n+\t\treturn;\n+\n+\tfor (const char *pair = debug; *debug != '\\0'; pair = debug) {\n+\t\tconst char *comma = strchrnul(debug, ',');\n+\t\tsize_t len = comma - pair;\n+\n+\t\t/* Skip over the comma. */\n+\t\tdebug = *comma == ',' ? comma + 1 : comma;\n+\n+\t\t/* Skip to the next pair if the pair is empty. */\n+\t\tif (!len)\n+\t\t\tcontinue;\n+\n+\t\tstd::string category;\n+\t\tstd::string level;\n+\n+\t\tconst char *colon = static_cast<const char *>(memchr(pair, ':', len));\n+\t\tif (!colon) {\n+\t\t\t/* 'x' is a shortcut for '*:x'. */\n+\t\t\tcategory = \"*\";\n+\t\t\tlevel = std::string(pair, len);\n+\t\t} else {\n+\t\t\tcategory = std::string(pair, colon - pair);\n+\t\t\tlevel = std::string(colon + 1, comma - colon - 1);\n+\t\t}\n+\n+\t\t/* Both the category and the level must be specified. */\n+\t\tif (category.empty() || level.empty())\n+\t\t\tcontinue;\n+\n+\t\tLogSeverity severity = parseLogLevel(level);\n+\t\tif (severity == -1)\n+\t\t\tcontinue;\n+\n+\t\tlevels_.push_back({ category, severity });\n+\t}\n+}\n+\n+/**\n+ * \\brief Parse a log level string into a LogSeverity\n+ * \\param[in] level The log level string\n+ *\n+ * Log levels can be specified as an integer value in the range from LogDebug to\n+ * LogFatal, or as a string corresponding to the severity name in uppercase. Any\n+ * other value is invalid.\n+ *\n+ * \\return The log severity, or -1 if the string is invalid\n+ */\n+LogSeverity Logger::parseLogLevel(const std::string &level)\n+{\n+\tstatic const char *const names[] = {\n+\t\t\"DEBUG\",\n+\t\t\"INFO\",\n+\t\t\"WARN\",\n+\t\t\"ERROR\",\n+\t\t\"FATAL\",\n+\t};\n+\n+\tint severity;\n+\n+\tif (std::isdigit(level[0])) {\n+\t\tchar *endptr;\n+\t\tseverity = strtoul(level.c_str(), &endptr, 10);\n+\t\tif (*endptr != '\\0' || severity > LogFatal)\n+\t\t\tseverity = -1;\n+\t} else {\n+\t\tseverity = -1;\n+\t\tfor (unsigned int i = 0; i < ARRAY_SIZE(names); ++i) {\n+\t\t\tif (names[i] == level) {\n+\t\t\t\tseverity = i;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn static_cast<LogSeverity>(severity);\n+}\n+\n+/**\n+ * \\brief Register a log category with the logger\n+ * \\param[in] category The log category\n+ *\n+ * Log categories must have unique names. If a category with the same name\n+ * already exists this function performs no operation.\n+ */\n+void Logger::registerCategory(LogCategory *category)\n+{\n+\tcategories_.insert(category);\n+\n+\tconst std::string &name = category->name();\n+\tfor (const std::pair<std::string, LogSeverity> &level : levels_) {\n+\t\tbool match = true;\n+\n+\t\tfor (unsigned int i = 0; i < level.first.size(); ++i) {\n+\t\t\tif (level.first[i] == '*')\n+\t\t\t\tbreak;\n+\n+\t\t\tif (i >= name.size() ||\n+\t\t\t name[i] != level.first[i]) {\n+\t\t\t\tmatch = false;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (match) {\n+\t\t\tcategory->setSeverity(level.second);\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+}\n+\n+/**\n+ * \\brief Unregister a log category from the logger\n+ * \\param[in] category The log category\n+ *\n+ * If the \\a category hasn't been registered with the logger this function\n+ * performs no operation.\n+ */\n+void Logger::unregisterCategory(LogCategory *category)\n+{\n+\tcategories_.erase(category);\n+}\n+\n /**\n * \\enum LogSeverity\n * Log message severity\n@@ -52,10 +252,12 @@ namespace libcamera {\n LogCategory::LogCategory(const char *name)\n \t: name_(name), severity_(LogSeverity::LogInfo)\n {\n+\tLogger::instance()->registerCategory(this);\n }\n \n LogCategory::~LogCategory()\n {\n+\tLogger::instance()->unregisterCategory(this);\n }\n \n /**\n", "prefixes": [ "libcamera-devel", "v2", "2/4" ] }