Move max_align_v and max_align_t to folly/lang/Align.h
[folly.git] / folly / experimental / logging / Init.cpp
index d1e6a6a98ac2fa855be55e5f633a0984b2c7b7a7..73542a8e0500c2c35cf6c78f911ea40c58d6aa0f 100644 (file)
  */
 #include <folly/experimental/logging/Init.h>
 
-#include <folly/experimental/logging/AsyncFileWriter.h>
-#include <folly/experimental/logging/GlogStyleFormatter.h>
-#include <folly/experimental/logging/ImmediateFileWriter.h>
-#include <folly/experimental/logging/LogCategory.h>
+#include <folly/experimental/logging/LogConfig.h>
+#include <folly/experimental/logging/LogConfigParser.h>
 #include <folly/experimental/logging/LoggerDB.h>
-#include <folly/experimental/logging/StandardLogHandler.h>
-
-using std::shared_ptr;
-using std::string;
-using std::vector;
+#include <folly/experimental/logging/StreamHandlerFactory.h>
 
 namespace folly {
 
-void initLogLevels(StringPiece configString, LogLevel defaultRootLevel) {
-  // Set the default root category log level first
-  LoggerDB::get()->getCategory(".")->setLevel(defaultRootLevel);
+/**
+ * The base logging settings to be applied in initLogging(),
+ * before any user-specified settings.
+ *
+ * This defines a log handler named "default" that writes to stderr,
+ * and configures the root log category to log to this handler and have a log
+ * level setting of WARN.
+ *
+ * Note that the default log handler uses async=false, so that log messages are
+ * written immediately to stderr from the thread that generated the log
+ * message.  This is often undesirable, as it can slow down normal processing
+ * waiting for logging I/O.  However, using async=true has some trade-offs of
+ * its own: it causes a new thread to be started, and not all message may get
+ * flushed to stderr if the program crashes.  For now, using async=false seems
+ * like the safer trade-off here, but many programs may wish to change this
+ * default.
+ *
+ * The user-specified config string may override any of these values.
+ * If the user-specified config string ends up not using the default log
+ * handler, the handler will be automatically forgotten by the LoggerDB code.
+ */
+constexpr StringPiece kDefaultLoggingConfig =
+    ".=WARN:default; default=stream:stream=stderr,async=false";
 
-  // Then apply the configuration string
-  if (!configString.empty()) {
-    auto ret = LoggerDB::get()->processConfigString(configString);
-    if (!ret.empty()) {
-      throw LoggingConfigError(ret);
-    }
-  }
-}
+void initLogging(StringPiece configString) {
+  // Register the StreamHandlerFactory
+  LoggerDB::get()->registerHandlerFactory(
+      std::make_unique<StreamHandlerFactory>());
+
+  // TODO: In the future it would be nice to build a better mechanism so that
+  // additional LogHandlerFactory objects could be automatically registered on
+  // startup if they are linked into our current executable.
+  //
+  // For now we register only the StreamHandlerFactory.  There is a
+  // FileHandlerFactory, but we do not register it by default: it allows
+  // appending to arbitrary files based on the config settings, and we do not
+  // want to allow this by default for security reasons.  (In the future
+  // maybe it would be worth enabling the FileHandlerFactory by default if we
+  // confirm that we are not a setuid or setgid binary.  i.e., if the real
+  // UID+GID is the same as the effective UID+GID.)
 
-void initLoggingGlogStyle(
-    StringPiece configString,
-    LogLevel defaultRootLevel,
-    bool asyncWrites) {
-  // Configure log levels
-  initLogLevels(configString, defaultRootLevel);
+  // Parse the default log level settings before processing the input config
+  // string.
+  auto config = parseLogConfig(kDefaultLoggingConfig);
 
-  // Create the LogHandler
-  std::shared_ptr<LogWriter> writer;
-  folly::File file{STDERR_FILENO, false};
-  if (asyncWrites) {
-    writer = std::make_shared<AsyncFileWriter>(std::move(file));
-  } else {
-    writer = std::make_shared<ImmediateFileWriter>(std::move(file));
+  // Then apply the configuration string
+  if (!configString.empty()) {
+    auto inputConfig = parseLogConfig(configString);
+    config.update(inputConfig);
   }
-  auto handler = std::make_shared<StandardLogHandler>(
-      std::make_shared<GlogStyleFormatter>(), std::move(writer));
 
-  // Add the handler to the root category.
-  LoggerDB::get()->getCategory(".")->addHandler(std::move(handler));
+  // Now apply the configuration to the LoggerDB
+  LoggerDB::get()->updateConfig(config);
 }
 
-LoggingConfigError::LoggingConfigError(const vector<string>& errors)
-    : invalid_argument{computeMessage(errors)} {}
-
-std::string LoggingConfigError::computeMessage(const vector<string>& errors) {
-  string msg = "error parsing logging configuration:";
-  for (const auto& error : errors) {
-    msg += "\n" + error;
-  }
-  return msg;
-}
-}
+} // namespace folly