{"id":313,"url":"https://patchwork.libcamera.org/api/1.1/patches/313/?format=json","web_url":"https://patchwork.libcamera.org/patch/313/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","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/1.1/people/2/?format=json","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/1.1/series/108/?format=json","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"]}