2 * Copyright 2004-present Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <folly/Conv.h>
19 #include <folly/CppAttributes.h>
20 #include <folly/Range.h>
21 #include <folly/Synchronized.h>
24 #include <unordered_map>
27 #include <folly/experimental/logging/LogName.h>
34 class LogHandlerFactory;
35 enum class LogLevel : uint32_t;
38 * LoggerDB stores the set of LogCategory objects.
43 * Get the main LoggerDB singleton.
45 static LoggerDB* get();
50 * Get the LogCategory for the specified name.
52 * This creates the LogCategory for the specified name if it does not exist
55 LogCategory* getCategory(folly::StringPiece name);
58 * Get the LogCategory for the specified name, if it already exists.
60 * This returns nullptr if no LogCategory has been created yet for the
63 LogCategory* FOLLY_NULLABLE getCategoryOrNull(folly::StringPiece name);
66 * Set the log level for the specified category.
68 * Messages logged to a specific log category will be ignored unless the
69 * message log level is greater than the LogCategory's effective log level.
71 * If inherit is true, LogCategory's effective log level is the minimum of
72 * its level and it's parent category's effective log level. If inherit is
73 * false, the LogCategory's effective log level is simply its log level.
74 * (Setting inherit to false is necessary if you want a child LogCategory to
75 * use a less verbose level than its parent categories.)
77 void setLevel(folly::StringPiece name, LogLevel level, bool inherit = true);
78 void setLevel(LogCategory* category, LogLevel level, bool inherit = true);
81 * Get a LogConfig object describing the current state of the LoggerDB.
83 * Note that this may not 100% accurately describe the current configuration
84 * if callers have manually added LogHandlers to some categories without
85 * using the updateConfig() or resetConfig() functions. In this case
86 * getConfig() will simply report these handlers as "unknown_handler" when
87 * returning handler names for the categories in question.
89 LogConfig getConfig() const;
92 * Update the current LoggerDB state with the specified LogConfig settings.
94 * Log categories and handlers listed in the LogConfig object will be updated
95 * to the new state listed in the LogConfig. Settings on categories and
96 * handlers not listed in the config will be left as-is.
98 void updateConfig(const LogConfig& config);
101 * Reset the current LoggerDB state to the specified LogConfig settings.
103 * All LogCategories not mentioned in the new LogConfig will have all
104 * currently configured log handlers removed and their log level set to its
105 * default state. For the root category the default log level is ERR; for
106 * all other categories the default level is MAX_LEVEL with log level
107 * inheritance enabled.
109 * LogCategories listed in the new config but without LogHandler information
110 * defined will have all existing handlers removed.
112 void resetConfig(const LogConfig& config);
115 * Remove all registered LogHandlers on all LogCategory objects.
117 * This is called on the main LoggerDB object during shutdown.
119 void cleanupHandlers();
122 * Call flush() on all LogHandler objects registered on any LogCategory in
125 * Returns the number of registered LogHandlers.
127 size_t flushAllHandlers();
130 * Register a LogHandlerFactory.
132 * The LogHandlerFactory will be used to create LogHandler objects from a
133 * LogConfig object during updateConfig() and resetConfig() calls.
135 * Only one factory can be registered for a given handler type name.
136 * LogHandlerFactory::getType() returns the handler type supported by this
139 * If an existing LogHandlerFactory is already registered with this type name
140 * and replaceExisting is false a std::range_error will be thrown.
141 * Otherwise, if replaceExisting is true, the new factory will replace the
144 void registerHandlerFactory(
145 std::unique_ptr<LogHandlerFactory> factory,
146 bool replaceExisting = false);
149 * Remove a registered LogHandlerFactory.
151 * The type parameter should be the name of the handler type, as returned by
152 * LogHandlerFactory::getType().
154 * Throws std::range_error if no handler factory with this type name exists.
156 void unregisterHandlerFactory(folly::StringPiece type);
159 * Initialize the LogCategory* and std::atomic<LogLevel> used by an XLOG()
162 * Returns the current effective LogLevel of the category.
165 folly::StringPiece categoryName,
166 std::atomic<LogLevel>* xlogCategoryLevel,
167 LogCategory** xlogCategory);
168 LogCategory* xlogInitCategory(
169 folly::StringPiece categoryName,
170 LogCategory** xlogCategory,
171 std::atomic<bool>* isInitialized);
173 enum TestConstructorArg { TESTING };
176 * Construct a LoggerDB for testing purposes.
178 * Most callers should not need this function, and should use
179 * LoggerDB::get() to obtain the main LoggerDB singleton. This function
180 * exists mainly to allow testing LoggerDB objects in unit tests.
181 * It requires an explicit argument just to prevent callers from calling it
184 explicit LoggerDB(TestConstructorArg);
187 * internalWarning() is used to report a problem when something goes wrong
188 * internally in the logging library.
190 * We can't log these messages through the normal logging flow since logging
193 * Example scenarios where this is used:
194 * - We fail to write to a log file (for instance, when the disk is full)
195 * - A LogHandler throws an unexpected exception
197 template <typename... Args>
198 static void internalWarning(
199 folly::StringPiece file,
201 Args&&... args) noexcept {
203 file, lineNumber, folly::to<std::string>(std::forward<Args>(args)...));
206 using InternalWarningHandler =
207 void (*)(folly::StringPiece file, int lineNumber, std::string&&);
210 * Set a function to be called when the logging library generates an internal
213 * The supplied handler should never throw exceptions.
215 * If a null handler is supplied, the default built-in handler will be used.
217 * The default handler reports the message with _CrtDbgReport(_CRT_WARN) on
218 * Windows, and prints the message to stderr on other platforms. It also
219 * rate limits messages if they are arriving too quickly.
221 static void setInternalWarningHandler(InternalWarningHandler handler);
224 using LoggerNameMap = std::unordered_map<
226 std::unique_ptr<LogCategory>,
230 using HandlerFactoryMap =
231 std::unordered_map<std::string, std::unique_ptr<LogHandlerFactory>>;
232 using HandlerMap = std::unordered_map<std::string, std::weak_ptr<LogHandler>>;
234 HandlerFactoryMap factories;
238 // Forbidden copy constructor and assignment operator
239 LoggerDB(LoggerDB const&) = delete;
240 LoggerDB& operator=(LoggerDB const&) = delete;
243 LogCategory* getOrCreateCategoryLocked(
244 LoggerNameMap& loggersByName,
245 folly::StringPiece name);
246 LogCategory* createCategoryLocked(
247 LoggerNameMap& loggersByName,
248 folly::StringPiece name,
249 LogCategory* parent);
251 using NewHandlerMap =
252 std::unordered_map<std::string, std::shared_ptr<LogHandler>>;
253 using OldToNewHandlerMap = std::
254 unordered_map<std::shared_ptr<LogHandler>, std::shared_ptr<LogHandler>>;
255 void startConfigUpdate(
256 const Synchronized<HandlerInfo>::LockedPtr& handlerInfo,
257 const LogConfig& config,
258 NewHandlerMap* handlers,
259 OldToNewHandlerMap* oldToNewHandlerMap);
260 void finishConfigUpdate(
261 const Synchronized<HandlerInfo>::LockedPtr& handlerInfo,
262 NewHandlerMap* handlers,
263 OldToNewHandlerMap* oldToNewHandlerMap);
264 std::vector<std::shared_ptr<LogHandler>> buildCategoryHandlerList(
265 const NewHandlerMap& handlerMap,
266 StringPiece categoryName,
267 const std::vector<std::string>& categoryHandlerNames);
269 static void internalWarningImpl(
270 folly::StringPiece filename,
272 std::string&& msg) noexcept;
273 static void defaultInternalWarningImpl(
274 folly::StringPiece filename,
276 std::string&& msg) noexcept;
279 * A map of LogCategory objects by name.
281 * Lookups can be performed using arbitrary StringPiece values that do not
282 * have to be in canonical form.
284 folly::Synchronized<LoggerNameMap> loggersByName_;
287 * The LogHandlers and LogHandlerFactories.
289 * For lock ordering purposes, if you need to acquire both the loggersByName_
290 * and handlerInfo_ locks, the handlerInfo_ lock must be acquired first.
292 folly::Synchronized<HandlerInfo> handlerInfo_;
294 static std::atomic<InternalWarningHandler> warningHandler_;