logging: add a LogHandler registry to LoggerDB
[folly.git] / folly / experimental / logging / LoggerDB.cpp
index ee09681a981ac344ef3b1e70d7f3a20fa11e5032..fdfcdfa51b218d93225abbdb34cb23989a8ced2c 100644 (file)
@@ -22,6 +22,7 @@
 #include <folly/String.h>
 #include <folly/experimental/logging/LogCategory.h>
 #include <folly/experimental/logging/LogHandler.h>
+#include <folly/experimental/logging/LogHandlerFactory.h>
 #include <folly/experimental/logging/LogLevel.h>
 #include <folly/experimental/logging/Logger.h>
 #include <folly/experimental/logging/RateLimiter.h>
@@ -76,6 +77,8 @@ LoggerDB::LoggerDB() {
 
 LoggerDB::LoggerDB(TestConstructorArg) : LoggerDB() {}
 
+LoggerDB::~LoggerDB() {}
+
 LogCategory* LoggerDB::getCategory(StringPiece name) {
   return getOrCreateCategoryLocked(*loggersByName_.wlock(), name);
 }
@@ -173,6 +176,18 @@ void LoggerDB::cleanupHandlers() {
     }
   }
 
+  // Also extract our HandlerFactoryMap and HandlerMap, so we can clear them
+  // later without holding the handlerInfo_ lock.
+  HandlerFactoryMap factories;
+  HandlerMap handlers;
+  {
+    auto handlerInfo = handlerInfo_.wlock();
+    factories.swap(handlerInfo->factories);
+    handlers.swap(handlerInfo->handlers);
+  }
+
+  // Remove all of the LogHandlers from all log categories,
+  // to drop any shared_ptr references to the LogHandlers
   for (auto* category : categories) {
     category->clearHandlers();
   }
@@ -199,6 +214,31 @@ size_t LoggerDB::flushAllHandlers() {
   return handlers.size();
 }
 
+void LoggerDB::registerHandlerFactory(
+    std::unique_ptr<LogHandlerFactory> factory,
+    bool replaceExisting) {
+  auto type = factory->getType();
+  auto handlerInfo = handlerInfo_.wlock();
+  if (replaceExisting) {
+    handlerInfo->factories[type.str()] = std::move(factory);
+  } else {
+    auto ret = handlerInfo->factories.emplace(type.str(), std::move(factory));
+    if (!ret.second) {
+      throw std::range_error(to<std::string>(
+          "a LogHandlerFactory for the type \"", type, "\" already exists"));
+    }
+  }
+}
+
+void LoggerDB::unregisterHandlerFactory(StringPiece type) {
+  auto handlerInfo = handlerInfo_.wlock();
+  auto numRemoved = handlerInfo->factories.erase(type.str());
+  if (numRemoved != 1) {
+    throw std::range_error(
+        to<std::string>("no LogHandlerFactory for type \"", type, "\" found"));
+  }
+}
+
 LogLevel LoggerDB::xlogInit(
     StringPiece categoryName,
     std::atomic<LogLevel>* xlogCategoryLevel,