logging.h
1 // Copyright (c) 2009-2010 Satoshi Nakamoto 2 // Copyright (c) 2009-present The Bitcoin Core developers 3 // Distributed under the MIT software license, see the accompanying 4 // file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 6 #ifndef BITCOIN_LOGGING_H 7 #define BITCOIN_LOGGING_H 8 9 #include <threadsafety.h> 10 #include <tinyformat.h> 11 #include <util/fs.h> 12 #include <util/string.h> 13 #include <util/time.h> 14 15 #include <atomic> 16 #include <cstdint> 17 #include <functional> 18 #include <list> 19 #include <mutex> 20 #include <string> 21 #include <unordered_map> 22 #include <vector> 23 24 static const bool DEFAULT_LOGTIMEMICROS = false; 25 static const bool DEFAULT_LOGIPS = false; 26 static const bool DEFAULT_LOGTIMESTAMPS = true; 27 static const bool DEFAULT_LOGTHREADNAMES = false; 28 static const bool DEFAULT_LOGSOURCELOCATIONS = false; 29 static constexpr bool DEFAULT_LOGLEVELALWAYS = false; 30 extern const char * const DEFAULT_DEBUGLOGFILE; 31 32 extern bool fLogIPs; 33 34 struct LogCategory { 35 std::string category; 36 bool active; 37 }; 38 39 namespace BCLog { 40 using CategoryMask = uint64_t; 41 enum LogFlags : CategoryMask { 42 NONE = CategoryMask{0}, 43 NET = (CategoryMask{1} << 0), 44 TOR = (CategoryMask{1} << 1), 45 MEMPOOL = (CategoryMask{1} << 2), 46 HTTP = (CategoryMask{1} << 3), 47 BENCH = (CategoryMask{1} << 4), 48 ZMQ = (CategoryMask{1} << 5), 49 WALLETDB = (CategoryMask{1} << 6), 50 RPC = (CategoryMask{1} << 7), 51 ESTIMATEFEE = (CategoryMask{1} << 8), 52 ADDRMAN = (CategoryMask{1} << 9), 53 SELECTCOINS = (CategoryMask{1} << 10), 54 REINDEX = (CategoryMask{1} << 11), 55 CMPCTBLOCK = (CategoryMask{1} << 12), 56 RAND = (CategoryMask{1} << 13), 57 PRUNE = (CategoryMask{1} << 14), 58 PROXY = (CategoryMask{1} << 15), 59 MEMPOOLREJ = (CategoryMask{1} << 16), 60 LIBEVENT = (CategoryMask{1} << 17), 61 COINDB = (CategoryMask{1} << 18), 62 QT = (CategoryMask{1} << 19), 63 LEVELDB = (CategoryMask{1} << 20), 64 VALIDATION = (CategoryMask{1} << 21), 65 I2P = (CategoryMask{1} << 22), 66 IPC = (CategoryMask{1} << 23), 67 #ifdef DEBUG_LOCKCONTENTION 68 LOCK = (CategoryMask{1} << 24), 69 #endif 70 BLOCKSTORAGE = (CategoryMask{1} << 25), 71 TXRECONCILIATION = (CategoryMask{1} << 26), 72 SCAN = (CategoryMask{1} << 27), 73 TXPACKAGES = (CategoryMask{1} << 28), 74 ALL = ~NONE, 75 }; 76 enum class Level { 77 Trace = 0, // High-volume or detailed logging for development/debugging 78 Debug, // Reasonably noisy logging, but still usable in production 79 Info, // Default 80 Warning, 81 Error, 82 }; 83 constexpr auto DEFAULT_LOG_LEVEL{Level::Debug}; 84 constexpr size_t DEFAULT_MAX_LOG_BUFFER{1'000'000}; // buffer up to 1MB of log data prior to StartLogging 85 86 class Logger 87 { 88 public: 89 struct BufferedLog { 90 SystemClock::time_point now; 91 std::chrono::seconds mocktime; 92 std::string str, logging_function, source_file, threadname; 93 int source_line; 94 LogFlags category; 95 Level level; 96 }; 97 98 private: 99 mutable StdMutex m_cs; // Can not use Mutex from sync.h because in debug mode it would cause a deadlock when a potential deadlock was detected 100 101 FILE* m_fileout GUARDED_BY(m_cs) = nullptr; 102 std::list<BufferedLog> m_msgs_before_open GUARDED_BY(m_cs); 103 bool m_buffering GUARDED_BY(m_cs) = true; //!< Buffer messages before logging can be started. 104 size_t m_max_buffer_memusage GUARDED_BY(m_cs){DEFAULT_MAX_LOG_BUFFER}; 105 size_t m_cur_buffer_memusage GUARDED_BY(m_cs){0}; 106 size_t m_buffer_lines_discarded GUARDED_BY(m_cs){0}; 107 108 //! Category-specific log level. Overrides `m_log_level`. 109 std::unordered_map<LogFlags, Level> m_category_log_levels GUARDED_BY(m_cs); 110 111 //! If there is no category-specific log level, all logs with a severity 112 //! level lower than `m_log_level` will be ignored. 113 std::atomic<Level> m_log_level{DEFAULT_LOG_LEVEL}; 114 115 /** Log categories bitfield. */ 116 std::atomic<CategoryMask> m_categories{BCLog::NONE}; 117 118 void FormatLogStrInPlace(std::string& str, LogFlags category, Level level, std::string_view source_file, int source_line, std::string_view logging_function, std::string_view threadname, SystemClock::time_point now, std::chrono::seconds mocktime) const; 119 120 std::string LogTimestampStr(SystemClock::time_point now, std::chrono::seconds mocktime) const; 121 122 /** Slots that connect to the print signal */ 123 std::list<std::function<void(const std::string&)>> m_print_callbacks GUARDED_BY(m_cs) {}; 124 125 /** Send a string to the log output (internal) */ 126 void LogPrintStr_(std::string_view str, std::string_view logging_function, std::string_view source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) 127 EXCLUSIVE_LOCKS_REQUIRED(m_cs); 128 129 std::string GetLogPrefix(LogFlags category, Level level) const; 130 131 public: 132 bool m_print_to_console = false; 133 bool m_print_to_file = false; 134 135 bool m_log_timestamps = DEFAULT_LOGTIMESTAMPS; 136 bool m_log_time_micros = DEFAULT_LOGTIMEMICROS; 137 bool m_log_threadnames = DEFAULT_LOGTHREADNAMES; 138 bool m_log_sourcelocations = DEFAULT_LOGSOURCELOCATIONS; 139 bool m_always_print_category_level = DEFAULT_LOGLEVELALWAYS; 140 141 fs::path m_file_path; 142 std::atomic<bool> m_reopen_file{false}; 143 144 /** Send a string to the log output */ 145 void LogPrintStr(std::string_view str, std::string_view logging_function, std::string_view source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) 146 EXCLUSIVE_LOCKS_REQUIRED(!m_cs); 147 148 /** Returns whether logs will be written to any output */ 149 bool Enabled() const EXCLUSIVE_LOCKS_REQUIRED(!m_cs) 150 { 151 StdLockGuard scoped_lock(m_cs); 152 return m_buffering || m_print_to_console || m_print_to_file || !m_print_callbacks.empty(); 153 } 154 155 /** Connect a slot to the print signal and return the connection */ 156 std::list<std::function<void(const std::string&)>>::iterator PushBackCallback(std::function<void(const std::string&)> fun) EXCLUSIVE_LOCKS_REQUIRED(!m_cs) 157 { 158 StdLockGuard scoped_lock(m_cs); 159 m_print_callbacks.push_back(std::move(fun)); 160 return --m_print_callbacks.end(); 161 } 162 163 /** Delete a connection */ 164 void DeleteCallback(std::list<std::function<void(const std::string&)>>::iterator it) EXCLUSIVE_LOCKS_REQUIRED(!m_cs) 165 { 166 StdLockGuard scoped_lock(m_cs); 167 m_print_callbacks.erase(it); 168 } 169 170 /** Start logging (and flush all buffered messages) */ 171 bool StartLogging() EXCLUSIVE_LOCKS_REQUIRED(!m_cs); 172 /** Only for testing */ 173 void DisconnectTestLogger() EXCLUSIVE_LOCKS_REQUIRED(!m_cs); 174 175 /** Disable logging 176 * This offers a slight speedup and slightly smaller memory usage 177 * compared to leaving the logging system in its default state. 178 * Mostly intended for libbitcoin-kernel apps that don't want any logging. 179 * Should be used instead of StartLogging(). 180 */ 181 void DisableLogging() EXCLUSIVE_LOCKS_REQUIRED(!m_cs); 182 183 void ShrinkDebugFile(); 184 185 std::unordered_map<LogFlags, Level> CategoryLevels() const EXCLUSIVE_LOCKS_REQUIRED(!m_cs) 186 { 187 StdLockGuard scoped_lock(m_cs); 188 return m_category_log_levels; 189 } 190 void SetCategoryLogLevel(const std::unordered_map<LogFlags, Level>& levels) EXCLUSIVE_LOCKS_REQUIRED(!m_cs) 191 { 192 StdLockGuard scoped_lock(m_cs); 193 m_category_log_levels = levels; 194 } 195 bool SetCategoryLogLevel(std::string_view category_str, std::string_view level_str) EXCLUSIVE_LOCKS_REQUIRED(!m_cs); 196 197 Level LogLevel() const { return m_log_level.load(); } 198 void SetLogLevel(Level level) { m_log_level = level; } 199 bool SetLogLevel(std::string_view level); 200 201 CategoryMask GetCategoryMask() const { return m_categories.load(); } 202 203 void EnableCategory(LogFlags flag); 204 bool EnableCategory(std::string_view str); 205 void DisableCategory(LogFlags flag); 206 bool DisableCategory(std::string_view str); 207 208 bool WillLogCategory(LogFlags category) const; 209 bool WillLogCategoryLevel(LogFlags category, Level level) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs); 210 211 /** Returns a vector of the log categories in alphabetical order. */ 212 std::vector<LogCategory> LogCategoriesList() const; 213 /** Returns a string with the log categories in alphabetical order. */ 214 std::string LogCategoriesString() const 215 { 216 return util::Join(LogCategoriesList(), ", ", [&](const LogCategory& i) { return i.category; }); 217 }; 218 219 //! Returns a string with all user-selectable log levels. 220 std::string LogLevelsString() const; 221 222 //! Returns the string representation of a log level. 223 static std::string LogLevelToStr(BCLog::Level level); 224 225 bool DefaultShrinkDebugFile() const; 226 }; 227 228 } // namespace BCLog 229 230 BCLog::Logger& LogInstance(); 231 232 /** Return true if log accepts specified category, at the specified level. */ 233 static inline bool LogAcceptCategory(BCLog::LogFlags category, BCLog::Level level) 234 { 235 return LogInstance().WillLogCategoryLevel(category, level); 236 } 237 238 /** Return true if str parses as a log category and set the flag */ 239 bool GetLogCategory(BCLog::LogFlags& flag, std::string_view str); 240 241 template <typename... Args> 242 inline void LogPrintFormatInternal(std::string_view logging_function, std::string_view source_file, const int source_line, const BCLog::LogFlags flag, const BCLog::Level level, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args) 243 { 244 if (LogInstance().Enabled()) { 245 std::string log_msg; 246 try { 247 log_msg = tfm::format(fmt, args...); 248 } catch (tinyformat::format_error& fmterr) { 249 log_msg = "Error \"" + std::string{fmterr.what()} + "\" while formatting log message: " + fmt.fmt; 250 } 251 LogInstance().LogPrintStr(log_msg, logging_function, source_file, source_line, flag, level); 252 } 253 } 254 255 #define LogPrintLevel_(category, level, ...) LogPrintFormatInternal(__func__, __FILE__, __LINE__, category, level, __VA_ARGS__) 256 257 // Log unconditionally. 258 // Be conservative when using functions that unconditionally log to debug.log! 259 // It should not be the case that an inbound peer can fill up a user's storage 260 // with debug.log entries. 261 #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, __VA_ARGS__) 262 #define LogWarning(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Warning, __VA_ARGS__) 263 #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, __VA_ARGS__) 264 265 // Deprecated unconditional logging. 266 #define LogPrintf(...) LogInfo(__VA_ARGS__) 267 268 // Use a macro instead of a function for conditional logging to prevent 269 // evaluating arguments when logging for the category is not enabled. 270 271 // Log conditionally, prefixing the output with the passed category name and severity level. 272 #define LogPrintLevel(category, level, ...) \ 273 do { \ 274 if (LogAcceptCategory((category), (level))) { \ 275 LogPrintLevel_(category, level, __VA_ARGS__); \ 276 } \ 277 } while (0) 278 279 // Log conditionally, prefixing the output with the passed category name. 280 #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) 281 #define LogTrace(category, ...) LogPrintLevel(category, BCLog::Level::Trace, __VA_ARGS__) 282 283 #endif // BITCOIN_LOGGING_H