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 <crypto/siphash.h> 10 #include <logging/categories.h> // IWYU pragma: export 11 #include <span.h> 12 #include <util/byte_units.h> 13 #include <util/fs.h> 14 #include <util/log.h> // IWYU pragma: export 15 #include <util/stdmutex.h> 16 #include <util/string.h> 17 #include <util/time.h> 18 19 #include <atomic> 20 #include <cstdint> 21 #include <cstring> 22 #include <functional> 23 #include <list> 24 #include <memory> 25 #include <optional> 26 #include <string> 27 #include <unordered_map> 28 #include <vector> 29 30 static const bool DEFAULT_LOGTIMEMICROS = false; 31 static const bool DEFAULT_LOGIPS = false; 32 static const bool DEFAULT_LOGTIMESTAMPS = true; 33 static const bool DEFAULT_LOGTHREADNAMES = false; 34 static const bool DEFAULT_LOGSOURCELOCATIONS = false; 35 static constexpr bool DEFAULT_LOGLEVELALWAYS = false; 36 extern const char * const DEFAULT_DEBUGLOGFILE; 37 38 extern bool fLogIPs; 39 40 struct SourceLocationEqual { 41 bool operator()(const SourceLocation& lhs, const SourceLocation& rhs) const noexcept 42 { 43 return lhs.line() == rhs.line() && std::string_view(lhs.file_name()) == std::string_view(rhs.file_name()); 44 } 45 }; 46 47 struct SourceLocationHasher { 48 size_t operator()(const SourceLocation& s) const noexcept 49 { 50 // Use CSipHasher(0, 0) as a simple way to get uniform distribution. 51 return size_t(CSipHasher(0, 0) 52 .Write(s.line()) 53 .Write(MakeUCharSpan(std::string_view{s.file_name()})) 54 .Finalize()); 55 } 56 }; 57 58 struct LogCategory { 59 std::string category; 60 bool active; 61 }; 62 63 namespace BCLog { 64 constexpr auto DEFAULT_LOG_LEVEL{Level::Debug}; 65 constexpr size_t DEFAULT_MAX_LOG_BUFFER{1'000'000}; // buffer up to 1MB of log data prior to StartLogging 66 constexpr uint64_t RATELIMIT_MAX_BYTES{1_MiB}; // maximum number of bytes per source location that can be logged within the RATELIMIT_WINDOW 67 constexpr auto RATELIMIT_WINDOW{1h}; // time window after which log ratelimit stats are reset 68 constexpr bool DEFAULT_LOGRATELIMIT{true}; 69 70 //! Fixed window rate limiter for logging. 71 class LogRateLimiter 72 { 73 public: 74 //! Keeps track of an individual source location and how many available bytes are left for logging from it. 75 struct Stats { 76 //! Remaining bytes 77 uint64_t m_available_bytes; 78 //! Number of bytes that were consumed but didn't fit in the available bytes. 79 uint64_t m_dropped_bytes{0}; 80 81 Stats(uint64_t max_bytes) : m_available_bytes{max_bytes} {} 82 //! Updates internal accounting and returns true if enough available_bytes were remaining 83 bool Consume(uint64_t bytes); 84 }; 85 86 private: 87 mutable StdMutex m_mutex; 88 89 //! Stats for each source location that has attempted to log something. 90 std::unordered_map<SourceLocation, Stats, SourceLocationHasher, SourceLocationEqual> m_source_locations GUARDED_BY(m_mutex); 91 //! Whether any log locations are suppressed. Cached view on m_source_locations for performance reasons. 92 std::atomic<bool> m_suppression_active{false}; 93 LogRateLimiter(uint64_t max_bytes, std::chrono::seconds reset_window); 94 95 public: 96 using SchedulerFunction = std::function<void(std::function<void()>, std::chrono::milliseconds)>; 97 /** 98 * @param scheduler_func Callable object used to schedule resetting the window. The first 99 * parameter is the function to be executed, and the second is the 100 * reset_window interval. 101 * @param max_bytes Maximum number of bytes that can be logged for each source 102 * location. 103 * @param reset_window Time window after which the stats are reset. 104 */ 105 static std::shared_ptr<LogRateLimiter> Create( 106 SchedulerFunction&& scheduler_func, 107 uint64_t max_bytes, 108 std::chrono::seconds reset_window); 109 //! Maximum number of bytes logged per location per window. 110 const uint64_t m_max_bytes; 111 //! Interval after which the window is reset. 112 const std::chrono::seconds m_reset_window; 113 //! Suppression status of a source log location. 114 enum class Status { 115 UNSUPPRESSED, // string fits within the limit 116 NEWLY_SUPPRESSED, // suppression has started since this string 117 STILL_SUPPRESSED, // suppression is still ongoing 118 }; 119 //! Consumes `source_loc`'s available bytes corresponding to the size of the (formatted) 120 //! `str` and returns its status. 121 [[nodiscard]] Status Consume( 122 const SourceLocation& source_loc, 123 const std::string& str) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); 124 //! Resets all usage to zero. Called periodically by the scheduler. 125 void Reset() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); 126 //! Returns true if any log locations are currently being suppressed. 127 bool SuppressionsActive() const { return m_suppression_active; } 128 }; 129 130 class Logger 131 { 132 private: 133 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 134 135 FILE* m_fileout GUARDED_BY(m_cs) = nullptr; 136 std::list<util::log::Entry> m_msgs_before_open GUARDED_BY(m_cs); 137 bool m_buffering GUARDED_BY(m_cs) = true; //!< Buffer messages before logging can be started. 138 size_t m_max_buffer_memusage GUARDED_BY(m_cs){DEFAULT_MAX_LOG_BUFFER}; 139 size_t m_cur_buffer_memusage GUARDED_BY(m_cs){0}; 140 size_t m_buffer_lines_discarded GUARDED_BY(m_cs){0}; 141 142 //! Manages the rate limiting of each log location. 143 std::shared_ptr<LogRateLimiter> m_limiter GUARDED_BY(m_cs); 144 145 //! Category-specific log level. Overrides `m_log_level`. 146 std::unordered_map<LogFlags, Level> m_category_log_levels GUARDED_BY(m_cs); 147 148 //! If there is no category-specific log level, all logs with a severity 149 //! level lower than `m_log_level` will be ignored. 150 std::atomic<Level> m_log_level{DEFAULT_LOG_LEVEL}; 151 152 /** Log categories bitfield. */ 153 std::atomic<CategoryMask> m_categories{BCLog::NONE}; 154 155 std::string Format(const util::log::Entry& entry) const; 156 157 std::string LogTimestampStr(SystemClock::time_point now, std::chrono::seconds mocktime) const; 158 159 /** Slots that connect to the print signal */ 160 std::list<std::function<void(const std::string&)>> m_print_callbacks GUARDED_BY(m_cs){}; 161 162 /** Send an entry to the log output (internal) */ 163 void LogPrint_(util::log::Entry log_entry) EXCLUSIVE_LOCKS_REQUIRED(m_cs); 164 165 std::string GetLogPrefix(LogFlags category, Level level) const; 166 167 public: 168 bool m_print_to_console = false; 169 bool m_print_to_file = false; 170 171 bool m_log_timestamps = DEFAULT_LOGTIMESTAMPS; 172 bool m_log_time_micros = DEFAULT_LOGTIMEMICROS; 173 bool m_log_threadnames = DEFAULT_LOGTHREADNAMES; 174 bool m_log_sourcelocations = DEFAULT_LOGSOURCELOCATIONS; 175 bool m_always_print_category_level = DEFAULT_LOGLEVELALWAYS; 176 177 fs::path m_file_path; 178 std::atomic<bool> m_reopen_file{false}; 179 180 /** Send an entry to the log output */ 181 void LogPrint(util::log::Entry log_entry) EXCLUSIVE_LOCKS_REQUIRED(!m_cs); 182 183 /** Returns whether logs will be written to any output */ 184 bool Enabled() const EXCLUSIVE_LOCKS_REQUIRED(!m_cs) 185 { 186 STDLOCK(m_cs); 187 return m_buffering || m_print_to_console || m_print_to_file || !m_print_callbacks.empty(); 188 } 189 190 /** Connect a slot to the print signal and return the connection */ 191 std::list<std::function<void(const std::string&)>>::iterator PushBackCallback(std::function<void(const std::string&)> fun) EXCLUSIVE_LOCKS_REQUIRED(!m_cs) 192 { 193 STDLOCK(m_cs); 194 m_print_callbacks.push_back(std::move(fun)); 195 return --m_print_callbacks.end(); 196 } 197 198 /** Delete a connection */ 199 void DeleteCallback(std::list<std::function<void(const std::string&)>>::iterator it) EXCLUSIVE_LOCKS_REQUIRED(!m_cs) 200 { 201 STDLOCK(m_cs); 202 m_print_callbacks.erase(it); 203 } 204 205 size_t NumConnections() EXCLUSIVE_LOCKS_REQUIRED(!m_cs) 206 { 207 STDLOCK(m_cs); 208 return m_print_callbacks.size(); 209 } 210 211 /** Start logging (and flush all buffered messages) */ 212 bool StartLogging() EXCLUSIVE_LOCKS_REQUIRED(!m_cs); 213 /** Only for testing */ 214 void DisconnectTestLogger() EXCLUSIVE_LOCKS_REQUIRED(!m_cs); 215 216 void SetRateLimiting(std::shared_ptr<LogRateLimiter> limiter) EXCLUSIVE_LOCKS_REQUIRED(!m_cs) 217 { 218 STDLOCK(m_cs); 219 m_limiter = std::move(limiter); 220 } 221 222 /** Disable logging 223 * This offers a slight speedup and slightly smaller memory usage 224 * compared to leaving the logging system in its default state. 225 * Mostly intended for libbitcoin-kernel apps that don't want any logging. 226 * Should be used instead of StartLogging(). 227 */ 228 void DisableLogging() EXCLUSIVE_LOCKS_REQUIRED(!m_cs); 229 230 void ShrinkDebugFile(); 231 232 std::unordered_map<LogFlags, Level> CategoryLevels() const EXCLUSIVE_LOCKS_REQUIRED(!m_cs) 233 { 234 STDLOCK(m_cs); 235 return m_category_log_levels; 236 } 237 void SetCategoryLogLevel(const std::unordered_map<LogFlags, Level>& levels) EXCLUSIVE_LOCKS_REQUIRED(!m_cs) 238 { 239 STDLOCK(m_cs); 240 m_category_log_levels = levels; 241 } 242 void AddCategoryLogLevel(LogFlags category, Level level) EXCLUSIVE_LOCKS_REQUIRED(!m_cs) 243 { 244 STDLOCK(m_cs); 245 m_category_log_levels[category] = level; 246 } 247 bool SetCategoryLogLevel(std::string_view category_str, std::string_view level_str) EXCLUSIVE_LOCKS_REQUIRED(!m_cs); 248 249 Level LogLevel() const { return m_log_level.load(); } 250 void SetLogLevel(Level level) { m_log_level = level; } 251 bool SetLogLevel(std::string_view level); 252 253 CategoryMask GetCategoryMask() const { return m_categories.load(); } 254 255 void EnableCategory(LogFlags flag); 256 bool EnableCategory(std::string_view str); 257 void DisableCategory(LogFlags flag); 258 bool DisableCategory(std::string_view str); 259 260 bool WillLogCategory(LogFlags category) const; 261 bool WillLogCategoryLevel(LogFlags category, Level level) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs); 262 263 /** Returns a vector of the log categories in alphabetical order. */ 264 std::vector<LogCategory> LogCategoriesList() const; 265 /** Returns a string with the log categories in alphabetical order. */ 266 std::string LogCategoriesString() const 267 { 268 return util::Join(LogCategoriesList(), ", ", [&](const LogCategory& i) { return i.category; }); 269 }; 270 271 //! Returns a string with all user-selectable log levels. 272 std::string LogLevelsString() const; 273 274 //! Returns the string representation of a log level. 275 static std::string LogLevelToStr(BCLog::Level level); 276 277 bool DefaultShrinkDebugFile() const; 278 }; 279 280 } // namespace BCLog 281 282 BCLog::Logger& LogInstance(); 283 284 /** Return true if log accepts specified category, at the specified level. */ 285 static inline bool LogAcceptCategory(BCLog::LogFlags category, BCLog::Level level) 286 { 287 return LogInstance().WillLogCategoryLevel(category, level); 288 } 289 290 /// Return log flag if str parses as a log category. 291 std::optional<BCLog::LogFlags> GetLogCategory(std::string_view str); 292 293 #endif // BITCOIN_LOGGING_H