logging: add LoggerDB::updateConfig() and resetConfig()
[folly.git] / folly / experimental / logging / LogCategory.h
1 /*
2  * Copyright 2004-present Facebook, Inc.
3  *
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
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 #pragma once
17
18 #include <atomic>
19 #include <cstdint>
20 #include <list>
21 #include <string>
22
23 #include <folly/Range.h>
24 #include <folly/Synchronized.h>
25 #include <folly/experimental/logging/LogLevel.h>
26
27 namespace folly {
28
29 class LoggerDB;
30 class LogHandler;
31 class LogMessage;
32
33 /**
34  * LogCategory stores all of the logging configuration for a specific
35  * log category.
36  *
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.
40  */
41 class LogCategory {
42  public:
43   /**
44    * Create the root LogCategory.
45    *
46    * This should generally only be invoked by LoggerDB.
47    */
48   explicit LogCategory(LoggerDB* db);
49
50   /**
51    * Create a new LogCategory.
52    *
53    * This should only be invoked by LoggerDB, while holding the main LoggerDB
54    * lock.
55    *
56    * The name argument should already be in canonical form.
57    *
58    * This constructor automatically adds this new LogCategory to the parent
59    * category's firstChild_ linked-list.
60    */
61   LogCategory(folly::StringPiece name, LogCategory* parent);
62
63   /**
64    * Get the name of this log category.
65    */
66   const std::string& getName() const {
67     return name_;
68   }
69
70   /**
71    * Get the level for this log category.
72    */
73   LogLevel getLevel() const {
74     return static_cast<LogLevel>(
75         level_.load(std::memory_order_acquire) & ~FLAG_INHERIT);
76   }
77
78   /**
79    * Get the log level and inheritance flag.
80    */
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)};
85   }
86
87   /**
88    * Get the effective level for this log category.
89    *
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
93    * parents.
94    */
95   LogLevel getEffectiveLevel() const {
96     return effectiveLevel_.load(std::memory_order_acquire);
97   }
98
99   /**
100    * Get the effective log level using std::memory_order_relaxed.
101    *
102    * This is primarily used for log message checks.  Most other callers should
103    * use getEffectiveLevel() above to be more conservative with regards to
104    * memory ordering.
105    */
106   LogLevel getEffectiveLevelRelaxed() const {
107     return effectiveLevel_.load(std::memory_order_relaxed);
108   }
109
110   /**
111    * Check whether this Logger or any of its parent Loggers would do anything
112    * with a log message at the given level.
113    */
114   bool logCheck(LogLevel level) const {
115     // We load the effective level using std::memory_order_relaxed.
116     //
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;
125   }
126
127   /**
128    * Set the log level for this LogCategory.
129    *
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.
132    *
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.)
138    */
139   void setLevel(LogLevel level, bool inherit = true);
140
141   /**
142    * Get the LoggerDB that this LogCategory belongs to.
143    *
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.
147    */
148   LoggerDB* getDB() const {
149     return db_;
150   }
151
152   /**
153    * Attach a LogHandler to this category.
154    */
155   void addHandler(std::shared_ptr<LogHandler> handler);
156
157   /**
158    * Remove all LogHandlers from this category.
159    */
160   void clearHandlers();
161
162   /**
163    * Get the list of LogHandlers attached to this category.
164    */
165   std::vector<std::shared_ptr<LogHandler>> getHandlers() const;
166
167   /**
168    * Replace the list of LogHandlers with a completely new list.
169    */
170   void replaceHandlers(std::vector<std::shared_ptr<LogHandler>> handlers);
171
172   /**
173    * Update the LogHandlers attached to this LogCategory by replacing
174    * currently attached handlers with new LogHandler objects.
175    *
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.
179    *
180    * This is used when the LogHandler configuration is changed requiring one or
181    * more LogHandler objects to be replaced with new ones.
182    */
183   void updateHandlers(const std::unordered_map<
184                       std::shared_ptr<LogHandler>,
185                       std::shared_ptr<LogHandler>>& handlerMap);
186
187   /* Internal methods for use by other parts of the logging library code */
188
189   /**
190    * Admit a message into the LogCategory hierarchy to be logged.
191    *
192    * The caller is responsible for having already performed log level
193    * admittance checks.
194    *
195    * This method generally should be invoked only through the logging macros,
196    * rather than calling this directly.
197    */
198   void admitMessage(const LogMessage& message) const;
199
200   /**
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.
204    *
205    * This method should only be invoked by LoggerDB.
206    */
207   void setLevelLocked(LogLevel level, bool inherit);
208
209   /**
210    * Register a std::atomic<LogLevel> value used by XLOG*() macros to check the
211    * effective level for this category.
212    *
213    * The LogCategory will keep this value updated whenever its effective log
214    * level changes.
215    *
216    * This function should only be invoked by LoggerDB, and the LoggerDB lock
217    * must be held when calling it.
218    */
219   void registerXlogLevel(std::atomic<LogLevel>* levelPtr);
220
221  private:
222   enum : uint32_t { FLAG_INHERIT = 0x80000000 };
223
224   // Forbidden copy constructor and assignment operator
225   LogCategory(LogCategory const&) = delete;
226   LogCategory& operator=(LogCategory const&) = delete;
227
228   void processMessage(const LogMessage& message) const;
229   void updateEffectiveLevel(LogLevel newEffectiveLevel);
230   void parentLevelUpdated(LogLevel parentEffectiveLevel);
231
232   /**
233    * The minimum log level of this category and all of its parents.
234    */
235   std::atomic<LogLevel> effectiveLevel_{LogLevel::MAX_LEVEL};
236
237   /**
238    * The current log level for this category.
239    *
240    * The most significant bit is used to indicate if this logger should
241    * inherit its parent's effective log level.
242    */
243   std::atomic<uint32_t> level_{0};
244
245   /**
246    * Our parent LogCategory in the category hierarchy.
247    *
248    * For instance, if our log name is "foo.bar.abc", our parent category
249    * is "foo.bar".
250    */
251   LogCategory* const parent_{nullptr};
252
253   /**
254    * Our log category name.
255    */
256   const std::string name_;
257
258   /**
259    * The list of LogHandlers attached to this category.
260    */
261   folly::Synchronized<std::vector<std::shared_ptr<LogHandler>>> handlers_;
262
263   /**
264    * A pointer to the LoggerDB that we belong to.
265    *
266    * This is almost always the main LoggerDB singleton.  Unit tests are the
267    * main place where we use other LoggerDB objects besides the singleton.
268    */
269   LoggerDB* const db_{nullptr};
270
271   /**
272    * Pointers to children and sibling loggers.
273    * These pointers should only ever be accessed while holding the
274    * LoggerDB::loggersByName_ lock.  (These are only modified when creating new
275    * loggers, which occurs with the main LoggerDB lock held.)
276    */
277   LogCategory* firstChild_{nullptr};
278   LogCategory* nextSibling_{nullptr};
279
280   /**
281    * A list of LogLevel values used by XLOG*() statements for this LogCategory.
282    * The XLOG*() statements will check these values.  We ensure they are kept
283    * up-to-date each time the effective log level changes for this category.
284    *
285    * This list may only be accessed while holding the main LoggerDB lock.
286    */
287   std::vector<std::atomic<LogLevel>*> xlogLevels_;
288 };
289 } // namespace folly