2 * Copyright 2017-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.
23 #include <folly/Range.h>
24 #include <folly/Synchronized.h>
25 #include <folly/experimental/logging/LogLevel.h>
34 * LogCategory stores all of the logging configuration for a specific
37 * This class is separate from Logger to allow multiple Logger objects to all
38 * refer to the same log category. Logger can be thought of as a small wrapper
39 * class that behaves like a pointer to a LogCategory object.
44 * Create the root LogCategory.
46 * This should generally only be invoked by LoggerDB.
48 explicit LogCategory(LoggerDB* db);
51 * Create a new LogCategory.
53 * This should only be invoked by LoggerDB, while holding the main LoggerDB
56 * The name argument should already be in canonical form.
58 * This constructor automatically adds this new LogCategory to the parent
59 * category's firstChild_ linked-list.
61 LogCategory(folly::StringPiece name, LogCategory* parent);
64 * Get the name of this log category.
66 const std::string& getName() const {
71 * Get the level for this log category.
73 LogLevel getLevel() const {
74 return static_cast<LogLevel>(
75 level_.load(std::memory_order_acquire) & ~FLAG_INHERIT);
79 * Get the log level and inheritance flag.
81 std::pair<LogLevel, bool> getLevelInfo() const {
82 auto value = level_.load(std::memory_order_acquire);
83 return {static_cast<LogLevel>(value & ~FLAG_INHERIT),
84 bool(value & FLAG_INHERIT)};
88 * Get the effective level for this log category.
90 * This is the minimum log level of this category and all of its parents.
91 * Log messages below this level will be ignored, while messages at or
92 * above this level need to be processed by this category or one of its
95 LogLevel getEffectiveLevel() const {
96 return effectiveLevel_.load(std::memory_order_acquire);
100 * Get the effective log level using std::memory_order_relaxed.
102 * This is primarily used for log message checks. Most other callers should
103 * use getEffectiveLevel() above to be more conservative with regards to
106 LogLevel getEffectiveLevelRelaxed() const {
107 return effectiveLevel_.load(std::memory_order_relaxed);
111 * Check whether this Logger or any of its parent Loggers would do anything
112 * with a log message at the given level.
114 bool logCheck(LogLevel level) const {
115 // We load the effective level using std::memory_order_relaxed.
117 // We want to make log checks as lightweight as possible. It's fine if we
118 // don't immediately respond to changes made to the log level from other
119 // threads. We can wait until some other operation triggers a memory
120 // barrier before we honor the new log level setting. No other memory
121 // accesses depend on the log level value. Callers should not rely on all
122 // other threads to immediately stop logging as soon as they decrease the
123 // log level for a given category.
124 return effectiveLevel_.load(std::memory_order_relaxed) <= level;
128 * Set the log level for this LogCategory.
130 * Messages logged to a specific log category will be ignored unless the
131 * message log level is greater than the LogCategory's effective log level.
133 * If inherit is true, LogCategory's effective log level is the minimum of
134 * its level and its parent category's effective log level. If inherit is
135 * false, the LogCategory's effective log level is simply its log level.
136 * (Setting inherit to false is necessary if you want a child LogCategory to
137 * use a less verbose level than its parent categories.)
139 void setLevel(LogLevel level, bool inherit = true);
142 * Get the LoggerDB that this LogCategory belongs to.
144 * This is almost always the main LoggerDB singleton returned by
145 * LoggerDB::get(). The logging unit tests are the main location that
146 * creates alternative LoggerDB objects.
148 LoggerDB* getDB() const {
153 * Attach a LogHandler to this category.
155 void addHandler(std::shared_ptr<LogHandler> handler);
158 * Remove all LogHandlers from this category.
160 void clearHandlers();
163 * Get the list of LogHandlers attached to this category.
165 std::vector<std::shared_ptr<LogHandler>> getHandlers() const;
168 * Replace the list of LogHandlers with a completely new list.
170 void replaceHandlers(std::vector<std::shared_ptr<LogHandler>> handlers);
173 * Update the LogHandlers attached to this LogCategory by replacing
174 * currently attached handlers with new LogHandler objects.
176 * The handlerMap argument is a map of (old_handler -> new_handler)
177 * If any of the LogHandlers currently attached to this category are found in
178 * the handlerMap, replace them with the new handler indicated in the map.
180 * This is used when the LogHandler configuration is changed requiring one or
181 * more LogHandler objects to be replaced with new ones.
183 void updateHandlers(const std::unordered_map<
184 std::shared_ptr<LogHandler>,
185 std::shared_ptr<LogHandler>>& handlerMap);
187 /* Internal methods for use by other parts of the logging library code */
190 * Admit a message into the LogCategory hierarchy to be logged.
192 * The caller is responsible for having already performed log level
195 * This method generally should be invoked only through the logging macros,
196 * rather than calling this directly.
198 void admitMessage(const LogMessage& message) const;
201 * Note: setLevelLocked() may only be called while holding the
202 * LoggerDB loggersByName_ lock. It is safe to call this while holding the
203 * loggersByName_ lock in read-mode; holding it exclusively is not required.
205 * This method should only be invoked by LoggerDB.
207 void setLevelLocked(LogLevel level, bool inherit);
210 * Register a std::atomic<LogLevel> value used by XLOG*() macros to check the
211 * effective level for this category.
213 * The LogCategory will keep this value updated whenever its effective log
216 * This function should only be invoked by LoggerDB, and the LoggerDB lock
217 * must be held when calling it.
219 void registerXlogLevel(std::atomic<LogLevel>* levelPtr);
222 enum : uint32_t { FLAG_INHERIT = 0x80000000 };
224 // FLAG_INHERIT is the stored in the uppermost bit of the LogLevel field.
225 // assert that it does not conflict with valid LogLevel values.
227 static_cast<uint32_t>(LogLevel::MAX_LEVEL) < FLAG_INHERIT,
228 "The FLAG_INHERIT bit must not be set in any valid LogLevel value");
230 // Forbidden copy constructor and assignment operator
231 LogCategory(LogCategory const&) = delete;
232 LogCategory& operator=(LogCategory const&) = delete;
234 void processMessage(const LogMessage& message) const;
235 void updateEffectiveLevel(LogLevel newEffectiveLevel);
236 void parentLevelUpdated(LogLevel parentEffectiveLevel);
239 * The minimum log level of this category and all of its parents.
241 std::atomic<LogLevel> effectiveLevel_{LogLevel::MAX_LEVEL};
244 * The current log level for this category.
246 * The most significant bit is used to indicate if this logger should
247 * inherit its parent's effective log level.
249 std::atomic<uint32_t> level_{0};
252 * Our parent LogCategory in the category hierarchy.
254 * For instance, if our log name is "foo.bar.abc", our parent category
257 LogCategory* const parent_{nullptr};
260 * Our log category name.
262 const std::string name_;
265 * The list of LogHandlers attached to this category.
267 folly::Synchronized<std::vector<std::shared_ptr<LogHandler>>> handlers_;
270 * A pointer to the LoggerDB that we belong to.
272 * This is almost always the main LoggerDB singleton. Unit tests are the
273 * main place where we use other LoggerDB objects besides the singleton.
275 LoggerDB* const db_{nullptr};
278 * Pointers to children and sibling loggers.
279 * These pointers should only ever be accessed while holding the
280 * LoggerDB::loggersByName_ lock. (These are only modified when creating new
281 * loggers, which occurs with the main LoggerDB lock held.)
283 LogCategory* firstChild_{nullptr};
284 LogCategory* nextSibling_{nullptr};
287 * A list of LogLevel values used by XLOG*() statements for this LogCategory.
288 * The XLOG*() statements will check these values. We ensure they are kept
289 * up-to-date each time the effective log level changes for this category.
291 * This list may only be accessed while holding the main LoggerDB lock.
293 std::vector<std::atomic<LogLevel>*> xlogLevels_;