Line data Source code
1 : // Copyright (c) 2009-2010 Satoshi Nakamoto 2 : // Copyright (c) 2009-2020 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 <fs.h> 10 : #include <tinyformat.h> 11 : #include <threadsafety.h> 12 : #include <util/string.h> 13 : 14 : #include <atomic> 15 : #include <cstdint> 16 : #include <list> 17 : #include <mutex> 18 : #include <string> 19 : #include <vector> 20 : 21 : static const bool DEFAULT_LOGTIMEMICROS = false; 22 : static const bool DEFAULT_LOGIPS = false; 23 : static const bool DEFAULT_LOGTIMESTAMPS = true; 24 : static const bool DEFAULT_LOGTHREADNAMES = false; 25 : extern const char * const DEFAULT_DEBUGLOGFILE; 26 : 27 : extern bool fLogIPs; 28 : 29 970800 : struct LogCategory { 30 : std::string category; 31 : bool active; 32 : }; 33 : 34 : namespace BCLog { 35 : enum LogFlags : uint32_t { 36 : NONE = 0, 37 : NET = (1 << 0), 38 : TOR = (1 << 1), 39 : MEMPOOL = (1 << 2), 40 : HTTP = (1 << 3), 41 : BENCH = (1 << 4), 42 : ZMQ = (1 << 5), 43 : WALLETDB = (1 << 6), 44 : RPC = (1 << 7), 45 : ESTIMATEFEE = (1 << 8), 46 : ADDRMAN = (1 << 9), 47 : SELECTCOINS = (1 << 10), 48 : REINDEX = (1 << 11), 49 : CMPCTBLOCK = (1 << 12), 50 : RAND = (1 << 13), 51 : PRUNE = (1 << 14), 52 : PROXY = (1 << 15), 53 : MEMPOOLREJ = (1 << 16), 54 : LIBEVENT = (1 << 17), 55 : COINDB = (1 << 18), 56 : QT = (1 << 19), 57 : LEVELDB = (1 << 20), 58 : VALIDATION = (1 << 21), 59 : ALL = ~(uint32_t)0, 60 : }; 61 : 62 5470 : class Logger 63 : { 64 : private: 65 : 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 66 : 67 1094 : FILE* m_fileout GUARDED_BY(m_cs) = nullptr; 68 : std::list<std::string> m_msgs_before_open GUARDED_BY(m_cs); 69 1094 : bool m_buffering GUARDED_BY(m_cs) = true; //!< Buffer messages before logging can be started. 70 : 71 : /** 72 : * m_started_new_line is a state variable that will suppress printing of 73 : * the timestamp when multiple calls are made that don't end in a 74 : * newline. 75 : */ 76 1094 : std::atomic_bool m_started_new_line{true}; 77 : 78 : /** Log categories bitfield. */ 79 1094 : std::atomic<uint32_t> m_categories{0}; 80 : 81 : std::string LogTimestampStr(const std::string& str); 82 : 83 : /** Slots that connect to the print signal */ 84 1094 : std::list<std::function<void(const std::string&)>> m_print_callbacks GUARDED_BY(m_cs) {}; 85 : 86 : public: 87 1094 : bool m_print_to_console = false; 88 1094 : bool m_print_to_file = false; 89 : 90 1094 : bool m_log_timestamps = DEFAULT_LOGTIMESTAMPS; 91 1094 : bool m_log_time_micros = DEFAULT_LOGTIMEMICROS; 92 1094 : bool m_log_threadnames = DEFAULT_LOGTHREADNAMES; 93 : 94 : fs::path m_file_path; 95 1094 : std::atomic<bool> m_reopen_file{false}; 96 : 97 : /** Send a string to the log output */ 98 : void LogPrintStr(const std::string& str); 99 : 100 : /** Returns whether logs will be written to any output */ 101 2284456 : bool Enabled() const 102 : { 103 2284456 : StdLockGuard scoped_lock(m_cs); 104 2284456 : return m_buffering || m_print_to_console || m_print_to_file || !m_print_callbacks.empty(); 105 2284483 : } 106 : 107 : /** Connect a slot to the print signal and return the connection */ 108 460 : std::list<std::function<void(const std::string&)>>::iterator PushBackCallback(std::function<void(const std::string&)> fun) 109 : { 110 460 : StdLockGuard scoped_lock(m_cs); 111 460 : m_print_callbacks.push_back(std::move(fun)); 112 460 : return --m_print_callbacks.end(); 113 460 : } 114 : 115 : /** Delete a connection */ 116 9 : void DeleteCallback(std::list<std::function<void(const std::string&)>>::iterator it) 117 : { 118 9 : StdLockGuard scoped_lock(m_cs); 119 9 : m_print_callbacks.erase(it); 120 9 : } 121 : 122 : /** Start logging (and flush all buffered messages) */ 123 : bool StartLogging(); 124 : /** Only for testing */ 125 : void DisconnectTestLogger(); 126 : 127 : void ShrinkDebugFile(); 128 : 129 10 : uint32_t GetCategoryMask() const { return m_categories.load(); } 130 : 131 : void EnableCategory(LogFlags flag); 132 : bool EnableCategory(const std::string& str); 133 : void DisableCategory(LogFlags flag); 134 : bool DisableCategory(const std::string& str); 135 : 136 : bool WillLogCategory(LogFlags category) const; 137 : /** Returns a vector of the log categories */ 138 : std::vector<LogCategory> LogCategoriesList(); 139 : /** Returns a string with the log categories */ 140 3231 : std::string LogCategoriesString() 141 : { 142 74313 : return Join(LogCategoriesList(), ", ", [&](const LogCategory& i) { return i.category; }); 143 0 : }; 144 : 145 : bool DefaultShrinkDebugFile() const; 146 : }; 147 : 148 : } // namespace BCLog 149 : 150 : BCLog::Logger& LogInstance(); 151 : 152 : /** Return true if log accepts specified category */ 153 2259291 : static inline bool LogAcceptCategory(BCLog::LogFlags category) 154 : { 155 2259291 : return LogInstance().WillLogCategory(category); 156 : } 157 : 158 : /** Return true if str parses as a log category and set the flag */ 159 : bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str); 160 : 161 : // Be conservative when using LogPrintf/error or other things which 162 : // unconditionally log to debug.log! It should not be the case that an inbound 163 : // peer can fill up a user's disk with debug.log entries. 164 : 165 : template <typename... Args> 166 2284478 : static inline void LogPrintf(const char* fmt, const Args&... args) 167 : { 168 2284478 : if (LogInstance().Enabled()) { 169 2262804 : std::string log_msg; 170 : try { 171 2262804 : log_msg = tfm::format(fmt, args...); 172 2262764 : } catch (tinyformat::format_error& fmterr) { 173 : /* Original format string will have newline so don't add one here */ 174 0 : log_msg = "Error \"" + std::string(fmterr.what()) + "\" while formatting log message: " + fmt; 175 0 : } 176 2262756 : LogInstance().LogPrintStr(log_msg); 177 2262804 : } 178 2284483 : } 179 : 180 : // Use a macro instead of a function for conditional logging to prevent 181 : // evaluating arguments when logging for the category is not enabled. 182 : #define LogPrint(category, ...) \ 183 : do { \ 184 : if (LogAcceptCategory((category))) { \ 185 : LogPrintf(__VA_ARGS__); \ 186 : } \ 187 : } while (0) 188 : 189 : #endif // BITCOIN_LOGGING_H