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