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