/ src / logging.h
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