LCOV - code coverage report
Current view: top level - src - logging.h (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 30 48 62.5 %
Date: 2023-09-26 12:08:55 Functions: 22 228 9.6 %

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

Generated by: LCOV version 1.14