logging: implement FATAL and DFATAL log levels
[folly.git] / folly / experimental / logging / xlog.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 <folly/Likely.h>
19 #include <folly/Range.h>
20 #include <folly/experimental/logging/LogStream.h>
21 #include <folly/experimental/logging/Logger.h>
22 #include <folly/experimental/logging/LoggerDB.h>
23
24 /*
25  * This file contains the XLOG() and XLOGF() macros.
26  *
27  * These macros make it easy to use the logging library without having to
28  * manually pick log category names.  All XLOG() and XLOGF() statements in a
29  * given file automatically use a LogCategory based on the current file name.
30  *
31  * For instance, in src/foo/bar.cpp, the default log category name will be
32  * "src.foo.bar"
33  *
34  * If desired, the log category name used by XLOG() in a .cpp file may be
35  * overridden using XLOG_SET_CATEGORY() macro.
36  */
37
38 /**
39  * Log a message to this file's default log category.
40  *
41  * By default the log category name is automatically picked based on the
42  * current filename.  In src/foo/bar.cpp the log category name "src.foo.bar"
43  * will be used.  In "lib/stuff/foo.h" the log category name will be
44  * "lib.stuff.foo"
45  *
46  * Note that the filename is based on the __FILE__ macro defined by the
47  * compiler.  This is typically dependent on the filename argument that you
48  * give to the compiler.  For example, if you compile src/foo/bar.cpp by
49  * invoking the compiler inside src/foo and only give it "bar.cpp" as an
50  * argument, the category name will simply be "bar".  In general XLOG() works
51  * best if you always invoke the compiler from the root directory of your
52  * project repository.
53  */
54 #define XLOG(level, ...)                   \
55   XLOG_IMPL(                               \
56       ::folly::LogLevel::level,            \
57       ::folly::LogStreamProcessor::APPEND, \
58       ##__VA_ARGS__)
59
60 /**
61  * Log a message to this file's default log category, using a format string.
62  */
63 #define XLOGF(level, fmt, arg1, ...)       \
64   XLOG_IMPL(                               \
65       ::folly::LogLevel::level,            \
66       ::folly::LogStreamProcessor::FORMAT, \
67       fmt,                                 \
68       arg1,                                \
69       ##__VA_ARGS__)
70
71 /**
72  * Helper macro used to implement XLOG() and XLOGF()
73  *
74  * Beware that the level argument is evalutated twice.
75  *
76  * This macro is somewhat tricky:
77  *
78  * - In order to support streaming argument support (with the << operator),
79  *   the macro must expand to a single ternary ? expression.  This is the only
80  *   way we can avoid evaluating the log arguments if the log check fails,
81  *   and still have the macro behave as expected when used as the body of an if
82  *   or else statement.
83  *
84  * - We need to store some static-scope local state in order to track the
85  *   LogCategory to use.  This is a bit tricky to do and still meet the
86  *   requirements of being a single expression, but fortunately static
87  *   variables inside a lambda work for this purpose.
88  *
89  *   Inside header files, each XLOG() statement defines to static variables:
90  *   - the LogLevel for this category
91  *   - a pointer to the LogCategory
92  *
93  *   If the __INCLUDE_LEVEL__ macro is available (both gcc and clang support
94  *   this), then we we can detect when we are inside a .cpp file versus a
95  *   header file.  If we are inside a .cpp file, we can avoid declaring these
96  *   variables once per XLOG() statement, and instead we only declare one copy
97  *   of these variables for the entire file.
98  *
99  * - We want to make sure this macro is safe to use even from inside static
100  *   initialization code that runs before main.  We also want to make the log
101  *   admittance check as cheap as possible, so that disabled debug logs have
102  *   minimal overhead, and can be left in place even in performance senstive
103  *   code.
104  *
105  *   In order to do this, we rely on zero-initialization of variables with
106  *   static storage duration.  The LogLevel variable will always be
107  *   0-initialized before any code runs.  Therefore the very first time an
108  *   XLOG() statement is hit the initial log level check will always pass
109  *   (since all level values are greater or equal to 0), and we then do a
110  *   second check to see if the log level and category variables need to be
111  *   initialized.  On all subsequent calls, disabled log statements can be
112  *   skipped with just a single check of the LogLevel.
113  */
114 #define XLOG_IMPL(level, type, ...)                                    \
115   (!XLOG_IS_ON_IMPL(level))                                            \
116       ? static_cast<void>(0)                                           \
117       : ::folly::LogStreamProcessorT<::folly::isLogLevelFatal(level)>( \
118             XLOG_GET_CATEGORY(),                                       \
119             (level),                                                   \
120             __FILE__,                                                  \
121             __LINE__,                                                  \
122             (type),                                                    \
123             ##__VA_ARGS__) &                                           \
124           ::folly::LogStream()
125
126 /**
127  * Check if and XLOG() statement with the given log level would be enabled.
128  */
129 #define XLOG_IS_ON(level) XLOG_IS_ON_IMPL(::folly::LogLevel::level)
130
131 /**
132  * Helper macro to implement of XLOG_IS_ON()
133  *
134  * This macro is used in the XLOG() implementation, and therefore must be as
135  * cheap as possible.  It stores the category's LogLevel as a local static
136  * variable.  The very first time this macro is evaluated it will look up the
137  * correct LogCategory and initialize the LogLevel.  Subsequent calls then
138  * are only a single conditional log level check.
139  *
140  * The LogCategory object keeps track of this local LogLevel variable and
141  * automatically keeps it up-to-date when the category's effective level is
142  * changed.
143  *
144  * Most of this code must live in the macro definition itself, and cannot be
145  * moved into a helper function: The getXlogCategoryName() call must be made as
146  * part of the macro expansion in order to work correctly.  We also want to
147  * avoid calling it whenever possible.  Therefore most of the logic must be
148  * done in the macro expansion.
149  *
150  * See XlogLevelInfo for the implementation details.
151  */
152 #define XLOG_IS_ON_IMPL(level)                                                 \
153   ([] {                                                                        \
154     static ::folly::XlogLevelInfo<XLOG_IS_IN_HEADER_FILE> _xlogLevel_;         \
155     const auto _xlogLevelToCheck_ = (level);                                   \
156     /*                                                                         \
157      * Do an initial relaxed check.  If this fails we know the category level  \
158      * is initialized and the log admittance check failed.                     \
159      * Use LIKELY() to optimize for the case of disabled debug statements:     \
160      * we disabled debug statements to be cheap.  If the log message is        \
161      * enabled then this check will still be minimal perf overhead compared to \
162      * the overall cost of logging it.                                         \
163      */                                                                        \
164     if (LIKELY(                                                                \
165             _xlogLevelToCheck_ <                                               \
166             _xlogLevel_.getLevel(                                              \
167                 &_xlogFileScopeInfo_, std::memory_order_relaxed))) {           \
168       return false;                                                            \
169     }                                                                          \
170     /*                                                                         \
171      * Load the level value with memory_order_acquire, and check               \
172      * to see if it is initialized or not.                                     \
173      */                                                                        \
174     auto _xlogCurrentLevel_ =                                                  \
175         _xlogLevel_.getLevel(&_xlogFileScopeInfo_, std::memory_order_acquire); \
176     if (UNLIKELY(_xlogCurrentLevel_ == ::folly::LogLevel::UNINITIALIZED)) {    \
177       _xlogCurrentLevel_ = _xlogLevel_.init(                                   \
178           getXlogCategoryName(__FILE__), &_xlogFileScopeInfo_);                \
179     }                                                                          \
180     return _xlogLevelToCheck_ >= _xlogCurrentLevel_;                           \
181   }())
182
183 /**
184  * Get a pointer to the LogCategory that will be used by XLOG() statements in
185  * this file.
186  *
187  * This macro is used in the XLOG() implementation, and therefore must be as
188  * cheap as possible.  It stores the LogCategory* pointer as a local static
189  * variable.  Only the first invocation has to look up the log category by
190  * name.  Subsequent invocations re-use the already looked-up LogCategory
191  * pointer.
192  *
193  * Most of this code must live in the macro definition itself, and cannot be
194  * moved into a helper function: The getXlogCategoryName() call must be made as
195  * part of the macro expansion in order to work correctly.  We also want to
196  * avoid calling it whenever possible.  Therefore most of the logic must be
197  * done in the macro expansion.
198  *
199  * See XlogCategoryInfo for the implementation details.
200  */
201 #define XLOG_GET_CATEGORY()                                                  \
202   [] {                                                                       \
203     static ::folly::XlogCategoryInfo<XLOG_IS_IN_HEADER_FILE> _xlogCategory_; \
204     if (!_xlogCategory_.isInitialized()) {                                   \
205       return _xlogCategory_.init(getXlogCategoryName(__FILE__));             \
206     }                                                                        \
207     return _xlogCategory_.getCategory(&_xlogFileScopeInfo_);                 \
208   }()
209
210 /**
211  * XLOG_SET_CATEGORY() can be used to explicitly define the log category name
212  * used by all XLOG() and XLOGF() calls in this translation unit.
213  *
214  * This overrides the default behavior of picking a category name based on the
215  * current filename.
216  *
217  * This should be used at the top-level scope in a .cpp file, before any XLOG()
218  * or XLOGF() macros have been used in the file.
219  *
220  * XLOG_SET_CATEGORY() cannot be used inside header files.
221  */
222 #ifdef __INCLUDE_LEVEL__
223 #define XLOG_SET_CATEGORY(category)                              \
224   namespace {                                                    \
225   static_assert(                                                 \
226       __INCLUDE_LEVEL__ == 0,                                    \
227       "XLOG_SET_CATEGORY() should not be used in header files"); \
228   inline std::string getXlogCategoryName(const char*) {          \
229     return category;                                             \
230   }                                                              \
231   }
232 #else
233 #define XLOG_SET_CATEGORY(category)                     \
234   namespace {                                           \
235   inline std::string getXlogCategoryName(const char*) { \
236     return category;                                    \
237   }                                                     \
238   }
239 #endif
240
241 /**
242  * XLOG_IS_IN_HEADER_FILE evaluates to false if we can definitively tell if we
243  * are not in a header file.  Otherwise, it evaluates to true.
244  */
245 #ifdef __INCLUDE_LEVEL__
246 #define XLOG_IS_IN_HEADER_FILE bool(__INCLUDE_LEVEL__ > 0)
247 #else
248 // Without __INCLUDE_LEVEL__ we canot tell if we are in a header file or not,
249 // and must pessimstically assume we are always in a header file.
250 #define XLOG_IS_IN_HEADER_FILE true
251 #endif
252
253 namespace folly {
254
255 class XlogFileScopeInfo {
256  public:
257 #ifdef __INCLUDE_LEVEL__
258   std::atomic<::folly::LogLevel> level;
259   ::folly::LogCategory* category;
260 #endif
261 };
262
263 /**
264  * A file-static XlogLevelInfo and XlogCategoryInfo object is declared for each
265  * XLOG() statement.
266  *
267  * We intentionally do not provide constructors for these structures, and rely
268  * on their members to be zero-initialized when the program starts.  This
269  * ensures that everything will work as desired even if XLOG() statements are
270  * used during dynamic object initialization before main().
271  */
272 template <bool IsInHeaderFile>
273 struct XlogLevelInfo {
274  public:
275   inline LogLevel getLevel(XlogFileScopeInfo*, std::memory_order order) {
276     return level_.load(order);
277   }
278
279   inline LogLevel init(folly::StringPiece categoryName, XlogFileScopeInfo*) {
280     return LoggerDB::get()->xlogInit(categoryName, &level_, nullptr);
281   }
282
283  private:
284   // This member will always be zero-initialized on program start.
285   std::atomic<LogLevel> level_;
286 };
287
288 template <bool IsInHeaderFile>
289 struct XlogCategoryInfo {
290  public:
291   bool isInitialized() {
292     return isInitialized_.load(std::memory_order_acquire);
293   }
294
295   LogCategory* init(folly::StringPiece categoryName) {
296     return LoggerDB::get()->xlogInitCategory(
297         categoryName, &category_, &isInitialized_);
298   }
299
300   LogCategory* getCategory(XlogFileScopeInfo*) {
301     return category_;
302   }
303
304  private:
305   // These variables will always be zero-initialized on program start.
306   std::atomic<bool> isInitialized_;
307   LogCategory* category_;
308 };
309
310 #ifdef __INCLUDE_LEVEL__
311 /**
312  * Specialization of XlogLevelInfo for XLOG() statements in the .cpp file being
313  * compiled.  In this case we only define a single file-static LogLevel object
314  * for the entire file, rather than defining one for each XLOG() statement.
315  */
316 template <>
317 struct XlogLevelInfo<false> {
318  public:
319   inline LogLevel getLevel(
320       XlogFileScopeInfo* fileScopeInfo,
321       std::memory_order order) {
322     return fileScopeInfo->level.load(order);
323   }
324
325   inline LogLevel init(
326       folly::StringPiece categoryName,
327       XlogFileScopeInfo* fileScopeInfo) {
328     return LoggerDB::get()->xlogInit(
329         categoryName, &fileScopeInfo->level, &fileScopeInfo->category);
330   }
331 };
332
333 /**
334  * Specialization of XlogCategoryInfo for XLOG() statements in the .cpp file
335  * being compiled.  In this case we only define a single file-static LogLevel
336  * object for the entire file, rather than defining one for each XLOG()
337  * statement.
338  */
339 template <>
340 struct XlogCategoryInfo<false> {
341  public:
342   constexpr bool isInitialized() {
343     // XlogLevelInfo<false>::check() is always called before XlogCategoryInfo
344     // is used, and it will will have already initialized fileScopeInfo.
345     // Therefore we never have to check if it is initialized yet here.
346     return true;
347   }
348   LogCategory* init(folly::StringPiece) {
349     // This method is never used given that isInitialized() always returns true
350     abort();
351     return nullptr;
352   }
353   LogCategory* getCategory(XlogFileScopeInfo* fileScopeInfo) {
354     return fileScopeInfo->category;
355   }
356 };
357 #endif
358
359 /**
360  * Get the default XLOG() category name for the given filename.
361  *
362  * This function returns the category name that will be used by XLOG() if
363  * XLOG_SET_CATEGORY() has not been used.
364  */
365 std::string getXlogCategoryNameForFile(folly::StringPiece filename);
366 }
367
368 /*
369  * We intentionally use an unnamed namespace inside a header file here.
370  *
371  * We want each .cpp file that uses xlog.h to get its own separate
372  * implementation of the following functions and variables.
373  */
374 namespace {
375 /**
376  * The default getXlogCategoryName() implementation.
377  * This will be used if XLOG_SET_CATEGORY() has not been used yet.
378  *
379  * This is a template purely so that XLOG_SET_CATEGORY() can define a more
380  * specific version if desired, allowing XLOG_SET_CATEGORY() to override this
381  * implementation once it has been used.  The template paramete
382  */
383 template <typename T>
384 inline std::string getXlogCategoryName(const T* filename) {
385   return ::folly::getXlogCategoryNameForFile(filename);
386 }
387
388 /**
389  * File-scope LogLevel and LogCategory data for XLOG() statements,
390  * if __INCLUDE_LEVEL__ is supported.
391  *
392  * This allows us to only have one LogLevel and LogCategory pointer for the
393  * entire .cpp file, rather than needing a separate copy for each XLOG()
394  * statement.
395  */
396 ::folly::XlogFileScopeInfo _xlogFileScopeInfo_;
397 }