Commit ae69959c authored by Adam Simpkins's avatar Adam Simpkins Committed by Facebook Github Bot

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
parent 73c52b9f
...@@ -169,8 +169,9 @@ class LogCategory { ...@@ -169,8 +169,9 @@ class LogCategory {
void admitMessage(const LogMessage& message) const; void admitMessage(const LogMessage& message) const;
/** /**
* Note: setLevelLocked() may only be called while holding the main * Note: setLevelLocked() may only be called while holding the
* LoggerDB lock. * 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. * This method should only be invoked by LoggerDB.
*/ */
...@@ -240,9 +241,9 @@ class LogCategory { ...@@ -240,9 +241,9 @@ class LogCategory {
/** /**
* Pointers to children and sibling loggers. * Pointers to children and sibling loggers.
* These pointers should only ever be accessed while holding the main * These pointers should only ever be accessed while holding the
* LoggerDB lock. (These are only modified when creating new loggers, * LoggerDB::loggersByName_ lock. (These are only modified when creating new
* which occurs with the main LoggerDB lock held.) * loggers, which occurs with the main LoggerDB lock held.)
*/ */
LogCategory* firstChild_{nullptr}; LogCategory* firstChild_{nullptr};
LogCategory* nextSibling_{nullptr}; LogCategory* nextSibling_{nullptr};
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <folly/String.h> #include <folly/String.h>
#include <folly/experimental/logging/LogCategory.h> #include <folly/experimental/logging/LogCategory.h>
#include <folly/experimental/logging/LogHandler.h> #include <folly/experimental/logging/LogHandler.h>
#include <folly/experimental/logging/LogHandlerFactory.h>
#include <folly/experimental/logging/LogLevel.h> #include <folly/experimental/logging/LogLevel.h>
#include <folly/experimental/logging/Logger.h> #include <folly/experimental/logging/Logger.h>
#include <folly/experimental/logging/RateLimiter.h> #include <folly/experimental/logging/RateLimiter.h>
...@@ -76,6 +77,8 @@ LoggerDB::LoggerDB() { ...@@ -76,6 +77,8 @@ LoggerDB::LoggerDB() {
LoggerDB::LoggerDB(TestConstructorArg) : LoggerDB() {} LoggerDB::LoggerDB(TestConstructorArg) : LoggerDB() {}
LoggerDB::~LoggerDB() {}
LogCategory* LoggerDB::getCategory(StringPiece name) { LogCategory* LoggerDB::getCategory(StringPiece name) {
return getOrCreateCategoryLocked(*loggersByName_.wlock(), name); return getOrCreateCategoryLocked(*loggersByName_.wlock(), name);
} }
...@@ -173,6 +176,18 @@ void LoggerDB::cleanupHandlers() { ...@@ -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) { for (auto* category : categories) {
category->clearHandlers(); category->clearHandlers();
} }
...@@ -199,6 +214,31 @@ size_t LoggerDB::flushAllHandlers() { ...@@ -199,6 +214,31 @@ size_t LoggerDB::flushAllHandlers() {
return handlers.size(); 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( LogLevel LoggerDB::xlogInit(
StringPiece categoryName, StringPiece categoryName,
std::atomic<LogLevel>* xlogCategoryLevel, std::atomic<LogLevel>* xlogCategoryLevel,
......
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
namespace folly { namespace folly {
class LogCategory; class LogCategory;
class LogHandler;
class LogHandlerFactory;
enum class LogLevel : uint32_t; enum class LogLevel : uint32_t;
/** /**
...@@ -41,6 +43,8 @@ class LoggerDB { ...@@ -41,6 +43,8 @@ class LoggerDB {
*/ */
static LoggerDB* get(); static LoggerDB* get();
~LoggerDB();
/** /**
* Get the LogCategory for the specified name. * Get the LogCategory for the specified name.
* *
...@@ -99,6 +103,35 @@ class LoggerDB { ...@@ -99,6 +103,35 @@ class LoggerDB {
*/ */
size_t flushAllHandlers(); 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() * Initialize the LogCategory* and std::atomic<LogLevel> used by an XLOG()
* statement. * statement.
...@@ -171,6 +204,14 @@ class LoggerDB { ...@@ -171,6 +204,14 @@ class LoggerDB {
LogName::Hash, LogName::Hash,
LogName::Equals>; 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 // Forbidden copy constructor and assignment operator
LoggerDB(LoggerDB const&) = delete; LoggerDB(LoggerDB const&) = delete;
LoggerDB& operator=(LoggerDB const&) = delete; LoggerDB& operator=(LoggerDB const&) = delete;
...@@ -201,6 +242,11 @@ class LoggerDB { ...@@ -201,6 +242,11 @@ class LoggerDB {
*/ */
folly::Synchronized<LoggerNameMap> loggersByName_; folly::Synchronized<LoggerNameMap> loggersByName_;
/**
* The LogHandlers and LogHandlerFactories.
*/
folly::Synchronized<HandlerInfo> handlerInfo_;
static std::atomic<InternalWarningHandler> warningHandler_; static std::atomic<InternalWarningHandler> warningHandler_;
}; };
} // namespace folly } // namespace folly
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment