Fix copyright lines
[folly.git] / folly / experimental / logging / LoggerDB.h
index 635e6f9d08779a60d645bbbd23dbb020efc34b66..ac5a492136522215b6f2ada1b80b076a76056998 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2004-present Facebook, Inc.
+ * Copyright 2017-present Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
  */
 #pragma once
 
+#include <folly/Conv.h>
 #include <folly/CppAttributes.h>
 #include <folly/Range.h>
 #include <folly/Synchronized.h>
@@ -28,6 +29,9 @@
 namespace folly {
 
 class LogCategory;
+class LogConfig;
+class LogHandler;
+class LogHandlerFactory;
 enum class LogLevel : uint32_t;
 
 /**
@@ -40,6 +44,8 @@ class LoggerDB {
    */
   static LoggerDB* get();
 
+  ~LoggerDB();
+
   /**
    * Get the LogCategory for the specified name.
    *
@@ -72,16 +78,38 @@ class LoggerDB {
   void setLevel(LogCategory* category, LogLevel level, bool inherit = true);
 
   /**
-   * Apply a configuration string specifying a series a log levels.
+   * Get a LogConfig object describing the current state of the LoggerDB.
+   *
+   * Note that this may not 100% accurately describe the current configuration
+   * if callers have manually added LogHandlers to some categories without
+   * using the updateConfig() or resetConfig() functions.  In this case
+   * getConfig() will simply report these handlers as "unknown_handler" when
+   * returning handler names for the categories in question.
+   */
+  LogConfig getConfig() const;
+
+  /**
+   * Update the current LoggerDB state with the specified LogConfig settings.
+   *
+   * Log categories and handlers listed in the LogConfig object will be updated
+   * to the new state listed in the LogConfig.  Settings on categories and
+   * handlers not listed in the config will be left as-is.
+   */
+  void updateConfig(const LogConfig& config);
+
+  /**
+   * Reset the current LoggerDB state to the specified LogConfig settings.
    *
-   * The string format is a comma separated list of <name>=<level> sections.
-   * e.g.: "foo=DBG3,log.bar=WARN"
+   * All LogCategories not mentioned in the new LogConfig will have all
+   * currently configured log handlers removed and their log level set to its
+   * default state.  For the root category the default log level is ERR; for
+   * all other categories the default level is MAX_LEVEL with log level
+   * inheritance enabled.
    *
-   * Returns a list of error messages for each error encountered trying to
-   * parse the config string.  The return value will be an empty vector if no
-   * errors were encountered.
+   * LogCategories listed in the new config but without LogHandler information
+   * defined will have all existing handlers removed.
    */
-  std::vector<std::string> processConfigString(folly::StringPiece config);
+  void resetConfig(const LogConfig& config);
 
   /**
    * Remove all registered LogHandlers on all LogCategory objects.
@@ -90,6 +118,58 @@ class LoggerDB {
    */
   void cleanupHandlers();
 
+  /**
+   * Call flush() on all LogHandler objects registered on any LogCategory in
+   * this LoggerDB.
+   *
+   * Returns the number of registered LogHandlers.
+   */
+  size_t flushAllHandlers();
+
+  /**
+   * Register a LogHandlerFactory.
+   *
+   * The LogHandlerFactory will be used to create LogHandler objects from a
+   * LogConfig object during updateConfig() and resetConfig() calls.
+   *
+   * Only one factory can be registered for a given handler type name.
+   * LogHandlerFactory::getType() returns the handler type supported by this
+   * LogHandlerFactory.
+   *
+   * If an existing LogHandlerFactory is already registered with this type name
+   * and replaceExisting is false a std::range_error will be thrown.
+   * Otherwise, if replaceExisting is true, the new factory will replace the
+   * existing factory.
+   */
+  void registerHandlerFactory(
+      std::unique_ptr<LogHandlerFactory> factory,
+      bool replaceExisting = false);
+
+  /**
+   * Remove a registered LogHandlerFactory.
+   *
+   * The type parameter should be the name of the handler type, as returned by
+   * LogHandlerFactory::getType().
+   *
+   * Throws std::range_error if no handler factory with this type name exists.
+   */
+  void unregisterHandlerFactory(folly::StringPiece type);
+
+  /**
+   * Initialize the LogCategory* and std::atomic<LogLevel> used by an XLOG()
+   * statement.
+   *
+   * Returns the current effective LogLevel of the category.
+   */
+  LogLevel xlogInit(
+      folly::StringPiece categoryName,
+      std::atomic<LogLevel>* xlogCategoryLevel,
+      LogCategory** xlogCategory);
+  LogCategory* xlogInitCategory(
+      folly::StringPiece categoryName,
+      LogCategory** xlogCategory,
+      std::atomic<bool>* isInitialized);
+
   enum TestConstructorArg { TESTING };
 
   /**
@@ -103,6 +183,43 @@ class LoggerDB {
    */
   explicit LoggerDB(TestConstructorArg);
 
+  /**
+   * internalWarning() is used to report a problem when something goes wrong
+   * internally in the logging library.
+   *
+   * We can't log these messages through the normal logging flow since logging
+   * itself has failed.
+   *
+   * Example scenarios where this is used:
+   * - We fail to write to a log file (for instance, when the disk is full)
+   * - A LogHandler throws an unexpected exception
+   */
+  template <typename... Args>
+  static void internalWarning(
+      folly::StringPiece file,
+      int lineNumber,
+      Args&&... args) noexcept {
+    internalWarningImpl(
+        file, lineNumber, folly::to<std::string>(std::forward<Args>(args)...));
+  }
+
+  using InternalWarningHandler =
+      void (*)(folly::StringPiece file, int lineNumber, std::string&&);
+
+  /**
+   * Set a function to be called when the logging library generates an internal
+   * warning.
+   *
+   * The supplied handler should never throw exceptions.
+   *
+   * If a null handler is supplied, the default built-in handler will be used.
+   *
+   * The default handler reports the message with _CrtDbgReport(_CRT_WARN) on
+   * Windows, and prints the message to stderr on other platforms.  It also
+   * rate limits messages if they are arriving too quickly.
+   */
+  static void setInternalWarningHandler(InternalWarningHandler handler);
+
  private:
   using LoggerNameMap = std::unordered_map<
       folly::StringPiece,
@@ -110,6 +227,14 @@ class LoggerDB {
       LogName::Hash,
       LogName::Equals>;
 
+  using HandlerFactoryMap =
+      std::unordered_map<std::string, std::unique_ptr<LogHandlerFactory>>;
+  using HandlerMap = std::unordered_map<std::string, std::weak_ptr<LogHandler>>;
+  struct HandlerInfo {
+    HandlerFactoryMap factories;
+    HandlerMap handlers;
+  };
+
   // Forbidden copy constructor and assignment operator
   LoggerDB(LoggerDB const&) = delete;
   LoggerDB& operator=(LoggerDB const&) = delete;
@@ -123,6 +248,33 @@ class LoggerDB {
       folly::StringPiece name,
       LogCategory* parent);
 
+  using NewHandlerMap =
+      std::unordered_map<std::string, std::shared_ptr<LogHandler>>;
+  using OldToNewHandlerMap = std::
+      unordered_map<std::shared_ptr<LogHandler>, std::shared_ptr<LogHandler>>;
+  void startConfigUpdate(
+      const Synchronized<HandlerInfo>::LockedPtr& handlerInfo,
+      const LogConfig& config,
+      NewHandlerMap* handlers,
+      OldToNewHandlerMap* oldToNewHandlerMap);
+  void finishConfigUpdate(
+      const Synchronized<HandlerInfo>::LockedPtr& handlerInfo,
+      NewHandlerMap* handlers,
+      OldToNewHandlerMap* oldToNewHandlerMap);
+  std::vector<std::shared_ptr<LogHandler>> buildCategoryHandlerList(
+      const NewHandlerMap& handlerMap,
+      StringPiece categoryName,
+      const std::vector<std::string>& categoryHandlerNames);
+
+  static void internalWarningImpl(
+      folly::StringPiece filename,
+      int lineNumber,
+      std::string&& msg) noexcept;
+  static void defaultInternalWarningImpl(
+      folly::StringPiece filename,
+      int lineNumber,
+      std::string&& msg) noexcept;
+
   /**
    * A map of LogCategory objects by name.
    *
@@ -130,5 +282,15 @@ class LoggerDB {
    * have to be in canonical form.
    */
   folly::Synchronized<LoggerNameMap> loggersByName_;
+
+  /**
+   * The LogHandlers and LogHandlerFactories.
+   *
+   * For lock ordering purposes, if you need to acquire both the loggersByName_
+   * and handlerInfo_ locks, the handlerInfo_ lock must be acquired first.
+   */
+  folly::Synchronized<HandlerInfo> handlerInfo_;
+
+  static std::atomic<InternalWarningHandler> warningHandler_;
 };
-}
+} // namespace folly