LCOV - code coverage report
Current view: top level - src - logging.h (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 56 64 87.5 %
Date: 2026-06-25 07:23:51 Functions: 159 556 28.6 %

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

Generated by: LCOV version 1.16