unioil-loyalty-rn-app/ios/Pods/Flipper-Folly/folly/logging/LoggerDB.h

384 lines
13 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include <folly/Conv.h>
#include <folly/CppAttributes.h>
#include <folly/Range.h>
#include <folly/ScopeGuard.h>
#include <folly/Synchronized.h>
#include <folly/detail/StaticSingletonManager.h>
#include <folly/logging/LogName.h>
namespace folly {
class LogCategory;
class LogConfig;
class LogHandler;
class LogHandlerFactory;
enum class LogLevel : uint32_t;
/**
* LoggerDB stores the set of LogCategory objects.
*/
class LoggerDB {
using ContextCallback = folly::Function<std::string() const>;
public:
/**
* Get the main LoggerDB singleton.
*/
static LoggerDB& get();
~LoggerDB();
/**
* Get the LogCategory for the specified name.
*
* This creates the LogCategory for the specified name if it does not exist
* already.
*/
LogCategory* getCategory(folly::StringPiece name);
/**
* Get the LogCategory for the specified name, if it already exists.
*
* This returns nullptr if no LogCategory has been created yet for the
* specified name.
*/
LogCategory* FOLLY_NULLABLE getCategoryOrNull(folly::StringPiece name);
/**
* Set the log level for the specified category.
*
* Messages logged to a specific log category will be ignored unless the
* message log level is greater than the LogCategory's effective log level.
*
* If inherit is true, LogCategory's effective log level is the minimum of
* its level and it's parent category's effective log level. If inherit is
* false, the LogCategory's effective log level is simply its log level.
* (Setting inherit to false is necessary if you want a child LogCategory to
* use a less verbose level than its parent categories.)
*/
void setLevel(folly::StringPiece name, LogLevel level, bool inherit = true);
void setLevel(LogCategory* category, LogLevel level, bool inherit = true);
/**
* Get a LogConfig object describing the current state of the LoggerDB.
*/
LogConfig getConfig() const;
/**
* Get a LogConfig object fully describing the state of the LoggerDB.
*
* This is similar to getConfig(), but it returns LogCategoryConfig objects
* for all defined log categories, including ones that are using the default
* configuration settings.
*/
LogConfig getFullConfig() 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.
*
* 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
* kDefaultLogLevel (see LogLevel.h); for all other categories the default
* level is MAX_LEVEL with log level inheritance enabled.
*
* LogCategories listed in the new config but without LogHandler information
* defined will have all existing handlers removed.
*/
void resetConfig(const LogConfig& config);
/**
* Remove all registered LogHandlers on all LogCategory objects.
*
* This is called on the main LoggerDB object during shutdown.
*/
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 };
/**
* Construct a LoggerDB for testing purposes.
*
* Most callers should not need this function, and should use
* LoggerDB::get() to obtain the main LoggerDB singleton. This function
* exists mainly to allow testing LoggerDB objects in unit tests.
* It requires an explicit argument just to prevent callers from calling it
* unintentionally.
*/
explicit LoggerDB(TestConstructorArg);
/**
* Add a new context string callback to the list.
*
* The callbacks will be invoked during the construction of log messages,
* and returned strings will be appended in order to the tail of log
* log entry prefixes with space prepended to each item.
*/
void addContextCallback(ContextCallback);
/**
* Return a context string to be appended after default log prefixes.
*
* The context string is cutomized through adding context callbacks to
* LoggerDB objects.
*/
std::string getContextString() const;
/**
* 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,
std::unique_ptr<LogCategory>,
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;
};
class ContextCallbackList {
public:
void addCallback(ContextCallback);
std::string getContextString() const;
~ContextCallbackList();
private:
class CallbacksObj;
std::atomic<CallbacksObj*> callbacks_{nullptr};
std::mutex writeMutex_;
};
// Forbidden copy constructor and assignment operator
LoggerDB(LoggerDB const&) = delete;
LoggerDB& operator=(LoggerDB const&) = delete;
LoggerDB();
LogCategory* getOrCreateCategoryLocked(
LoggerNameMap& loggersByName, folly::StringPiece name);
LogCategory* createCategoryLocked(
LoggerNameMap& loggersByName,
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>>;
LogConfig getConfigImpl(bool includeAllCategories) const;
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.
*
* Lookups can be performed using arbitrary StringPiece values that do not
* 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_;
/**
* Callbacks returning context strings.
*
* Exceptions from the callbacks are catched and reflected in corresponding
* position in log entries.
*/
ContextCallbackList contextCallbacks_;
static std::atomic<InternalWarningHandler> warningHandler_;
};
/**
* initializeLoggerDB() will be called to configure the main LoggerDB singleton
* the first time that LoggerDB::get() is called.
*
* This function can be used apply basic default settings to the LoggerDB,
* including default log level and log handler settings.
*
* A default implementation is provided as a weak symbol, so it can be
* overridden on a per-program basis if you want to customize the initial
* LoggerDB settings for your program.
*
* However, note that this function may be invoked before main() starts (if
* other code that runs before main uses the logging library). Therefore you
* should be careful about what code runs here. For instance, you probably
* should not create LogHandler objects that spawn new threads. It is
* generally a good idea to defer more complicated setup until after main()
* starts.
*
* In most situations it is normally better to override getBaseLoggingConfig()
* from logging/Init.h rather than overriding initializeLoggerDB(). You only
* need to override initializeLoggerDB() if you want to change the settings
* that are used for messages that get logged before initLogging() is called.
*
* The default implementation configures the root log category to write all
* warning and higher-level log messages to stderr, using a format similar to
* that used by GLOG.
*/
void initializeLoggerDB(LoggerDB& db);
FOLLY_ALWAYS_INLINE LoggerDB& LoggerDB::get() {
struct Singleton : LoggerDB {
Singleton() {
initializeLoggerDB(*this);
// This allows log handlers to flush any buffered messages before
// the program exits.
/* library-local */ static auto guard =
makeGuard([this] { cleanupHandlers(); });
}
};
// We intentionally leak the LoggerDB singleton and all of the LogCategory
// objects it contains.
//
// We want Logger objects to remain valid for the entire lifetime of the
// program, without having to worry about destruction ordering issues, or
// making the Logger perform reference counting on the LoggerDB.
return detail::createGlobal<Singleton, void>();
}
} // namespace folly