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 {
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};
......
......@@ -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,
......
......@@ -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<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.
......@@ -171,6 +204,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;
......@@ -201,6 +242,11 @@ class LoggerDB {
*/
folly::Synchronized<LoggerNameMap> loggersByName_;
/**
* The LogHandlers and LogHandlerFactories.
*/
folly::Synchronized<HandlerInfo> handlerInfo_;
static std::atomic<InternalWarningHandler> warningHandler_;
};
} // 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