From ae69959c3e3fc4dc0bff389bd24255f07072b336 Mon Sep 17 00:00:00 2001 From: Adam Simpkins Date: Wed, 29 Nov 2017 17:35:08 -0800 Subject: [PATCH] logging: add a LogHandler registry to LoggerDB Summary: Update the LoggerDB to track a list of LogHandlers by name, and LogHandlerFactories by handler type. This will be needed to support updating the LoggerDB configuration from a LogConfig object. Reviewed By: bolinfest Differential Revision: D6200562 fbshipit-source-id: e365b4e0df65aa5aaa34e118eb3cee9c9c45cb05 --- folly/experimental/logging/LogCategory.h | 11 +++--- folly/experimental/logging/LoggerDB.cpp | 40 +++++++++++++++++++++ folly/experimental/logging/LoggerDB.h | 46 ++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 5 deletions(-) diff --git a/folly/experimental/logging/LogCategory.h b/folly/experimental/logging/LogCategory.h index 91e72c91..4779a472 100644 --- a/folly/experimental/logging/LogCategory.h +++ b/folly/experimental/logging/LogCategory.h @@ -169,8 +169,9 @@ class LogCategory { void admitMessage(const LogMessage& message) const; /** - * Note: setLevelLocked() may only be called while holding the main - * LoggerDB lock. + * Note: setLevelLocked() may only be called while holding the + * LoggerDB loggersByName_ lock. It is safe to call this while holding the + * loggersByName_ lock in read-mode; holding it exclusively is not required. * * This method should only be invoked by LoggerDB. */ @@ -240,9 +241,9 @@ class LogCategory { /** * Pointers to children and sibling loggers. - * These pointers should only ever be accessed while holding the main - * LoggerDB lock. (These are only modified when creating new loggers, - * which occurs with the main LoggerDB lock held.) + * These pointers should only ever be accessed while holding the + * LoggerDB::loggersByName_ lock. (These are only modified when creating new + * loggers, which occurs with the main LoggerDB lock held.) */ LogCategory* firstChild_{nullptr}; LogCategory* nextSibling_{nullptr}; diff --git a/folly/experimental/logging/LoggerDB.cpp b/folly/experimental/logging/LoggerDB.cpp index ee09681a..fdfcdfa5 100644 --- a/folly/experimental/logging/LoggerDB.cpp +++ b/folly/experimental/logging/LoggerDB.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -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 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( + "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("no LogHandlerFactory for type \"", type, "\" found")); + } +} + LogLevel LoggerDB::xlogInit( StringPiece categoryName, std::atomic* xlogCategoryLevel, diff --git a/folly/experimental/logging/LoggerDB.h b/folly/experimental/logging/LoggerDB.h index 1c80cd96..c2c1d423 100644 --- a/folly/experimental/logging/LoggerDB.h +++ b/folly/experimental/logging/LoggerDB.h @@ -29,6 +29,8 @@ namespace folly { class LogCategory; +class LogHandler; +class LogHandlerFactory; enum class LogLevel : uint32_t; /** @@ -41,6 +43,8 @@ class LoggerDB { */ static LoggerDB* get(); + ~LoggerDB(); + /** * Get the LogCategory for the specified name. * @@ -99,6 +103,35 @@ class LoggerDB { */ 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 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 used by an XLOG() * statement. @@ -171,6 +204,14 @@ class LoggerDB { LogName::Hash, LogName::Equals>; + using HandlerFactoryMap = + std::unordered_map>; + using HandlerMap = std::unordered_map>; + struct HandlerInfo { + HandlerFactoryMap factories; + HandlerMap handlers; + }; + // Forbidden copy constructor and assignment operator LoggerDB(LoggerDB const&) = delete; LoggerDB& operator=(LoggerDB const&) = delete; @@ -201,6 +242,11 @@ class LoggerDB { */ folly::Synchronized loggersByName_; + /** + * The LogHandlers and LogHandlerFactories. + */ + folly::Synchronized handlerInfo_; + static std::atomic warningHandler_; }; } // namespace folly -- 2.34.1