log.h
1 // Copyright (c) The Bitcoin Core developers 2 // Distributed under the MIT software license, see the accompanying 3 // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 5 #ifndef BITCOIN_UTIL_LOG_H 6 #define BITCOIN_UTIL_LOG_H 7 8 // This header works in tandem with `logging/categories.h` 9 // to expose the complete logging interface. 10 #include <logging/categories.h> // IWYU pragma: export 11 #include <tinyformat.h> 12 #include <util/check.h> 13 #include <util/threadnames.h> 14 #include <util/time.h> 15 16 #include <cstdint> 17 #include <source_location> 18 #include <string> 19 #include <string_view> 20 21 /// Like std::source_location, but allowing to override the function name. 22 class SourceLocation 23 { 24 public: 25 /// The func argument must be constructed from the C++11 __func__ macro. 26 /// Ref: https://en.cppreference.com/w/cpp/language/function.html#func 27 /// Non-static string literals are not supported. 28 explicit SourceLocation( 29 const char* func, 30 std::source_location loc = std::source_location::current()) 31 : m_func{func}, m_loc{loc} {} 32 33 std::string_view file_name() const { return m_loc.file_name(); } 34 std::uint_least32_t line() const { return m_loc.line(); } 35 std::string_view function_name_short() const { return m_func; } 36 37 private: 38 std::string_view m_func; 39 std::source_location m_loc; 40 }; 41 42 namespace util::log { 43 /** Opaque to util::log; interpreted by consumers (e.g., BCLog::LogFlags). */ 44 using Category = uint64_t; 45 46 enum class Level { 47 Trace = 0, // High-volume or detailed logging for development/debugging 48 Debug, // Reasonably noisy logging, but still usable in production 49 Info, // Default 50 Warning, 51 Error, 52 }; 53 54 struct Entry { 55 Category category; 56 Level level; 57 bool should_ratelimit{false}; //!< Hint for consumers if this entry should be ratelimited 58 SystemClock::time_point timestamp{SystemClock::now()}; 59 std::chrono::seconds mocktime{GetMockTime()}; 60 std::string thread_name{util::ThreadGetInternalName()}; 61 SourceLocation source_loc; 62 std::string message; 63 }; 64 65 /** Return whether messages with specified category and level should be logged. Applications using 66 * the logging library need to provide this. */ 67 bool ShouldLog(Category category, Level level); 68 69 /** Send message to be logged. Applications using the logging library need to provide this. */ 70 void Log(Entry entry); 71 } // namespace util::log 72 73 namespace BCLog { 74 //! Alias for compatibility. Prefer util::log::Level over BCLog::Level in new code. 75 using Level = util::log::Level; 76 } // namespace BCLog 77 78 template <typename... Args> 79 inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags flag, BCLog::Level level, bool should_ratelimit, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args) 80 { 81 std::string log_msg; 82 try { 83 log_msg = tfm::format(fmt, args...); 84 } catch (tinyformat::format_error& fmterr) { 85 log_msg = "Error \"" + std::string{fmterr.what()} + "\" while formatting log message: " + fmt.fmt; 86 } 87 util::log::Log(util::log::Entry{ 88 .category = flag, 89 .level = level, 90 .should_ratelimit = should_ratelimit, 91 .source_loc = std::move(source_loc), 92 .message = std::move(log_msg)}); 93 } 94 95 // Allow __func__ to be used in any context without warnings: 96 // NOLINTNEXTLINE(bugprone-lambda-function-name) 97 #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(SourceLocation{__func__}, category, level, should_ratelimit, __VA_ARGS__) 98 99 // Log unconditionally. Uses basic rate limiting to mitigate disk filling attacks. 100 // Be conservative when using functions that unconditionally log to debug.log! 101 // It should not be the case that an inbound peer can fill up a user's storage 102 // with debug.log entries. 103 #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) 104 #define LogWarning(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Warning, /*should_ratelimit=*/true, __VA_ARGS__) 105 #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) 106 107 // Use a macro instead of a function for conditional logging to prevent 108 // evaluating arguments when logging for the category is not enabled. 109 110 // Log by prefixing the output with the passed category name and severity level. This logs conditionally if 111 // the category is allowed. No rate limiting is applied, because users specifying -debug are assumed to be 112 // developers or power users who are aware that -debug may cause excessive disk usage due to logging. 113 #define detail_LogIfCategoryAndLevelEnabled(category, level, ...) \ 114 do { \ 115 if (util::log::ShouldLog((category), (level))) { \ 116 bool rate_limit{level >= BCLog::Level::Info}; \ 117 Assume(!rate_limit); /*Only called with the levels below*/ \ 118 LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ 119 } \ 120 } while (0) 121 122 // Log conditionally, prefixing the output with the passed category name. 123 #define LogDebug(category, ...) detail_LogIfCategoryAndLevelEnabled(category, BCLog::Level::Debug, __VA_ARGS__) 124 #define LogTrace(category, ...) detail_LogIfCategoryAndLevelEnabled(category, BCLog::Level::Trace, __VA_ARGS__) 125 126 #endif // BITCOIN_UTIL_LOG_H