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