add a new logging library
[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 effective level for this log category.
80    *
81    * This is the minimum log level of this category and all of its parents.
82    * Log messages below this level will be ignored, while messages at or
83    * above this level need to be processed by this category or one of its
84    * parents.
85    */
86   LogLevel getEffectiveLevel() const {
87     return effectiveLevel_.load(std::memory_order_acquire);
88   }
89
90   /**
91    * Get the effective log level using std::memory_order_relaxed.
92    *
93    * This is primarily used for log message checks.  Most other callers should
94    * use getEffectiveLevel() above to be more conservative with regards to
95    * memory ordering.
96    */
97   LogLevel getEffectiveLevelRelaxed() const {
98     return effectiveLevel_.load(std::memory_order_relaxed);
99   }
100
101   /**
102    * Set the log level for this LogCategory.
103    *
104    * Messages logged to a specific log category will be ignored unless the
105    * message log level is greater than the LogCategory's effective log level.
106    *
107    * If inherit is true, LogCategory's effective log level is the minimum of
108    * its level and its parent category's effective log level.  If inherit is
109    * false, the LogCategory's effective log level is simply its log level.
110    * (Setting inherit to false is necessary if you want a child LogCategory to
111    * use a less verbose level than its parent categories.)
112    */
113   void setLevel(LogLevel level, bool inherit = true);
114
115   /**
116    * Process a log message.
117    *
118    * This method generally should be invoked through the Logger APIs,
119    * rather than calling this directly.
120    *
121    * This method assumes that log level admittance checks have already been
122    * performed.  This method unconditionally passes the message to the
123    * LogHandlers attached to this LogCategory, without any additional log level
124    * checks (apart from the ones done in the LogHandlers).
125    */
126   void processMessage(const LogMessage& message);
127
128   /**
129    * Get the LoggerDB that this LogCategory belongs to.
130    *
131    * This is almost always the main LoggerDB singleton returned by
132    * LoggerDB::get().  The logging unit tests are the main location that
133    * creates alternative LoggerDB objects.
134    */
135   LoggerDB* getDB() const {
136     return db_;
137   }
138
139   /**
140    * Attach a LogHandler to this category.
141    */
142   void addHandler(std::shared_ptr<LogHandler> handler);
143
144   /**
145    * Remove all LogHandlers from this category.
146    */
147   void clearHandlers();
148
149   /**
150    * Note: setLevelLocked() may only be called while holding the main
151    * LoggerDB lock.
152    *
153    * This method should only be invoked by LoggerDB.
154    */
155   void setLevelLocked(LogLevel level, bool inherit);
156
157  private:
158   enum : uint32_t { FLAG_INHERIT = 0x80000000 };
159
160   // Forbidden copy constructor and assignment operator
161   LogCategory(LogCategory const&) = delete;
162   LogCategory& operator=(LogCategory const&) = delete;
163
164   void updateEffectiveLevel(LogLevel newEffectiveLevel);
165   void parentLevelUpdated(LogLevel parentEffectiveLevel);
166
167   /**
168    * The minimum log level of this category and all of its parents.
169    */
170   std::atomic<LogLevel> effectiveLevel_{LogLevel::MAX_LEVEL};
171
172   /**
173    * The current log level for this category.
174    *
175    * The most significant bit is used to indicate if this logger should
176    * inherit its parent's effective log level.
177    */
178   std::atomic<uint32_t> level_{0};
179
180   /**
181    * Our parent LogCategory in the category hierarchy.
182    *
183    * For instance, if our log name is "foo.bar.abc", our parent category
184    * is "foo.bar".
185    */
186   LogCategory* const parent_{nullptr};
187
188   /**
189    * Our log category name.
190    */
191   const std::string name_;
192
193   /**
194    * The list of LogHandlers attached to this category.
195    */
196   folly::Synchronized<std::vector<std::shared_ptr<LogHandler>>> handlers_;
197
198   /**
199    * A pointer to the LoggerDB that we belong to.
200    *
201    * This is almost always the main LoggerDB singleton.  Unit tests are the
202    * main place where we use other LoggerDB objects besides the singleton.
203    */
204   LoggerDB* const db_{nullptr};
205
206   /**
207    * Pointers to children and sibling loggers.
208    * These pointers should only ever be accessed while holding the main
209    * LoggerDB lock.  (These are only modified when creating new loggers,
210    * which occurs with the main LoggerDB lock held.)
211    */
212   LogCategory* firstChild_{nullptr};
213   LogCategory* nextSibling_{nullptr};
214 };
215 }