3c17d6bf8cf2e78b77ce9e1cc52d52ca96fe2188
[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 #define XLOG_IMPL(level, type, ...)                                    \
116   (!XLOG_IS_ON_IMPL(level))                                            \
117       ? static_cast<void>(0)                                           \
118       : ::folly::LogStreamProcessorT<::folly::isLogLevelFatal(level)>( \
119             XLOG_GET_CATEGORY_INTERNAL(),                              \
120             (level),                                                   \
121             __FILE__,                                                  \
122             __LINE__,                                                  \
123             (type),                                                    \
124             ##__VA_ARGS__) &                                           \
125           ::folly::LogStream()
126
127 /**
128  * Check if and XLOG() statement with the given log level would be enabled.
129  */
130 #define XLOG_IS_ON(level) XLOG_IS_ON_IMPL(::folly::LogLevel::level)
131
132 /**
133  * Helper macro to implement of XLOG_IS_ON()
134  *
135  * This macro is used in the XLOG() implementation, and therefore must be as
136  * cheap as possible.  It stores the category's LogLevel as a local static
137  * variable.  The very first time this macro is evaluated it will look up the
138  * correct LogCategory and initialize the LogLevel.  Subsequent calls then
139  * are only a single conditional log level check.
140  *
141  * The LogCategory object keeps track of this local LogLevel variable and
142  * automatically keeps it up-to-date when the category's effective level is
143  * changed.
144  *
145  * Most of this code must live in the macro definition itself, and cannot be
146  * moved into a helper function: The getXlogCategoryName() call must be made as
147  * part of the macro expansion in order to work correctly.  We also want to
148  * avoid calling it whenever possible.  Therefore most of the logic must be
149  * done in the macro expansion.
150  *
151  * See XlogLevelInfo for the implementation details.
152  */
153 #define XLOG_IS_ON_IMPL(level)                                                 \
154   ([] {                                                                        \
155     static ::folly::XlogLevelInfo<XLOG_IS_IN_HEADER_FILE> _xlogLevel_;         \
156     const auto _xlogLevelToCheck_ = (level);                                   \
157     /*                                                                         \
158      * Do an initial relaxed check.  If this fails we know the category level  \
159      * is initialized and the log admittance check failed.                     \
160      * Use LIKELY() to optimize for the case of disabled debug statements:     \
161      * we disabled debug statements to be cheap.  If the log message is        \
162      * enabled then this check will still be minimal perf overhead compared to \
163      * the overall cost of logging it.                                         \
164      */                                                                        \
165     if (LIKELY(                                                                \
166             _xlogLevelToCheck_ <                                               \
167             _xlogLevel_.getLevel(                                              \
168                 &_xlogFileScopeInfo_, std::memory_order_relaxed))) {           \
169       return false;                                                            \
170     }                                                                          \
171     /*                                                                         \
172      * Load the level value with memory_order_acquire, and check               \
173      * to see if it is initialized or not.                                     \
174      */                                                                        \
175     auto _xlogCurrentLevel_ =                                                  \
176         _xlogLevel_.getLevel(&_xlogFileScopeInfo_, std::memory_order_acquire); \
177     if (UNLIKELY(_xlogCurrentLevel_ == ::folly::LogLevel::UNINITIALIZED)) {    \
178       _xlogCurrentLevel_ = _xlogLevel_.init(                                   \
179           getXlogCategoryName(__FILE__), &_xlogFileScopeInfo_);                \
180     }                                                                          \
181     return _xlogLevelToCheck_ >= _xlogCurrentLevel_;                           \
182   }())
183
184 /**
185  * Get the name of the log category that will be used by XLOG() statements
186  * in this file.
187  */
188 #define XLOG_GET_CATEGORY_NAME() getXlogCategoryName(__FILE__)
189
190 /**
191  * Get a pointer to the LogCategory that will be used by XLOG() statements in
192  * this file.
193  *
194  * This is just a small wrapper around a LoggerDB::getCategory() call.
195  * This must be implemented as a macro since it uses __FILE__, and that must
196  * expand to the correct filename based on where the macro is used.
197  */
198 #define XLOG_GET_CATEGORY() \
199   folly::LoggerDB::get()->getCategory(XLOG_GET_CATEGORY_NAME())
200
201 /**
202  * Internal version of XLOG_GET_CATEGORY() that is used in the XLOG() macro.
203  *
204  * This macro is used in the XLOG() implementation, and therefore must be as
205  * cheap as possible.  It stores the LogCategory* pointer as a local static
206  * variable.  Only the first invocation has to look up the log category by
207  * name.  Subsequent invocations re-use the already looked-up LogCategory
208  * pointer.
209  *
210  * This is only safe to call after XlogLevelInfo::init() has been called.
211  *
212  * Most of this code must live in the macro definition itself, and cannot be
213  * moved into a helper function: The getXlogCategoryName() call must be made as
214  * part of the macro expansion in order to work correctly.  We also want to
215  * avoid calling it whenever possible.  Therefore most of the logic must be
216  * done in the macro expansion.
217  *
218  * See XlogCategoryInfo for the implementation details.
219  */
220 #define XLOG_GET_CATEGORY_INTERNAL()                                         \
221   [] {                                                                       \
222     static ::folly::XlogCategoryInfo<XLOG_IS_IN_HEADER_FILE> _xlogCategory_; \
223     if (!_xlogCategory_.isInitialized()) {                                   \
224       return _xlogCategory_.init(getXlogCategoryName(__FILE__));             \
225     }                                                                        \
226     return _xlogCategory_.getCategory(&_xlogFileScopeInfo_);                 \
227   }()
228
229 /**
230  * XLOG_SET_CATEGORY_NAME() can be used to explicitly define the log category
231  * name used by all XLOG() and XLOGF() calls in this translation unit.
232  *
233  * This overrides the default behavior of picking a category name based on the
234  * current filename.
235  *
236  * This should be used at the top-level scope in a .cpp file, before any XLOG()
237  * or XLOGF() macros have been used in the file.
238  *
239  * XLOG_SET_CATEGORY_NAME() cannot be used inside header files.
240  */
241 #ifdef __INCLUDE_LEVEL__
242 #define XLOG_SET_CATEGORY_NAME(category)                              \
243   namespace {                                                         \
244   static_assert(                                                      \
245       __INCLUDE_LEVEL__ == 0,                                         \
246       "XLOG_SET_CATEGORY_NAME() should not be used in header files"); \
247   inline std::string getXlogCategoryName(const char*) {               \
248     return category;                                                  \
249   }                                                                   \
250   }
251 #else
252 #define XLOG_SET_CATEGORY_NAME(category)                \
253   namespace {                                           \
254   inline std::string getXlogCategoryName(const char*) { \
255     return category;                                    \
256   }                                                     \
257   }
258 #endif
259
260 /**
261  * XLOG_IS_IN_HEADER_FILE evaluates to false if we can definitively tell if we
262  * are not in a header file.  Otherwise, it evaluates to true.
263  */
264 #ifdef __INCLUDE_LEVEL__
265 #define XLOG_IS_IN_HEADER_FILE bool(__INCLUDE_LEVEL__ > 0)
266 #else
267 // Without __INCLUDE_LEVEL__ we canot tell if we are in a header file or not,
268 // and must pessimstically assume we are always in a header file.
269 #define XLOG_IS_IN_HEADER_FILE true
270 #endif
271
272 namespace folly {
273
274 class XlogFileScopeInfo {
275  public:
276 #ifdef __INCLUDE_LEVEL__
277   std::atomic<::folly::LogLevel> level;
278   ::folly::LogCategory* category;
279 #endif
280 };
281
282 /**
283  * A file-static XlogLevelInfo and XlogCategoryInfo object is declared for each
284  * XLOG() statement.
285  *
286  * We intentionally do not provide constructors for these structures, and rely
287  * on their members to be zero-initialized when the program starts.  This
288  * ensures that everything will work as desired even if XLOG() statements are
289  * used during dynamic object initialization before main().
290  */
291 template <bool IsInHeaderFile>
292 struct XlogLevelInfo {
293  public:
294   inline LogLevel getLevel(XlogFileScopeInfo*, std::memory_order order) {
295     return level_.load(order);
296   }
297
298   inline LogLevel init(folly::StringPiece categoryName, XlogFileScopeInfo*) {
299     return LoggerDB::get()->xlogInit(categoryName, &level_, nullptr);
300   }
301
302  private:
303   // This member will always be zero-initialized on program start.
304   std::atomic<LogLevel> level_;
305 };
306
307 template <bool IsInHeaderFile>
308 struct XlogCategoryInfo {
309  public:
310   bool isInitialized() const {
311     return isInitialized_.load(std::memory_order_acquire);
312   }
313
314   LogCategory* init(folly::StringPiece categoryName) {
315     return LoggerDB::get()->xlogInitCategory(
316         categoryName, &category_, &isInitialized_);
317   }
318
319   LogCategory* getCategory(XlogFileScopeInfo*) {
320     return category_;
321   }
322
323  private:
324   // These variables will always be zero-initialized on program start.
325   std::atomic<bool> isInitialized_;
326   LogCategory* category_;
327 };
328
329 #ifdef __INCLUDE_LEVEL__
330 /**
331  * Specialization of XlogLevelInfo for XLOG() statements in the .cpp file being
332  * compiled.  In this case we only define a single file-static LogLevel object
333  * for the entire file, rather than defining one for each XLOG() statement.
334  */
335 template <>
336 struct XlogLevelInfo<false> {
337  public:
338   inline LogLevel getLevel(
339       XlogFileScopeInfo* fileScopeInfo,
340       std::memory_order order) {
341     return fileScopeInfo->level.load(order);
342   }
343
344   inline LogLevel init(
345       folly::StringPiece categoryName,
346       XlogFileScopeInfo* fileScopeInfo) {
347     return LoggerDB::get()->xlogInit(
348         categoryName, &fileScopeInfo->level, &fileScopeInfo->category);
349   }
350 };
351
352 /**
353  * Specialization of XlogCategoryInfo for XLOG() statements in the .cpp file
354  * being compiled.  In this case we only define a single file-static LogLevel
355  * object for the entire file, rather than defining one for each XLOG()
356  * statement.
357  */
358 template <>
359 struct XlogCategoryInfo<false> {
360  public:
361   constexpr bool isInitialized() const {
362     // XlogLevelInfo<false>::init() is always called before XlogCategoryInfo
363     // is used, and it will have already initialized fileScopeInfo.
364     // Therefore we never have to check if it is initialized yet here.
365     return true;
366   }
367   [[noreturn]] LogCategory* init(folly::StringPiece /* categoryName */) {
368     // This method is never used given that isInitialized() always returns true
369     ::std::abort();
370   }
371   LogCategory* getCategory(XlogFileScopeInfo* fileScopeInfo) {
372     return fileScopeInfo->category;
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 }
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 /**
394  * The default getXlogCategoryName() implementation.
395  * This will be used if XLOG_SET_CATEGORY_NAME() has not been used yet.
396  *
397  * This is a template purely so that XLOG_SET_CATEGORY_NAME() can define a more
398  * specific version if desired, allowing XLOG_SET_CATEGORY_NAME() to override
399  * this implementation once it has been used.
400  */
401 template <typename T>
402 inline std::string getXlogCategoryName(const T* filename) {
403   return ::folly::getXlogCategoryNameForFile(filename);
404 }
405
406 /**
407  * File-scope LogLevel and LogCategory data for XLOG() statements,
408  * if __INCLUDE_LEVEL__ is supported.
409  *
410  * This allows us to only have one LogLevel and LogCategory pointer for the
411  * entire .cpp file, rather than needing a separate copy for each XLOG()
412  * statement.
413  */
414 ::folly::XlogFileScopeInfo _xlogFileScopeInfo_;
415 }