1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
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 
17 #pragma once
18 
19 #include <cstdlib>
20 
21 #include <folly/Likely.h>
22 #include <folly/Portability.h>
23 #include <folly/Range.h>
24 #include <folly/logging/LogStream.h>
25 #include <folly/logging/Logger.h>
26 #include <folly/logging/LoggerDB.h>
27 #include <folly/logging/ObjectToString.h>
28 #include <folly/logging/RateLimiter.h>
29 
30 /*
31  * This file contains the XLOG() and XLOGF() macros.
32  *
33  * These macros make it easy to use the logging library without having to
34  * manually pick log category names.  All XLOG() and XLOGF() statements in a
35  * given file automatically use a LogCategory based on the current file name.
36  *
37  * For instance, in src/foo/bar.cpp, the default log category name will be
38  * "src.foo.bar"
39  *
40  * If desired, the log category name used by XLOG() in a .cpp file may be
41  * overridden using XLOG_SET_CATEGORY_NAME() macro.
42  */
43 
44 /**
45  * Log a message to this file's default log category.
46  *
47  * By default the log category name is automatically picked based on the
48  * current filename.  In src/foo/bar.cpp the log category name "src.foo.bar"
49  * will be used.  In "lib/stuff/foo.h" the log category name will be
50  * "lib.stuff.foo"
51  *
52  * Note that the filename is based on the __FILE__ macro defined by the
53  * compiler.  This is typically dependent on the filename argument that you
54  * give to the compiler.  For example, if you compile src/foo/bar.cpp by
55  * invoking the compiler inside src/foo and only give it "bar.cpp" as an
56  * argument, the category name will simply be "bar".  In general XLOG() works
57  * best if you always invoke the compiler from the root directory of your
58  * project repository.
59  */
60 
61 /*
62  * The global value of FOLLY_XLOG_MIN_LEVEL. All the messages logged to
63  * XLOG(XXX) with severity less than FOLLY_XLOG_MIN_LEVEL will not be displayed.
64  * If it can be determined at compile time that the message will not be printed,
65  * the statement will be compiled out.
66  * FOLLY_XLOG_MIN_LEVEL should be below FATAL.
67  *
68  *
69  * Example: to strip out messages less than ERR, use the value of ERR below.
70  */
71 #ifndef FOLLY_XLOG_MIN_LEVEL
72 #define FOLLY_XLOG_MIN_LEVEL MIN_LEVEL
73 #endif
74 
75 namespace folly {
76 constexpr auto kLoggingMinLevel = LogLevel::FOLLY_XLOG_MIN_LEVEL;
77 static_assert(
78     !isLogLevelFatal(kLoggingMinLevel),
79     "Cannot set FOLLY_XLOG_MIN_LEVEL to disable fatal messages");
80 } // namespace folly
81 
82 #define XLOG(level, ...)                   \
83   XLOG_IMPL(                               \
84       ::folly::LogLevel::level,            \
85       ::folly::LogStreamProcessor::APPEND, \
86       ##__VA_ARGS__)
87 
88 /**
89  * Log a message if and only if the specified condition predicate evaluates
90  * to true. Note that the condition is *only* evaluated if the log-level check
91  * passes.
92  */
93 #define XLOG_IF(level, cond, ...)          \
94   XLOG_IF_IMPL(                            \
95       ::folly::LogLevel::level,            \
96       cond,                                \
97       ::folly::LogStreamProcessor::APPEND, \
98       ##__VA_ARGS__)
99 /**
100  * Log a message to this file's default log category, using a format string.
101  */
102 #define XLOGF(level, fmt, arg1, ...)       \
103   XLOG_IMPL(                               \
104       ::folly::LogLevel::level,            \
105       ::folly::LogStreamProcessor::FORMAT, \
106       fmt,                                 \
107       arg1,                                \
108       ##__VA_ARGS__)
109 
110 /**
111  * Log a message using a format string if and only if the specified condition
112  * predicate evaluates to true. Note that the condition is *only* evaluated
113  * if the log-level check passes.
114  */
115 #define XLOGF_IF(level, cond, fmt, arg1, ...) \
116   XLOG_IF_IMPL(                               \
117       ::folly::LogLevel::level,               \
118       cond,                                   \
119       ::folly::LogStreamProcessor::FORMAT,    \
120       fmt,                                    \
121       arg1,                                   \
122       ##__VA_ARGS__)
123 
124 /**
125  * Similar to XLOG(...) except only log a message every @param ms
126  * milliseconds.
127  *
128  * Note that this is threadsafe.
129  */
130 #define XLOG_EVERY_MS(level, ms, ...)                                  \
131   XLOG_IF(                                                             \
132       level,                                                           \
133       [__folly_detail_xlog_ms = ms] {                                  \
134         static ::folly::logging::IntervalRateLimiter                   \
135             folly_detail_xlog_limiter(                                 \
136                 1, std::chrono::milliseconds(__folly_detail_xlog_ms)); \
137         return folly_detail_xlog_limiter.check();                      \
138       }(),                                                             \
139       ##__VA_ARGS__)
140 
141 /**
142  * Similar to XLOG(...) except only log a message every @param ms
143  * milliseconds and if the specified condition predicate evaluates to true.
144  *
145  * Note that this is threadsafe.
146  */
147 #define XLOG_EVERY_MS_IF(level, cond, ms, ...)                             \
148   XLOG_IF(                                                                 \
149       level,                                                               \
150       (cond) &&                                                            \
151           [__folly_detail_xlog_ms = ms] {                                  \
152             static ::folly::logging::IntervalRateLimiter                   \
153                 folly_detail_xlog_limiter(                                 \
154                     1, std::chrono::milliseconds(__folly_detail_xlog_ms)); \
155             return folly_detail_xlog_limiter.check();                      \
156           }(),                                                             \
157       ##__VA_ARGS__)
158 
159 /**
160  * Similar to XLOGF(...) except only log a message every @param ms
161  * milliseconds.
162  *
163  * Note that this is threadsafe.
164  */
165 #define XLOGF_EVERY_MS(level, ms, fmt, arg1, ...)                      \
166   XLOGF_IF(                                                            \
167       level,                                                           \
168       [__folly_detail_xlog_ms = ms] {                                  \
169         static ::folly::logging::IntervalRateLimiter                   \
170             folly_detail_xlog_limiter(                                 \
171                 1, std::chrono::milliseconds(__folly_detail_xlog_ms)); \
172         return folly_detail_xlog_limiter.check();                      \
173       }(),                                                             \
174       fmt,                                                             \
175       arg1,                                                            \
176       ##__VA_ARGS__)
177 
178 namespace folly {
179 namespace detail {
180 
181 template <typename Tag>
xlogEveryNImpl(size_t n)182 FOLLY_EXPORT FOLLY_ALWAYS_INLINE bool xlogEveryNImpl(size_t n) {
183   static std::atomic<size_t> count{0};
184   auto const value = count.load(std::memory_order_relaxed);
185   count.store(value + 1, std::memory_order_relaxed);
186   return FOLLY_UNLIKELY((value % n) == 0);
187 }
188 
189 } // namespace detail
190 } // namespace folly
191 
192 /**
193  * Similar to XLOG(...) except only log a message every @param n
194  * invocations, approximately.
195  *
196  * The internal counter is process-global and threadsafe but, to
197  * to avoid the performance degradation of atomic-rmw operations,
198  * increments are non-atomic. Some increments may be missed under
199  * contention, leading to possible over-logging or under-logging
200  * effects.
201  */
202 #define XLOG_EVERY_N(level, n, ...)                                       \
203   XLOG_IF(                                                                \
204       level,                                                              \
205       [&] {                                                               \
206         struct folly_detail_xlog_tag {};                                  \
207         return ::folly::detail::xlogEveryNImpl<folly_detail_xlog_tag>(n); \
208       }(),                                                                \
209       ##__VA_ARGS__)
210 
211 /**
212  * Similar to XLOG(...) except only log a message every @param n
213  * invocations, approximately, and if the specified condition predicate
214  * evaluates to true.
215  *
216  * The internal counter is process-global and threadsafe but, to
217  * to avoid the performance degradation of atomic-rmw operations,
218  * increments are non-atomic. Some increments may be missed under
219  * contention, leading to possible over-logging or under-logging
220  * effects.
221  */
222 #define XLOG_EVERY_N_IF(level, cond, n, ...)                                  \
223   XLOG_IF(                                                                    \
224       level,                                                                  \
225       (cond) &&                                                               \
226           [&] {                                                               \
227             struct folly_detail_xlog_tag {};                                  \
228             return ::folly::detail::xlogEveryNImpl<folly_detail_xlog_tag>(n); \
229           }(),                                                                \
230       ##__VA_ARGS__)
231 
232 namespace folly {
233 namespace detail {
234 
235 template <typename Tag>
xlogEveryNExactImpl(size_t n)236 FOLLY_EXPORT FOLLY_ALWAYS_INLINE bool xlogEveryNExactImpl(size_t n) {
237   static std::atomic<size_t> count{0};
238   auto const value = count.fetch_add(1, std::memory_order_relaxed);
239   return FOLLY_UNLIKELY((value % n) == 0);
240 }
241 
242 } // namespace detail
243 } // namespace folly
244 
245 /**
246  * Similar to XLOG(...) except only log a message every @param n
247  * invocations, exactly.
248  *
249  * The internal counter is process-global and threadsafe and
250  * increments are atomic. The over-logging and under-logging
251  * schenarios of XLOG_EVERY_N(...) are avoided, traded off for
252  * the performance degradation of atomic-rmw operations.
253  */
254 #define XLOG_EVERY_N_EXACT(level, n, ...)                                      \
255   XLOG_IF(                                                                     \
256       level,                                                                   \
257       [&] {                                                                    \
258         struct folly_detail_xlog_tag {};                                       \
259         return ::folly::detail::xlogEveryNExactImpl<folly_detail_xlog_tag>(n); \
260       }(),                                                                     \
261       ##__VA_ARGS__)
262 
263 namespace folly {
264 namespace detail {
265 
266 size_t& xlogEveryNThreadEntry(void const* const key);
267 
268 template <typename Tag>
xlogEveryNThreadImpl(size_t n)269 FOLLY_EXPORT FOLLY_ALWAYS_INLINE bool xlogEveryNThreadImpl(size_t n) {
270   static char key;
271   auto& count = xlogEveryNThreadEntry(&key);
272   return FOLLY_UNLIKELY((count++ % n) == 0);
273 }
274 
275 } // namespace detail
276 } // namespace folly
277 
278 /**
279  * Similar to XLOG(...) except only log a message every @param n
280  * invocations per thread.
281  *
282  * The internal counter is thread-local, avoiding the contention
283  * which the XLOG_EVERY_N variations which use a global counter
284  * may suffer. If a given XLOG_EVERY_N or variation expansion is
285  * encountered concurrently by multiple threads in a hot code
286  * path and the global counter in the expansion is observed to
287  * be contended, then switching to XLOG_EVERY_N_THREAD can help.
288  *
289  * Every thread that invokes this expansion has a counter for
290  * this expansion. The internal counters are all stored in a
291  * single thread-local map to control TLS overhead, at the cost
292  * of a small runtime performance hit.
293  */
294 #define XLOG_EVERY_N_THREAD(level, n, ...)                                   \
295   XLOG_IF(                                                                   \
296       level,                                                                 \
297       [&] {                                                                  \
298         struct folly_detail_xlog_tag {};                                     \
299         return ::folly::detail::xlogEveryNThreadImpl<folly_detail_xlog_tag>( \
300             n);                                                              \
301       }(),                                                                   \
302       ##__VA_ARGS__)
303 
304 /**
305  * Similar to XLOG(...) except only log at most @param count messages
306  * per @param ms millisecond interval.
307  *
308  * The internal counters are process-global and threadsafe.
309  */
310 #define XLOG_N_PER_MS(level, count, ms, ...)                                   \
311   XLOG_IF(                                                                     \
312       level,                                                                   \
313       [] {                                                                     \
314         static ::folly::logging::IntervalRateLimiter                           \
315             folly_detail_xlog_limiter((count), std::chrono::milliseconds(ms)); \
316         return folly_detail_xlog_limiter.check();                              \
317       }(),                                                                     \
318       ##__VA_ARGS__)
319 
320 namespace folly {
321 namespace detail {
322 
323 template <typename Tag>
xlogFirstNExactImpl(std::size_t n)324 FOLLY_EXPORT FOLLY_ALWAYS_INLINE bool xlogFirstNExactImpl(std::size_t n) {
325   static std::atomic<std::size_t> counter{0};
326   auto const value = counter.load(std::memory_order_relaxed);
327   return value < n && counter.fetch_add(1, std::memory_order_relaxed) < n;
328 }
329 
330 } // namespace detail
331 } // namespace folly
332 
333 /**
334  * Similar to XLOG(...) except only log a message the first n times, exactly.
335  *
336  * The internal counter is process-global and threadsafe and exchanges are
337  * atomic.
338  */
339 #define XLOG_FIRST_N(level, n, ...)                                            \
340   XLOG_IF(                                                                     \
341       level,                                                                   \
342       [&] {                                                                    \
343         struct folly_detail_xlog_tag {};                                       \
344         return ::folly::detail::xlogFirstNExactImpl<folly_detail_xlog_tag>(n); \
345       }(),                                                                     \
346       ##__VA_ARGS__)
347 
348 /**
349  * FOLLY_XLOG_STRIP_PREFIXES can be defined to a string containing a
350  * colon-separated list of directory prefixes to strip off from the filename
351  * before using it to compute the log category name.
352  *
353  * If this is defined, use xlogStripFilename() to strip off directory prefixes;
354  * otherwise just use __FILE__ literally.  xlogStripFilename() is a constexpr
355  * expression so that this stripping can be performed fully at compile time.
356  * (There is no guarantee that the compiler will evaluate it at compile time,
357  * though.)
358  */
359 #ifdef FOLLY_XLOG_STRIP_PREFIXES
360 #define XLOG_FILENAME \
361   folly::xlogStripFilename(__FILE__, FOLLY_XLOG_STRIP_PREFIXES)
362 #else
363 #define XLOG_FILENAME __FILE__
364 #endif
365 
366 #define XLOG_IMPL(level, type, ...) \
367   XLOG_ACTUAL_IMPL(                 \
368       level, true, ::folly::isLogLevelFatal(level), type, ##__VA_ARGS__)
369 
370 #define XLOG_IF_IMPL(level, cond, type, ...) \
371   XLOG_ACTUAL_IMPL(level, cond, false, type, ##__VA_ARGS__)
372 
373 /**
374  * Helper macro used to implement XLOG() and XLOGF()
375  *
376  * Beware that the level argument is evaluated twice.
377  *
378  * This macro is somewhat tricky:
379  *
380  * - In order to support streaming argument support (with the << operator),
381  *   the macro must expand to a single ternary ? expression.  This is the only
382  *   way we can avoid evaluating the log arguments if the log check fails,
383  *   and still have the macro behave as expected when used as the body of an if
384  *   or else statement.
385  *
386  * - We need to store some static-scope local state in order to track the
387  *   LogCategory to use.  This is a bit tricky to do and still meet the
388  *   requirements of being a single expression, but fortunately static
389  *   variables inside a lambda work for this purpose.
390  *
391  *   Inside header files, each XLOG() statement defines to static variables:
392  *   - the LogLevel for this category
393  *   - a pointer to the LogCategory
394  *
395  *   If the __INCLUDE_LEVEL__ macro is available (both gcc and clang support
396  *   this), then we we can detect when we are inside a .cpp file versus a
397  *   header file.  If we are inside a .cpp file, we can avoid declaring these
398  *   variables once per XLOG() statement, and instead we only declare one copy
399  *   of these variables for the entire file.
400  *
401  * - We want to make sure this macro is safe to use even from inside static
402  *   initialization code that runs before main.  We also want to make the log
403  *   admittance check as cheap as possible, so that disabled debug logs have
404  *   minimal overhead, and can be left in place even in performance senstive
405  *   code.
406  *
407  *   In order to do this, we rely on zero-initialization of variables with
408  *   static storage duration.  The LogLevel variable will always be
409  *   0-initialized before any code runs.  Therefore the very first time an
410  *   XLOG() statement is hit the initial log level check will always pass
411  *   (since all level values are greater or equal to 0), and we then do a
412  *   second check to see if the log level and category variables need to be
413  *   initialized.  On all subsequent calls, disabled log statements can be
414  *   skipped with just a single check of the LogLevel.
415  */
416 #define XLOG_ACTUAL_IMPL(level, cond, always_fatal, type, ...)             \
417   (!XLOG_IS_ON_IMPL(level) || !(cond))                                     \
418       ? ::folly::logDisabledHelper(::folly::bool_constant<always_fatal>{}) \
419       : ::folly::LogStreamVoidify<::folly::isLogLevelFatal(level)>{} &     \
420           ::folly::LogStreamProcessor(                                     \
421               [] {                                                         \
422                 static ::folly::XlogCategoryInfo<XLOG_IS_IN_HEADER_FILE>   \
423                     folly_detail_xlog_category;                            \
424                 return folly_detail_xlog_category.getInfo(                 \
425                     &xlog_detail::xlogFileScopeInfo);                      \
426               }(),                                                         \
427               (level),                                                     \
428               xlog_detail::getXlogCategoryName(XLOG_FILENAME, 0),          \
429               xlog_detail::isXlogCategoryOverridden(0),                    \
430               XLOG_FILENAME,                                               \
431               __LINE__,                                                    \
432               __func__,                                                    \
433               (type),                                                      \
434               ##__VA_ARGS__)                                               \
435               .stream()
436 
437 /**
438  * Check if an XLOG() statement with the given log level would be enabled.
439  *
440  * The level parameter must be an unqualified LogLevel enum value.
441  */
442 #define XLOG_IS_ON(level) XLOG_IS_ON_IMPL(::folly::LogLevel::level)
443 
444 /**
445  * Helper macro to implement of XLOG_IS_ON()
446  *
447  * This macro is used in the XLOG() implementation, and therefore must be as
448  * cheap as possible.  It stores the category's LogLevel as a local static
449  * variable.  The very first time this macro is evaluated it will look up the
450  * correct LogCategory and initialize the LogLevel.  Subsequent calls then
451  * are only a single conditional log level check.
452  *
453  * The LogCategory object keeps track of this local LogLevel variable and
454  * automatically keeps it up-to-date when the category's effective level is
455  * changed.
456  *
457  * See XlogLevelInfo for the implementation details.
458  */
459 #define XLOG_IS_ON_IMPL(level)                                \
460   ((level >= ::folly::LogLevel::FOLLY_XLOG_MIN_LEVEL) && [] { \
461     static ::folly::XlogLevelInfo<XLOG_IS_IN_HEADER_FILE>     \
462         folly_detail_xlog_level;                              \
463     return folly_detail_xlog_level.check(                     \
464         (level),                                              \
465         xlog_detail::getXlogCategoryName(XLOG_FILENAME, 0),   \
466         xlog_detail::isXlogCategoryOverridden(0),             \
467         &xlog_detail::xlogFileScopeInfo);                     \
468   }())
469 
470 /**
471  * Get the name of the log category that will be used by XLOG() statements
472  * in this file.
473  */
474 #define XLOG_GET_CATEGORY_NAME()                            \
475   (xlog_detail::isXlogCategoryOverridden(0)                 \
476        ? xlog_detail::getXlogCategoryName(XLOG_FILENAME, 0) \
477        : ::folly::getXlogCategoryNameForFile(XLOG_FILENAME))
478 
479 /**
480  * Get a pointer to the LogCategory that will be used by XLOG() statements in
481  * this file.
482  *
483  * This is just a small wrapper around a LoggerDB::getCategory() call.
484  * This must be implemented as a macro since it uses __FILE__, and that must
485  * expand to the correct filename based on where the macro is used.
486  */
487 #define XLOG_GET_CATEGORY() \
488   folly::LoggerDB::get().getCategory(XLOG_GET_CATEGORY_NAME())
489 
490 /**
491  * XLOG_SET_CATEGORY_NAME() can be used to explicitly define the log category
492  * name used by all XLOG() and XLOGF() calls in this translation unit.
493  *
494  * This overrides the default behavior of picking a category name based on the
495  * current filename.
496  *
497  * This should be used at the top-level scope in a .cpp file, before any XLOG()
498  * or XLOGF() macros have been used in the file.
499  *
500  * XLOG_SET_CATEGORY_NAME() cannot be used inside header files.
501  */
502 #ifdef __INCLUDE_LEVEL__
503 #define XLOG_SET_CATEGORY_CHECK \
504   static_assert(                \
505       __INCLUDE_LEVEL__ == 0,   \
506       "XLOG_SET_CATEGORY_NAME() should not be used in header files");
507 #else
508 #define XLOG_SET_CATEGORY_CHECK
509 #endif
510 
511 #define XLOG_SET_CATEGORY_NAME(category)                               \
512   namespace xlog_detail {                                              \
513   namespace {                                                          \
514   XLOG_SET_CATEGORY_CHECK                                              \
515   constexpr inline folly::StringPiece getXlogCategoryName(             \
516       folly::StringPiece, int) {                                       \
517     return category;                                                   \
518   }                                                                    \
519   constexpr inline bool isXlogCategoryOverridden(int) { return true; } \
520   }                                                                    \
521   }
522 
523 /**
524  * Assert that a condition is true.
525  *
526  * This crashes the program with an XLOG(FATAL) message if the condition is
527  * false.  Unlike assert() CHECK statements are always enabled, regardless of
528  * the setting of NDEBUG.
529  */
530 #define XCHECK(cond, ...) \
531   XLOG_IF(FATAL, UNLIKELY(!(cond)), "Check failed: " #cond " ", ##__VA_ARGS__)
532 
533 namespace folly {
534 namespace detail {
535 template <typename Arg1, typename Arg2, typename CmpFn>
XCheckOpImpl(folly::StringPiece checkStr,const Arg1 & arg1,const Arg2 & arg2,CmpFn && cmp_fn)536 std::unique_ptr<std::string> XCheckOpImpl(
537     folly::StringPiece checkStr,
538     const Arg1& arg1,
539     const Arg2& arg2,
540     CmpFn&& cmp_fn) {
541   if (LIKELY(cmp_fn(arg1, arg2))) {
542     return nullptr;
543   }
544   return std::make_unique<std::string>(folly::to<std::string>(
545       "Check failed: ",
546       checkStr,
547       " (",
548       ::folly::logging::objectToString(arg1),
549       " vs. ",
550       folly::logging::objectToString(arg2),
551       ")"));
552 }
553 } // namespace detail
554 } // namespace folly
555 
556 #define XCHECK_OP(op, arg1, arg2, ...)                                        \
557   while (auto _folly_logging_check_result = ::folly::detail::XCheckOpImpl(    \
558              #arg1 " " #op " " #arg2,                                         \
559              (arg1),                                                          \
560              (arg2),                                                          \
561              [](const auto& _folly_check_arg1, const auto& _folly_check_arg2) \
562                  -> bool { return _folly_check_arg1 op _folly_check_arg2; })) \
563   XLOG(FATAL, *_folly_logging_check_result, ##__VA_ARGS__)
564 
565 /**
566  * Assert a comparison relationship between two arguments.
567  *
568  * If the comparison check fails the values of both expressions being compared
569  * will be included in the failure message.  This is the main benefit of using
570  * these specific comparison macros over XCHECK().  XCHECK() will simply log
571  * that the expression evaluated was false, while these macros include the
572  * specific values being compared.
573  */
574 #define XCHECK_EQ(arg1, arg2, ...) XCHECK_OP(==, arg1, arg2, ##__VA_ARGS__)
575 #define XCHECK_NE(arg1, arg2, ...) XCHECK_OP(!=, arg1, arg2, ##__VA_ARGS__)
576 #define XCHECK_LT(arg1, arg2, ...) XCHECK_OP(<, arg1, arg2, ##__VA_ARGS__)
577 #define XCHECK_GT(arg1, arg2, ...) XCHECK_OP(>, arg1, arg2, ##__VA_ARGS__)
578 #define XCHECK_LE(arg1, arg2, ...) XCHECK_OP(<=, arg1, arg2, ##__VA_ARGS__)
579 #define XCHECK_GE(arg1, arg2, ...) XCHECK_OP(>=, arg1, arg2, ##__VA_ARGS__)
580 
581 /**
582  * Assert that a condition is true in debug builds only.
583  *
584  * When NDEBUG is not defined this behaves like XCHECK().
585  * When NDEBUG is defined XDCHECK statements are not evaluated and will never
586  * log.
587  *
588  * You can use `XLOG_IF(DFATAL, condition)` instead if you want the condition to
589  * be evaluated in release builds but log a message without crashing the
590  * program.
591  */
592 #define XDCHECK(cond, ...) \
593   (!::folly::kIsDebug) ? static_cast<void>(0) : XCHECK(cond, ##__VA_ARGS__)
594 
595 /*
596  * It would be nice to rely solely on folly::kIsDebug here rather than NDEBUG.
597  * However doing so would make the code substantially more complicated.  It is
598  * much simpler to simply change the definition of XDCHECK_OP() based on NDEBUG.
599  */
600 #ifdef NDEBUG
601 #define XDCHECK_OP(op, arg1, arg2, ...) \
602   while (false)                         \
603   XCHECK_OP(op, arg1, arg2, ##__VA_ARGS__)
604 #else
605 #define XDCHECK_OP(op, arg1, arg2, ...) XCHECK_OP(op, arg1, arg2, ##__VA_ARGS__)
606 #endif
607 
608 /**
609  * Assert a comparison relationship between two arguments in debug builds.
610  *
611  * When NDEBUG is not set these macros behaves like the corresponding
612  * XCHECK_XX() versions (XCHECK_EQ(), XCHECK_NE(), etc).
613  *
614  * When NDEBUG is defined these statements are not evaluated and will never log.
615  */
616 #define XDCHECK_EQ(arg1, arg2, ...) XDCHECK_OP(==, arg1, arg2, ##__VA_ARGS__)
617 #define XDCHECK_NE(arg1, arg2, ...) XDCHECK_OP(!=, arg1, arg2, ##__VA_ARGS__)
618 #define XDCHECK_LT(arg1, arg2, ...) XDCHECK_OP(<, arg1, arg2, ##__VA_ARGS__)
619 #define XDCHECK_GT(arg1, arg2, ...) XDCHECK_OP(>, arg1, arg2, ##__VA_ARGS__)
620 #define XDCHECK_LE(arg1, arg2, ...) XDCHECK_OP(<=, arg1, arg2, ##__VA_ARGS__)
621 #define XDCHECK_GE(arg1, arg2, ...) XDCHECK_OP(>=, arg1, arg2, ##__VA_ARGS__)
622 
623 /**
624  * XLOG_IS_IN_HEADER_FILE evaluates to false if we can definitively tell if we
625  * are not in a header file.  Otherwise, it evaluates to true.
626  */
627 #ifdef __INCLUDE_LEVEL__
628 #define XLOG_IS_IN_HEADER_FILE bool(__INCLUDE_LEVEL__ > 0)
629 #else
630 // Without __INCLUDE_LEVEL__ we canot tell if we are in a header file or not,
631 // and must pessimstically assume we are always in a header file.
632 #define XLOG_IS_IN_HEADER_FILE true
633 #endif
634 
635 namespace folly {
636 
637 class XlogFileScopeInfo {
638  public:
639 #ifdef __INCLUDE_LEVEL__
640   std::atomic<::folly::LogLevel> level;
641   ::folly::LogCategory* category;
642 #endif
643 };
644 
645 /**
646  * A file-static XlogLevelInfo and XlogCategoryInfo object is declared for each
647  * XLOG() statement.
648  *
649  * We intentionally do not provide constructors for these structures, and rely
650  * on their members to be zero-initialized when the program starts.  This
651  * ensures that everything will work as desired even if XLOG() statements are
652  * used during dynamic object initialization before main().
653  */
654 template <bool IsInHeaderFile>
655 class XlogLevelInfo {
656  public:
check(LogLevel levelToCheck,folly::StringPiece categoryName,bool isOverridden,XlogFileScopeInfo *)657   bool check(
658       LogLevel levelToCheck,
659       folly::StringPiece categoryName,
660       bool isOverridden,
661       XlogFileScopeInfo*) {
662     // Do an initial relaxed check.  If this fails we know the category level
663     // is initialized and the log admittance check failed.
664     // Use LIKELY() to optimize for the case of disabled debug statements:
665     // we disabled debug statements to be cheap.  If the log message is
666     // enabled then this check will still be minimal perf overhead compared to
667     // the overall cost of logging it.
668     if (LIKELY(levelToCheck < level_.load(std::memory_order_relaxed))) {
669       return false;
670     }
671 
672     // If we are still here, then either:
673     // - The log level check actually passed, or
674     // - level_ has not been initialized yet, and we have to initialize it and
675     //   then re-perform the check.
676     //
677     // Do this work in a separate helper method.  It is intentionally defined
678     // in the xlog.cpp file to avoid inlining, to reduce the amount of code
679     // emitted for each XLOG() statement.
680     auto currentLevel = loadLevelFull(categoryName, isOverridden);
681     return levelToCheck >= currentLevel;
682   }
683 
684  private:
685   LogLevel loadLevelFull(folly::StringPiece categoryName, bool isOverridden);
686 
687   // XlogLevelInfo objects are always defined with static storage.
688   // This member will always be zero-initialized on program start.
689   std::atomic<LogLevel> level_;
690 };
691 
692 template <bool IsInHeaderFile>
693 class XlogCategoryInfo {
694  public:
isInitialized()695   bool isInitialized() const {
696     return isInitialized_.load(std::memory_order_acquire);
697   }
698 
699   LogCategory* init(folly::StringPiece categoryName, bool isOverridden);
700 
getCategory(XlogFileScopeInfo *)701   LogCategory* getCategory(XlogFileScopeInfo*) { return category_; }
702 
703   /**
704    * Get a pointer to pass into the LogStreamProcessor constructor,
705    * so that it is able to look up the LogCategory information.
706    */
getInfo(XlogFileScopeInfo *)707   XlogCategoryInfo<IsInHeaderFile>* getInfo(XlogFileScopeInfo*) { return this; }
708 
709  private:
710   // These variables will always be zero-initialized on program start.
711   std::atomic<bool> isInitialized_;
712   LogCategory* category_;
713 };
714 
715 #ifdef __INCLUDE_LEVEL__
716 /**
717  * Specialization of XlogLevelInfo for XLOG() statements in the .cpp file being
718  * compiled.  In this case we only define a single file-static LogLevel object
719  * for the entire file, rather than defining one for each XLOG() statement.
720  */
721 template <>
722 class XlogLevelInfo<false> {
723  public:
check(LogLevel levelToCheck,folly::StringPiece categoryName,bool isOverridden,XlogFileScopeInfo * fileScopeInfo)724   static bool check(
725       LogLevel levelToCheck,
726       folly::StringPiece categoryName,
727       bool isOverridden,
728       XlogFileScopeInfo* fileScopeInfo) {
729     // As above in the non-specialized XlogFileScopeInfo code, do a simple
730     // relaxed check first.
731     if (LIKELY(
732             levelToCheck <
733             fileScopeInfo->level.load(::std::memory_order_relaxed))) {
734       return false;
735     }
736 
737     // If we are still here we the file-scope log level either needs to be
738     // initalized, or the log level check legitimately passed.
739     auto currentLevel =
740         loadLevelFull(categoryName, isOverridden, fileScopeInfo);
741     return levelToCheck >= currentLevel;
742   }
743 
744  private:
745   static LogLevel loadLevelFull(
746       folly::StringPiece categoryName,
747       bool isOverridden,
748       XlogFileScopeInfo* fileScopeInfo);
749 };
750 
751 /**
752  * Specialization of XlogCategoryInfo for XLOG() statements in the .cpp file
753  * being compiled.  In this case we only define a single file-static LogLevel
754  * object for the entire file, rather than defining one for each XLOG()
755  * statement.
756  */
757 template <>
758 class XlogCategoryInfo<false> {
759  public:
760   /**
761    * Get a pointer to pass into the LogStreamProcessor constructor,
762    * so that it is able to look up the LogCategory information.
763    */
getInfo(XlogFileScopeInfo * fileScopeInfo)764   XlogFileScopeInfo* getInfo(XlogFileScopeInfo* fileScopeInfo) {
765     return fileScopeInfo;
766   }
767 };
768 #endif
769 
770 /**
771  * Get the default XLOG() category name for the given filename.
772  *
773  * This function returns the category name that will be used by XLOG() if
774  * XLOG_SET_CATEGORY_NAME() has not been used.
775  */
776 folly::StringPiece getXlogCategoryNameForFile(folly::StringPiece filename);
777 
xlogIsDirSeparator(char c)778 constexpr bool xlogIsDirSeparator(char c) {
779   return c == '/' || (kIsWindows && c == '\\');
780 }
781 
782 namespace detail {
783 constexpr const char* xlogStripFilenameRecursive(
784     const char* filename,
785     const char* prefixes,
786     size_t prefixIdx,
787     size_t filenameIdx,
788     bool match);
xlogStripFilenameMatchFound(const char * filename,const char * prefixes,size_t prefixIdx,size_t filenameIdx)789 constexpr const char* xlogStripFilenameMatchFound(
790     const char* filename,
791     const char* prefixes,
792     size_t prefixIdx,
793     size_t filenameIdx) {
794   return (filename[filenameIdx] == '\0')
795       ? xlogStripFilenameRecursive(filename, prefixes, prefixIdx + 1, 0, true)
796       : (xlogIsDirSeparator(filename[filenameIdx])
797              ? xlogStripFilenameMatchFound(
798                    filename, prefixes, prefixIdx, filenameIdx + 1)
799              : (filename + filenameIdx));
800 }
xlogStripFilenameRecursive(const char * filename,const char * prefixes,size_t prefixIdx,size_t filenameIdx,bool match)801 constexpr const char* xlogStripFilenameRecursive(
802     const char* filename,
803     const char* prefixes,
804     size_t prefixIdx,
805     size_t filenameIdx,
806     bool match) {
807   // This would be much easier to understand if written as a while loop.
808   // However, in order to maintain compatibility with pre-C++14 compilers we
809   // have implemented it recursively to adhere to C++11 restrictions for
810   // constexpr functions.
811   return ((prefixes[prefixIdx] == ':' && filename[filenameIdx] != ':') ||
812           prefixes[prefixIdx] == '\0')
813       ? ((match && filenameIdx > 0 &&
814           (xlogIsDirSeparator(prefixes[filenameIdx - 1]) ||
815            xlogIsDirSeparator(filename[filenameIdx])))
816              ? (xlogStripFilenameMatchFound(
817                    filename, prefixes, prefixIdx, filenameIdx))
818              : ((prefixes[prefixIdx] == '\0')
819                     ? filename
820                     : xlogStripFilenameRecursive(
821                           filename, prefixes, prefixIdx + 1, 0, true)))
822       : ((match &&
823           ((prefixes[prefixIdx] == filename[filenameIdx]) ||
824            (xlogIsDirSeparator(prefixes[prefixIdx]) &&
825             xlogIsDirSeparator(filename[filenameIdx]))))
826              ? xlogStripFilenameRecursive(
827                    filename, prefixes, prefixIdx + 1, filenameIdx + 1, true)
828              : xlogStripFilenameRecursive(
829                    filename, prefixes, prefixIdx + 1, 0, false));
830 }
831 } // namespace detail
832 
833 /**
834  * Strip directory prefixes from a filename before using it in XLOG macros.
835  *
836  * This is primarily used to strip off the initial project directory path for
837  * projects that invoke the compiler with absolute path names.
838  *
839  * The filename argument is the filename to process.  This is normally the
840  * contents of the __FILE__ macro from the invoking file.
841  *
842  * prefixes is a colon-separated list of directory prefixes to strip off if
843  * present at the beginning of the filename.  The prefix list is searched in
844  * order, and only the first match found will be stripped.
845  *
846  * e.g., xlogStripFilename("/my/project/src/foo.cpp", "/tmp:/my/project")
847  * would return "src/foo.cpp"
848  */
xlogStripFilename(const char * filename,const char * prefixes)849 constexpr const char* xlogStripFilename(
850     const char* filename, const char* prefixes) {
851   return detail::xlogStripFilenameRecursive(filename, prefixes, 0, 0, true);
852 }
853 } // namespace folly
854 
855 /*
856  * We intentionally use an unnamed namespace inside a header file here.
857  *
858  * We want each .cpp file that uses xlog.h to get its own separate
859  * implementation of the following functions and variables.
860  */
861 namespace xlog_detail {
862 namespace {
863 /**
864  * The default getXlogCategoryName() function.
865  *
866  * By default this simply returns the filename argument passed in.
867  * The default isXlogCategoryOverridden() function returns false, indicating
868  * that the return value from getXlogCategoryName() needs to be converted
869  * using getXlogCategoryNameForFile().
870  *
871  * These are two separate steps because getXlogCategoryName() itself needs to
872  * remain constexpr--it is always evaluated in XLOG() statements, but we only
873  * want to call getXlogCategoryNameForFile() the very first time through, when
874  * we have to initialize the LogCategory object.
875  *
876  * This is a template function purely so that XLOG_SET_CATEGORY_NAME() can
877  * define a more specific version of this function that will take precedence
878  * over this one.
879  */
880 template <typename T>
getXlogCategoryName(folly::StringPiece filename,T)881 constexpr inline folly::StringPiece getXlogCategoryName(
882     folly::StringPiece filename, T) {
883   return filename;
884 }
885 
886 /**
887  * The default isXlogCategoryOverridden() function.
888  *
889  * This returns false indicating that the category name has not been
890  * overridden, so getXlogCategoryName() returns a raw filename that needs
891  * to be translated with getXlogCategoryNameForFile().
892  *
893  * This is a template function purely so that XLOG_SET_CATEGORY_NAME() can
894  * define a more specific version of this function that will take precedence
895  * over this one.
896  */
897 template <typename T>
isXlogCategoryOverridden(T)898 constexpr inline bool isXlogCategoryOverridden(T) {
899   return false;
900 }
901 
902 /**
903  * File-scope LogLevel and LogCategory data for XLOG() statements,
904  * if __INCLUDE_LEVEL__ is supported.
905  *
906  * This allows us to only have one LogLevel and LogCategory pointer for the
907  * entire .cpp file, rather than needing a separate copy for each XLOG()
908  * statement.
909  */
910 ::folly::XlogFileScopeInfo xlogFileScopeInfo;
911 } // namespace
912 } // namespace xlog_detail
913