[libcamera-devel,5/6] libcamera: log: Get log output file from the environment

Message ID 20190121005930.10112-6-laurent.pinchart@ideasonboard.com
State Superseded
Headers show
Series
  • Extend the logger with categories and configuration
Related show

Commit Message

Laurent Pinchart Jan. 21, 2019, 12:59 a.m. UTC
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 <laurent.pinchart@ideasonboard.com>
---
 src/libcamera/log.cpp | 47 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 45 insertions(+), 2 deletions(-)

Patch

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 <cstdio>
 #include <cstdlib>
 #include <ctime>
+#include <fstream>
 #include <iomanip>
+#include <iostream>
 #include <list>
 #include <string.h>
 #include <unordered_set>
@@ -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<LogCategory *> categories_;
 	std::list<std::pair<std::string, LogSeverity>> 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)