xlog.h 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. /*
  2. * Copyright 2017-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. #include <folly/Likely.h>
  18. #include <folly/Portability.h>
  19. #include <folly/Range.h>
  20. #include <folly/logging/LogStream.h>
  21. #include <folly/logging/Logger.h>
  22. #include <folly/logging/LoggerDB.h>
  23. #include <folly/logging/RateLimiter.h>
  24. #include <cstdlib>
  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. * Log a message to this file's default log category.
  40. *
  41. * By default the log category name is automatically picked based on the
  42. * current filename. In src/foo/bar.cpp the log category name "src.foo.bar"
  43. * will be used. In "lib/stuff/foo.h" the log category name will be
  44. * "lib.stuff.foo"
  45. *
  46. * Note that the filename is based on the __FILE__ macro defined by the
  47. * compiler. This is typically dependent on the filename argument that you
  48. * give to the compiler. For example, if you compile src/foo/bar.cpp by
  49. * invoking the compiler inside src/foo and only give it "bar.cpp" as an
  50. * argument, the category name will simply be "bar". In general XLOG() works
  51. * best if you always invoke the compiler from the root directory of your
  52. * project repository.
  53. */
  54. #define XLOG(level, ...) \
  55. XLOG_IMPL( \
  56. ::folly::LogLevel::level, \
  57. ::folly::LogStreamProcessor::APPEND, \
  58. ##__VA_ARGS__)
  59. /**
  60. * Log a message if and only if the specified condition predicate evaluates
  61. * to true. Note that the condition is *only* evaluated if the log-level check
  62. * passes.
  63. */
  64. #define XLOG_IF(level, cond, ...) \
  65. XLOG_IF_IMPL( \
  66. ::folly::LogLevel::level, \
  67. cond, \
  68. ::folly::LogStreamProcessor::APPEND, \
  69. ##__VA_ARGS__)
  70. /**
  71. * Log a message to this file's default log category, using a format string.
  72. */
  73. #define XLOGF(level, fmt, arg1, ...) \
  74. XLOG_IMPL( \
  75. ::folly::LogLevel::level, \
  76. ::folly::LogStreamProcessor::FORMAT, \
  77. fmt, \
  78. arg1, \
  79. ##__VA_ARGS__)
  80. /**
  81. * Log a message using a format string if and only if the specified condition
  82. * predicate evaluates to true. Note that the condition is *only* evaluated
  83. * if the log-level check passes.
  84. */
  85. #define XLOGF_IF(level, cond, fmt, arg1, ...) \
  86. XLOG_IF_IMPL( \
  87. ::folly::LogLevel::level, \
  88. cond, \
  89. ::folly::LogStreamProcessor::FORMAT, \
  90. fmt, \
  91. arg1, \
  92. ##__VA_ARGS__)
  93. /**
  94. * Similar to XLOG(...) except only log a message every @param ms
  95. * milliseconds.
  96. *
  97. * Note that this is threadsafe.
  98. */
  99. #define XLOG_EVERY_MS(level, ms, ...) \
  100. XLOG_IF( \
  101. level, \
  102. [] { \
  103. static ::folly::logging::IntervalRateLimiter \
  104. folly_detail_xlog_limiter(1, std::chrono::milliseconds(ms)); \
  105. return folly_detail_xlog_limiter.check(); \
  106. }(), \
  107. ##__VA_ARGS__)
  108. /**
  109. * Similar to XLOG(...) except only log a message every @param n
  110. * invocations.
  111. *
  112. * The internal counter is process-global and threadsafe.
  113. */
  114. #define XLOG_EVERY_N(level, n, ...) \
  115. XLOG_IF( \
  116. level, \
  117. [] { \
  118. static std::atomic<size_t> folly_detail_xlog_count{0}; \
  119. return FOLLY_UNLIKELY( \
  120. (folly_detail_xlog_count.fetch_add(1, std::memory_order_relaxed) % \
  121. (n)) == 0); \
  122. }(), \
  123. ##__VA_ARGS__)
  124. /**
  125. * Similar to XLOG(...) except only log at most @param count messages
  126. * per @param ms millisecond interval.
  127. *
  128. * The internal counters are process-global and threadsafe.
  129. */
  130. #define XLOG_N_PER_MS(level, count, ms, ...) \
  131. XLOG_IF( \
  132. level, \
  133. [] { \
  134. static ::folly::logging::IntervalRateLimiter \
  135. folly_detail_xlog_limiter((count), std::chrono::milliseconds(ms)); \
  136. return folly_detail_xlog_limiter.check(); \
  137. }(), \
  138. ##__VA_ARGS__)
  139. /**
  140. * FOLLY_XLOG_STRIP_PREFIXES can be defined to a string containing a
  141. * colon-separated list of directory prefixes to strip off from the filename
  142. * before using it to compute the log category name.
  143. *
  144. * If this is defined, use xlogStripFilename() to strip off directory prefixes;
  145. * otherwise just use __FILE__ literally. xlogStripFilename() is a constexpr
  146. * expression so that this stripping can be performed fully at compile time.
  147. * (There is no guarantee that the compiler will evaluate it at compile time,
  148. * though.)
  149. */
  150. #ifdef FOLLY_XLOG_STRIP_PREFIXES
  151. #define XLOG_FILENAME \
  152. folly::xlogStripFilename(__FILE__, FOLLY_XLOG_STRIP_PREFIXES)
  153. #else
  154. #define XLOG_FILENAME __FILE__
  155. #endif
  156. #define XLOG_IMPL(level, type, ...) \
  157. XLOG_ACTUAL_IMPL( \
  158. level, true, ::folly::isLogLevelFatal(level), type, ##__VA_ARGS__)
  159. #define XLOG_IF_IMPL(level, cond, type, ...) \
  160. XLOG_ACTUAL_IMPL(level, cond, false, type, ##__VA_ARGS__)
  161. /**
  162. * Helper macro used to implement XLOG() and XLOGF()
  163. *
  164. * Beware that the level argument is evaluated twice.
  165. *
  166. * This macro is somewhat tricky:
  167. *
  168. * - In order to support streaming argument support (with the << operator),
  169. * the macro must expand to a single ternary ? expression. This is the only
  170. * way we can avoid evaluating the log arguments if the log check fails,
  171. * and still have the macro behave as expected when used as the body of an if
  172. * or else statement.
  173. *
  174. * - We need to store some static-scope local state in order to track the
  175. * LogCategory to use. This is a bit tricky to do and still meet the
  176. * requirements of being a single expression, but fortunately static
  177. * variables inside a lambda work for this purpose.
  178. *
  179. * Inside header files, each XLOG() statement defines to static variables:
  180. * - the LogLevel for this category
  181. * - a pointer to the LogCategory
  182. *
  183. * If the __INCLUDE_LEVEL__ macro is available (both gcc and clang support
  184. * this), then we we can detect when we are inside a .cpp file versus a
  185. * header file. If we are inside a .cpp file, we can avoid declaring these
  186. * variables once per XLOG() statement, and instead we only declare one copy
  187. * of these variables for the entire file.
  188. *
  189. * - We want to make sure this macro is safe to use even from inside static
  190. * initialization code that runs before main. We also want to make the log
  191. * admittance check as cheap as possible, so that disabled debug logs have
  192. * minimal overhead, and can be left in place even in performance senstive
  193. * code.
  194. *
  195. * In order to do this, we rely on zero-initialization of variables with
  196. * static storage duration. The LogLevel variable will always be
  197. * 0-initialized before any code runs. Therefore the very first time an
  198. * XLOG() statement is hit the initial log level check will always pass
  199. * (since all level values are greater or equal to 0), and we then do a
  200. * second check to see if the log level and category variables need to be
  201. * initialized. On all subsequent calls, disabled log statements can be
  202. * skipped with just a single check of the LogLevel.
  203. */
  204. #define XLOG_ACTUAL_IMPL(level, cond, always_fatal, type, ...) \
  205. (!XLOG_IS_ON_IMPL(level) || !(cond)) \
  206. ? ::folly::logDisabledHelper(::folly::bool_constant<always_fatal>{}) \
  207. : ::folly::LogStreamVoidify<::folly::isLogLevelFatal(level)>{} & \
  208. ::folly::LogStreamProcessor( \
  209. [] { \
  210. static ::folly::XlogCategoryInfo<XLOG_IS_IN_HEADER_FILE> \
  211. folly_detail_xlog_category; \
  212. return folly_detail_xlog_category.getInfo( \
  213. &xlog_detail::xlogFileScopeInfo); \
  214. }(), \
  215. (level), \
  216. xlog_detail::getXlogCategoryName(XLOG_FILENAME, 0), \
  217. xlog_detail::isXlogCategoryOverridden(0), \
  218. XLOG_FILENAME, \
  219. __LINE__, \
  220. __func__, \
  221. (type), \
  222. ##__VA_ARGS__) \
  223. .stream()
  224. /**
  225. * Check if an XLOG() statement with the given log level would be enabled.
  226. *
  227. * The level parameter must be an unqualified LogLevel enum value.
  228. */
  229. #define XLOG_IS_ON(level) XLOG_IS_ON_IMPL(::folly::LogLevel::level)
  230. /**
  231. * Helper macro to implement of XLOG_IS_ON()
  232. *
  233. * This macro is used in the XLOG() implementation, and therefore must be as
  234. * cheap as possible. It stores the category's LogLevel as a local static
  235. * variable. The very first time this macro is evaluated it will look up the
  236. * correct LogCategory and initialize the LogLevel. Subsequent calls then
  237. * are only a single conditional log level check.
  238. *
  239. * The LogCategory object keeps track of this local LogLevel variable and
  240. * automatically keeps it up-to-date when the category's effective level is
  241. * changed.
  242. *
  243. * See XlogLevelInfo for the implementation details.
  244. */
  245. #define XLOG_IS_ON_IMPL(level) \
  246. ([] { \
  247. static ::folly::XlogLevelInfo<XLOG_IS_IN_HEADER_FILE> \
  248. folly_detail_xlog_level; \
  249. return folly_detail_xlog_level.check( \
  250. (level), \
  251. xlog_detail::getXlogCategoryName(XLOG_FILENAME, 0), \
  252. xlog_detail::isXlogCategoryOverridden(0), \
  253. &xlog_detail::xlogFileScopeInfo); \
  254. }())
  255. /**
  256. * Get the name of the log category that will be used by XLOG() statements
  257. * in this file.
  258. */
  259. #define XLOG_GET_CATEGORY_NAME() \
  260. (xlog_detail::isXlogCategoryOverridden(0) \
  261. ? xlog_detail::getXlogCategoryName(XLOG_FILENAME, 0) \
  262. : ::folly::getXlogCategoryNameForFile(XLOG_FILENAME))
  263. /**
  264. * Get a pointer to the LogCategory that will be used by XLOG() statements in
  265. * this file.
  266. *
  267. * This is just a small wrapper around a LoggerDB::getCategory() call.
  268. * This must be implemented as a macro since it uses __FILE__, and that must
  269. * expand to the correct filename based on where the macro is used.
  270. */
  271. #define XLOG_GET_CATEGORY() \
  272. folly::LoggerDB::get().getCategory(XLOG_GET_CATEGORY_NAME())
  273. /**
  274. * XLOG_SET_CATEGORY_NAME() can be used to explicitly define the log category
  275. * name used by all XLOG() and XLOGF() calls in this translation unit.
  276. *
  277. * This overrides the default behavior of picking a category name based on the
  278. * current filename.
  279. *
  280. * This should be used at the top-level scope in a .cpp file, before any XLOG()
  281. * or XLOGF() macros have been used in the file.
  282. *
  283. * XLOG_SET_CATEGORY_NAME() cannot be used inside header files.
  284. */
  285. #ifdef __INCLUDE_LEVEL__
  286. #define XLOG_SET_CATEGORY_CHECK \
  287. static_assert( \
  288. __INCLUDE_LEVEL__ == 0, \
  289. "XLOG_SET_CATEGORY_NAME() should not be used in header files");
  290. #else
  291. #define XLOG_SET_CATEGORY_CHECK
  292. #endif
  293. #define XLOG_SET_CATEGORY_NAME(category) \
  294. namespace { \
  295. namespace xlog_detail { \
  296. XLOG_SET_CATEGORY_CHECK \
  297. constexpr inline folly::StringPiece getXlogCategoryName( \
  298. folly::StringPiece, \
  299. int) { \
  300. return category; \
  301. } \
  302. constexpr inline bool isXlogCategoryOverridden(int) { \
  303. return true; \
  304. } \
  305. } \
  306. }
  307. /**
  308. * Assert that a condition is true.
  309. *
  310. * This crashes the program with an XLOG(FATAL) message if the condition is
  311. * false. Unlike assert() CHECK statements are always enabled, regardless of
  312. * the setting of NDEBUG.
  313. */
  314. #define XCHECK(cond, ...) \
  315. XLOG_IF(FATAL, UNLIKELY(!(cond)), "Check failed: " #cond " ", ##__VA_ARGS__)
  316. /**
  317. * Assert that a condition is true in non-debug builds.
  318. *
  319. * When NDEBUG is set this behaves like XDCHECK()
  320. * When NDEBUG is not defined XDCHECK statements are not evaluated and will
  321. * never log.
  322. *
  323. * You can use `XLOG_IF(DFATAL, condition)` instead if you want the condition to
  324. * be evaluated in release builds but log a message without crashing the
  325. * program.
  326. */
  327. #define XDCHECK(cond, ...) \
  328. (!::folly::kIsDebug) ? static_cast<void>(0) : XCHECK(cond, ##__VA_ARGS__)
  329. /**
  330. * XLOG_IS_IN_HEADER_FILE evaluates to false if we can definitively tell if we
  331. * are not in a header file. Otherwise, it evaluates to true.
  332. */
  333. #ifdef __INCLUDE_LEVEL__
  334. #define XLOG_IS_IN_HEADER_FILE bool(__INCLUDE_LEVEL__ > 0)
  335. #else
  336. // Without __INCLUDE_LEVEL__ we canot tell if we are in a header file or not,
  337. // and must pessimstically assume we are always in a header file.
  338. #define XLOG_IS_IN_HEADER_FILE true
  339. #endif
  340. namespace folly {
  341. class XlogFileScopeInfo {
  342. public:
  343. #ifdef __INCLUDE_LEVEL__
  344. std::atomic<::folly::LogLevel> level;
  345. ::folly::LogCategory* category;
  346. #endif
  347. };
  348. /**
  349. * A file-static XlogLevelInfo and XlogCategoryInfo object is declared for each
  350. * XLOG() statement.
  351. *
  352. * We intentionally do not provide constructors for these structures, and rely
  353. * on their members to be zero-initialized when the program starts. This
  354. * ensures that everything will work as desired even if XLOG() statements are
  355. * used during dynamic object initialization before main().
  356. */
  357. template <bool IsInHeaderFile>
  358. class XlogLevelInfo {
  359. public:
  360. bool check(
  361. LogLevel levelToCheck,
  362. folly::StringPiece categoryName,
  363. bool isOverridden,
  364. XlogFileScopeInfo*) {
  365. // Do an initial relaxed check. If this fails we know the category level
  366. // is initialized and the log admittance check failed.
  367. // Use LIKELY() to optimize for the case of disabled debug statements:
  368. // we disabled debug statements to be cheap. If the log message is
  369. // enabled then this check will still be minimal perf overhead compared to
  370. // the overall cost of logging it.
  371. if (LIKELY(levelToCheck < level_.load(std::memory_order_relaxed))) {
  372. return false;
  373. }
  374. // If we are still here, then either:
  375. // - The log level check actually passed, or
  376. // - level_ has not been initialized yet, and we have to initialize it and
  377. // then re-perform the check.
  378. //
  379. // Do this work in a separate helper method. It is intentionally defined
  380. // in the xlog.cpp file to avoid inlining, to reduce the amount of code
  381. // emitted for each XLOG() statement.
  382. auto currentLevel = loadLevelFull(categoryName, isOverridden);
  383. return levelToCheck >= currentLevel;
  384. }
  385. private:
  386. LogLevel loadLevelFull(folly::StringPiece categoryName, bool isOverridden);
  387. // XlogLevelInfo objects are always defined with static storage.
  388. // This member will always be zero-initialized on program start.
  389. std::atomic<LogLevel> level_;
  390. };
  391. template <bool IsInHeaderFile>
  392. class XlogCategoryInfo {
  393. public:
  394. bool isInitialized() const {
  395. return isInitialized_.load(std::memory_order_acquire);
  396. }
  397. LogCategory* init(folly::StringPiece categoryName, bool isOverridden);
  398. LogCategory* getCategory(XlogFileScopeInfo*) {
  399. return category_;
  400. }
  401. /**
  402. * Get a pointer to pass into the LogStreamProcessor constructor,
  403. * so that it is able to look up the LogCategory information.
  404. */
  405. XlogCategoryInfo<IsInHeaderFile>* getInfo(XlogFileScopeInfo*) {
  406. return this;
  407. }
  408. private:
  409. // These variables will always be zero-initialized on program start.
  410. std::atomic<bool> isInitialized_;
  411. LogCategory* category_;
  412. };
  413. #ifdef __INCLUDE_LEVEL__
  414. /**
  415. * Specialization of XlogLevelInfo for XLOG() statements in the .cpp file being
  416. * compiled. In this case we only define a single file-static LogLevel object
  417. * for the entire file, rather than defining one for each XLOG() statement.
  418. */
  419. template <>
  420. class XlogLevelInfo<false> {
  421. public:
  422. static bool check(
  423. LogLevel levelToCheck,
  424. folly::StringPiece categoryName,
  425. bool isOverridden,
  426. XlogFileScopeInfo* fileScopeInfo) {
  427. // As above in the non-specialized XlogFileScopeInfo code, do a simple
  428. // relaxed check first.
  429. if (LIKELY(
  430. levelToCheck <
  431. fileScopeInfo->level.load(::std::memory_order_relaxed))) {
  432. return false;
  433. }
  434. // If we are still here we the file-scope log level either needs to be
  435. // initalized, or the log level check legitimately passed.
  436. auto currentLevel =
  437. loadLevelFull(categoryName, isOverridden, fileScopeInfo);
  438. return levelToCheck >= currentLevel;
  439. }
  440. private:
  441. static LogLevel loadLevelFull(
  442. folly::StringPiece categoryName,
  443. bool isOverridden,
  444. XlogFileScopeInfo* fileScopeInfo);
  445. };
  446. /**
  447. * Specialization of XlogCategoryInfo for XLOG() statements in the .cpp file
  448. * being compiled. In this case we only define a single file-static LogLevel
  449. * object for the entire file, rather than defining one for each XLOG()
  450. * statement.
  451. */
  452. template <>
  453. class XlogCategoryInfo<false> {
  454. public:
  455. /**
  456. * Get a pointer to pass into the LogStreamProcessor constructor,
  457. * so that it is able to look up the LogCategory information.
  458. */
  459. XlogFileScopeInfo* getInfo(XlogFileScopeInfo* fileScopeInfo) {
  460. return fileScopeInfo;
  461. }
  462. };
  463. #endif
  464. /**
  465. * Get the default XLOG() category name for the given filename.
  466. *
  467. * This function returns the category name that will be used by XLOG() if
  468. * XLOG_SET_CATEGORY_NAME() has not been used.
  469. */
  470. folly::StringPiece getXlogCategoryNameForFile(folly::StringPiece filename);
  471. constexpr bool xlogIsDirSeparator(char c) {
  472. return c == '/' || (kIsWindows && c == '\\');
  473. }
  474. namespace detail {
  475. constexpr const char* xlogStripFilenameRecursive(
  476. const char* filename,
  477. const char* prefixes,
  478. size_t prefixIdx,
  479. size_t filenameIdx,
  480. bool match);
  481. constexpr const char* xlogStripFilenameMatchFound(
  482. const char* filename,
  483. const char* prefixes,
  484. size_t prefixIdx,
  485. size_t filenameIdx) {
  486. return (filename[filenameIdx] == '\0')
  487. ? xlogStripFilenameRecursive(filename, prefixes, prefixIdx + 1, 0, true)
  488. : (xlogIsDirSeparator(filename[filenameIdx])
  489. ? xlogStripFilenameMatchFound(
  490. filename, prefixes, prefixIdx, filenameIdx + 1)
  491. : (filename + filenameIdx));
  492. }
  493. constexpr const char* xlogStripFilenameRecursive(
  494. const char* filename,
  495. const char* prefixes,
  496. size_t prefixIdx,
  497. size_t filenameIdx,
  498. bool match) {
  499. // This would be much easier to understand if written as a while loop.
  500. // However, in order to maintain compatibility with pre-C++14 compilers we
  501. // have implemented it recursively to adhere to C++11 restrictions for
  502. // constexpr functions.
  503. return (prefixes[prefixIdx] == ':' || prefixes[prefixIdx] == '\0')
  504. ? ((match && filenameIdx > 0 &&
  505. (xlogIsDirSeparator(prefixes[filenameIdx - 1]) ||
  506. xlogIsDirSeparator(filename[filenameIdx])))
  507. ? (xlogStripFilenameMatchFound(
  508. filename, prefixes, prefixIdx, filenameIdx))
  509. : ((prefixes[prefixIdx] == '\0')
  510. ? filename
  511. : xlogStripFilenameRecursive(
  512. filename, prefixes, prefixIdx + 1, 0, true)))
  513. : ((match && (prefixes[prefixIdx] == filename[filenameIdx]))
  514. ? xlogStripFilenameRecursive(
  515. filename, prefixes, prefixIdx + 1, filenameIdx + 1, true)
  516. : xlogStripFilenameRecursive(
  517. filename, prefixes, prefixIdx + 1, 0, false));
  518. }
  519. } // namespace detail
  520. /**
  521. * Strip directory prefixes from a filename before using it in XLOG macros.
  522. *
  523. * This is primarily used to strip off the initial project directory path for
  524. * projects that invoke the compiler with absolute path names.
  525. *
  526. * The filename argument is the filename to process. This is normally the
  527. * contents of the __FILE__ macro from the invoking file.
  528. *
  529. * prefixes is a colon-separated list of directory prefixes to strip off if
  530. * present at the beginning of the filename. The prefix list is searched in
  531. * order, and only the first match found will be stripped.
  532. *
  533. * e.g., xlogStripFilename("/my/project/src/foo.cpp", "/tmp:/my/project")
  534. * would return "src/foo.cpp"
  535. */
  536. constexpr const char* xlogStripFilename(
  537. const char* filename,
  538. const char* prefixes) {
  539. return detail::xlogStripFilenameRecursive(filename, prefixes, 0, 0, true);
  540. }
  541. } // namespace folly
  542. /*
  543. * We intentionally use an unnamed namespace inside a header file here.
  544. *
  545. * We want each .cpp file that uses xlog.h to get its own separate
  546. * implementation of the following functions and variables.
  547. */
  548. namespace {
  549. namespace xlog_detail {
  550. /**
  551. * The default getXlogCategoryName() function.
  552. *
  553. * By default this simply returns the filename argument passed in.
  554. * The default isXlogCategoryOverridden() function returns false, indicating
  555. * that the return value from getXlogCategoryName() needs to be converted
  556. * using getXlogCategoryNameForFile().
  557. *
  558. * These are two separate steps because getXlogCategoryName() itself needs to
  559. * remain constexpr--it is always evaluated in XLOG() statements, but we only
  560. * want to call getXlogCategoryNameForFile() the very first time through, when
  561. * we have to initialize the LogCategory object.
  562. *
  563. * This is a template function purely so that XLOG_SET_CATEGORY_NAME() can
  564. * define a more specific version of this function that will take precedence
  565. * over this one.
  566. */
  567. template <typename T>
  568. constexpr inline folly::StringPiece getXlogCategoryName(
  569. folly::StringPiece filename,
  570. T) {
  571. return filename;
  572. }
  573. /**
  574. * The default isXlogCategoryOverridden() function.
  575. *
  576. * This returns false indicating that the category name has not been
  577. * overridden, so getXlogCategoryName() returns a raw filename that needs
  578. * to be translated with getXlogCategoryNameForFile().
  579. *
  580. * This is a template function purely so that XLOG_SET_CATEGORY_NAME() can
  581. * define a more specific version of this function that will take precedence
  582. * over this one.
  583. */
  584. template <typename T>
  585. constexpr inline bool isXlogCategoryOverridden(T) {
  586. return false;
  587. }
  588. /**
  589. * File-scope LogLevel and LogCategory data for XLOG() statements,
  590. * if __INCLUDE_LEVEL__ is supported.
  591. *
  592. * This allows us to only have one LogLevel and LogCategory pointer for the
  593. * entire .cpp file, rather than needing a separate copy for each XLOG()
  594. * statement.
  595. */
  596. ::folly::XlogFileScopeInfo xlogFileScopeInfo;
  597. } // namespace xlog_detail
  598. } // namespace