Bitcoin Core  27.99.0
P2P Digital Currency
logging.cpp
Go to the documentation of this file.
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 #include <logging.h>
7 #include <memusage.h>
8 #include <util/fs.h>
9 #include <util/string.h>
10 #include <util/threadnames.h>
11 #include <util/time.h>
12 
13 #include <array>
14 #include <map>
15 #include <optional>
16 
17 using util::Join;
19 
20 const char * const DEFAULT_DEBUGLOGFILE = "debug.log";
22 
24 {
40  static BCLog::Logger* g_logger{new BCLog::Logger()};
41  return *g_logger;
42 }
43 
45 
46 static int FileWriteStr(std::string_view str, FILE *fp)
47 {
48  return fwrite(str.data(), 1, str.size(), fp);
49 }
50 
52 {
53  StdLockGuard scoped_lock(m_cs);
54 
55  assert(m_buffering);
56  assert(m_fileout == nullptr);
57 
58  if (m_print_to_file) {
59  assert(!m_file_path.empty());
60  m_fileout = fsbridge::fopen(m_file_path, "a");
61  if (!m_fileout) {
62  return false;
63  }
64 
65  setbuf(m_fileout, nullptr); // unbuffered
66 
67  // Add newlines to the logfile to distinguish this execution from the
68  // last one.
69  FileWriteStr("\n\n\n\n\n", m_fileout);
70  }
71 
72  // dump buffered messages from before we opened the log
73  m_buffering = false;
74  if (m_buffer_lines_discarded > 0) {
75  LogPrintStr_(strprintf("Early logging buffer overflowed, %d log lines discarded.\n", m_buffer_lines_discarded), __func__, __FILE__, __LINE__, BCLog::ALL, Level::Info);
76  }
77  while (!m_msgs_before_open.empty()) {
78  const auto& buflog = m_msgs_before_open.front();
79  std::string s{buflog.str};
80  FormatLogStrInPlace(s, buflog.category, buflog.level, buflog.source_file, buflog.source_line, buflog.logging_function, buflog.threadname, buflog.now, buflog.mocktime);
81  m_msgs_before_open.pop_front();
82 
83  if (m_print_to_file) FileWriteStr(s, m_fileout);
84  if (m_print_to_console) fwrite(s.data(), 1, s.size(), stdout);
85  for (const auto& cb : m_print_callbacks) {
86  cb(s);
87  }
88  }
89  m_cur_buffer_memusage = 0;
90  if (m_print_to_console) fflush(stdout);
91 
92  return true;
93 }
94 
96 {
97  StdLockGuard scoped_lock(m_cs);
98  m_buffering = true;
99  if (m_fileout != nullptr) fclose(m_fileout);
100  m_fileout = nullptr;
101  m_print_callbacks.clear();
102  m_max_buffer_memusage = DEFAULT_MAX_LOG_BUFFER;
103  m_cur_buffer_memusage = 0;
104  m_buffer_lines_discarded = 0;
105  m_msgs_before_open.clear();
106 
107 }
108 
110 {
111  {
112  StdLockGuard scoped_lock(m_cs);
113  assert(m_buffering);
114  assert(m_print_callbacks.empty());
115  }
116  m_print_to_file = false;
117  m_print_to_console = false;
118  StartLogging();
119 }
120 
122 {
123  m_categories |= flag;
124 }
125 
126 bool BCLog::Logger::EnableCategory(std::string_view str)
127 {
128  BCLog::LogFlags flag;
129  if (!GetLogCategory(flag, str)) return false;
130  EnableCategory(flag);
131  return true;
132 }
133 
135 {
136  m_categories &= ~flag;
137 }
138 
139 bool BCLog::Logger::DisableCategory(std::string_view str)
140 {
141  BCLog::LogFlags flag;
142  if (!GetLogCategory(flag, str)) return false;
143  DisableCategory(flag);
144  return true;
145 }
146 
148 {
149  return (m_categories.load(std::memory_order_relaxed) & category) != 0;
150 }
151 
153 {
154  // Log messages at Info, Warning and Error level unconditionally, so that
155  // important troubleshooting information doesn't get lost.
156  if (level >= BCLog::Level::Info) return true;
157 
158  if (!WillLogCategory(category)) return false;
159 
160  StdLockGuard scoped_lock(m_cs);
161  const auto it{m_category_log_levels.find(category)};
162  return level >= (it == m_category_log_levels.end() ? LogLevel() : it->second);
163 }
164 
166 {
167  return m_categories == BCLog::NONE;
168 }
169 
170 static const std::map<std::string, BCLog::LogFlags, std::less<>> LOG_CATEGORIES_BY_STR{
171  {"0", BCLog::NONE},
172  {"", BCLog::NONE},
173  {"net", BCLog::NET},
174  {"tor", BCLog::TOR},
175  {"mempool", BCLog::MEMPOOL},
176  {"http", BCLog::HTTP},
177  {"bench", BCLog::BENCH},
178  {"zmq", BCLog::ZMQ},
179  {"walletdb", BCLog::WALLETDB},
180  {"rpc", BCLog::RPC},
181  {"estimatefee", BCLog::ESTIMATEFEE},
182  {"addrman", BCLog::ADDRMAN},
183  {"selectcoins", BCLog::SELECTCOINS},
184  {"reindex", BCLog::REINDEX},
185  {"cmpctblock", BCLog::CMPCTBLOCK},
186  {"rand", BCLog::RAND},
187  {"prune", BCLog::PRUNE},
188  {"proxy", BCLog::PROXY},
189  {"mempoolrej", BCLog::MEMPOOLREJ},
190  {"libevent", BCLog::LIBEVENT},
191  {"coindb", BCLog::COINDB},
192  {"qt", BCLog::QT},
193  {"leveldb", BCLog::LEVELDB},
194  {"validation", BCLog::VALIDATION},
195  {"i2p", BCLog::I2P},
196  {"ipc", BCLog::IPC},
197 #ifdef DEBUG_LOCKCONTENTION
198  {"lock", BCLog::LOCK},
199 #endif
200  {"blockstorage", BCLog::BLOCKSTORAGE},
201  {"txreconciliation", BCLog::TXRECONCILIATION},
202  {"scan", BCLog::SCAN},
203  {"txpackages", BCLog::TXPACKAGES},
204  {"1", BCLog::ALL},
205  {"all", BCLog::ALL},
206 };
207 
208 static const std::unordered_map<BCLog::LogFlags, std::string> LOG_CATEGORIES_BY_FLAG{
209  // Swap keys and values from LOG_CATEGORIES_BY_STR.
210  [](const auto& in) {
211  std::unordered_map<BCLog::LogFlags, std::string> out;
212  for (const auto& [k, v] : in) {
213  switch (v) {
214  case BCLog::NONE: out.emplace(BCLog::NONE, ""); break;
215  case BCLog::ALL: out.emplace(BCLog::ALL, "all"); break;
216  default: out.emplace(v, k);
217  }
218  }
219  return out;
221 };
222 
223 bool GetLogCategory(BCLog::LogFlags& flag, std::string_view str)
224 {
225  if (str.empty()) {
226  flag = BCLog::ALL;
227  return true;
228  }
229  auto it = LOG_CATEGORIES_BY_STR.find(str);
230  if (it != LOG_CATEGORIES_BY_STR.end()) {
231  flag = it->second;
232  return true;
233  }
234  return false;
235 }
236 
238 {
239  switch (level) {
240  case BCLog::Level::Trace:
241  return "trace";
242  case BCLog::Level::Debug:
243  return "debug";
244  case BCLog::Level::Info:
245  return "info";
247  return "warning";
248  case BCLog::Level::Error:
249  return "error";
250  }
251  assert(false);
252 }
253 
254 std::string LogCategoryToStr(BCLog::LogFlags category)
255 {
256  auto it = LOG_CATEGORIES_BY_FLAG.find(category);
257  assert(it != LOG_CATEGORIES_BY_FLAG.end());
258  return it->second;
259 }
260 
261 static std::optional<BCLog::Level> GetLogLevel(std::string_view level_str)
262 {
263  if (level_str == "trace") {
264  return BCLog::Level::Trace;
265  } else if (level_str == "debug") {
266  return BCLog::Level::Debug;
267  } else if (level_str == "info") {
268  return BCLog::Level::Info;
269  } else if (level_str == "warning") {
270  return BCLog::Level::Warning;
271  } else if (level_str == "error") {
272  return BCLog::Level::Error;
273  } else {
274  return std::nullopt;
275  }
276 }
277 
278 std::vector<LogCategory> BCLog::Logger::LogCategoriesList() const
279 {
280  std::vector<LogCategory> ret;
281  for (const auto& [category, flag] : LOG_CATEGORIES_BY_STR) {
282  if (flag != BCLog::NONE && flag != BCLog::ALL) {
283  ret.push_back(LogCategory{.category = category, .active = WillLogCategory(flag)});
284  }
285  }
286  return ret;
287 }
288 
290 static constexpr std::array<BCLog::Level, 3> LogLevelsList()
291 {
293 }
294 
296 {
297  const auto& levels = LogLevelsList();
298  return Join(std::vector<BCLog::Level>{levels.begin(), levels.end()}, ", ", [](BCLog::Level level) { return LogLevelToStr(level); });
299 }
300 
301 std::string BCLog::Logger::LogTimestampStr(SystemClock::time_point now, std::chrono::seconds mocktime) const
302 {
303  std::string strStamped;
304 
305  if (!m_log_timestamps)
306  return strStamped;
307 
308  const auto now_seconds{std::chrono::time_point_cast<std::chrono::seconds>(now)};
309  strStamped = FormatISO8601DateTime(TicksSinceEpoch<std::chrono::seconds>(now_seconds));
310  if (m_log_time_micros && !strStamped.empty()) {
311  strStamped.pop_back();
312  strStamped += strprintf(".%06dZ", Ticks<std::chrono::microseconds>(now - now_seconds));
313  }
314  if (mocktime > 0s) {
315  strStamped += " (mocktime: " + FormatISO8601DateTime(count_seconds(mocktime)) + ")";
316  }
317  strStamped += ' ';
318 
319  return strStamped;
320 }
321 
322 namespace BCLog {
330  std::string LogEscapeMessage(std::string_view str) {
331  std::string ret;
332  for (char ch_in : str) {
333  uint8_t ch = (uint8_t)ch_in;
334  if ((ch >= 32 || ch == '\n') && ch != '\x7f') {
335  ret += ch_in;
336  } else {
337  ret += strprintf("\\x%02x", ch);
338  }
339  }
340  return ret;
341  }
342 } // namespace BCLog
343 
344 std::string BCLog::Logger::GetLogPrefix(BCLog::LogFlags category, BCLog::Level level) const
345 {
346  if (category == LogFlags::NONE) category = LogFlags::ALL;
347 
348  const bool has_category{m_always_print_category_level || category != LogFlags::ALL};
349 
350  // If there is no category, Info is implied
351  if (!has_category && level == Level::Info) return {};
352 
353  std::string s{"["};
354  if (has_category) {
355  s += LogCategoryToStr(category);
356  }
357 
358  if (m_always_print_category_level || !has_category || level != Level::Debug) {
359  // If there is a category, Debug is implied, so don't add the level
360 
361  // Only add separator if we have a category
362  if (has_category) s += ":";
363  s += Logger::LogLevelToStr(level);
364  }
365 
366  s += "] ";
367  return s;
368 }
369 
370 static size_t MemUsage(const BCLog::Logger::BufferedLog& buflog)
371 {
372  return buflog.str.size() + buflog.logging_function.size() + buflog.source_file.size() + buflog.threadname.size() + memusage::MallocUsage(sizeof(memusage::list_node<BCLog::Logger::BufferedLog>));
373 }
374 
375 void BCLog::Logger::FormatLogStrInPlace(std::string& str, BCLog::LogFlags category, BCLog::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
376 {
377  str.insert(0, GetLogPrefix(category, level));
378 
379  if (m_log_sourcelocations) {
380  str.insert(0, strprintf("[%s:%d] [%s] ", RemovePrefixView(source_file, "./"), source_line, logging_function));
381  }
382 
383  if (m_log_threadnames) {
384  str.insert(0, strprintf("[%s] ", (threadname.empty() ? "unknown" : threadname)));
385  }
386 
387  str.insert(0, LogTimestampStr(now, mocktime));
388 }
389 
390 void BCLog::Logger::LogPrintStr(std::string_view str, std::string_view logging_function, std::string_view source_file, int source_line, BCLog::LogFlags category, BCLog::Level level)
391 {
392  StdLockGuard scoped_lock(m_cs);
393  return LogPrintStr_(str, logging_function, source_file, source_line, category, level);
394 }
395 
396 void BCLog::Logger::LogPrintStr_(std::string_view str, std::string_view logging_function, std::string_view source_file, int source_line, BCLog::LogFlags category, BCLog::Level level)
397 {
398  std::string str_prefixed = LogEscapeMessage(str);
399 
400  const bool starts_new_line = m_started_new_line;
401  m_started_new_line = !str.empty() && str[str.size()-1] == '\n';
402 
403  if (m_buffering) {
404  if (!starts_new_line) {
405  if (!m_msgs_before_open.empty()) {
406  m_msgs_before_open.back().str += str_prefixed;
407  m_cur_buffer_memusage += str_prefixed.size();
408  return;
409  } else {
410  // unlikely edge case; add a marker that something was trimmed
411  str_prefixed.insert(0, "[...] ");
412  }
413  }
414 
415  {
416  BufferedLog buf{
417  .now=SystemClock::now(),
418  .mocktime=GetMockTime(),
419  .str=str_prefixed,
420  .logging_function=std::string(logging_function),
421  .source_file=std::string(source_file),
422  .threadname=util::ThreadGetInternalName(),
423  .source_line=source_line,
424  .category=category,
425  .level=level,
426  };
427  m_cur_buffer_memusage += MemUsage(buf);
428  m_msgs_before_open.push_back(std::move(buf));
429  }
430 
431  while (m_cur_buffer_memusage > m_max_buffer_memusage) {
432  if (m_msgs_before_open.empty()) {
433  m_cur_buffer_memusage = 0;
434  break;
435  }
436  m_cur_buffer_memusage -= MemUsage(m_msgs_before_open.front());
437  m_msgs_before_open.pop_front();
438  ++m_buffer_lines_discarded;
439  }
440 
441  return;
442  }
443 
444  if (starts_new_line) {
445  FormatLogStrInPlace(str_prefixed, category, level, source_file, source_line, logging_function, util::ThreadGetInternalName(), SystemClock::now(), GetMockTime());
446  }
447 
448  if (m_print_to_console) {
449  // print to console
450  fwrite(str_prefixed.data(), 1, str_prefixed.size(), stdout);
451  fflush(stdout);
452  }
453  for (const auto& cb : m_print_callbacks) {
454  cb(str_prefixed);
455  }
456  if (m_print_to_file) {
457  assert(m_fileout != nullptr);
458 
459  // reopen the log file, if requested
460  if (m_reopen_file) {
461  m_reopen_file = false;
462  FILE* new_fileout = fsbridge::fopen(m_file_path, "a");
463  if (new_fileout) {
464  setbuf(new_fileout, nullptr); // unbuffered
465  fclose(m_fileout);
466  m_fileout = new_fileout;
467  }
468  }
469  FileWriteStr(str_prefixed, m_fileout);
470  }
471 }
472 
474 {
475  // Amount of debug.log to save at end when shrinking (must fit in memory)
476  constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;
477 
478  assert(!m_file_path.empty());
479 
480  // Scroll debug.log if it's getting too big
481  FILE* file = fsbridge::fopen(m_file_path, "r");
482 
483  // Special files (e.g. device nodes) may not have a size.
484  size_t log_size = 0;
485  try {
486  log_size = fs::file_size(m_file_path);
487  } catch (const fs::filesystem_error&) {}
488 
489  // If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE
490  // trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes
491  if (file && log_size > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10))
492  {
493  // Restart the file with some of the end
494  std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
495  if (fseek(file, -((long)vch.size()), SEEK_END)) {
496  LogPrintf("Failed to shrink debug log file: fseek(...) failed\n");
497  fclose(file);
498  return;
499  }
500  int nBytes = fread(vch.data(), 1, vch.size(), file);
501  fclose(file);
502 
503  file = fsbridge::fopen(m_file_path, "w");
504  if (file)
505  {
506  fwrite(vch.data(), 1, nBytes, file);
507  fclose(file);
508  }
509  }
510  else if (file != nullptr)
511  fclose(file);
512 }
513 
514 bool BCLog::Logger::SetLogLevel(std::string_view level_str)
515 {
516  const auto level = GetLogLevel(level_str);
517  if (!level.has_value() || level.value() > MAX_USER_SETABLE_SEVERITY_LEVEL) return false;
518  m_log_level = level.value();
519  return true;
520 }
521 
522 bool BCLog::Logger::SetCategoryLogLevel(std::string_view category_str, std::string_view level_str)
523 {
524  BCLog::LogFlags flag;
525  if (!GetLogCategory(flag, category_str)) return false;
526 
527  const auto level = GetLogLevel(level_str);
528  if (!level.has_value() || level.value() > MAX_USER_SETABLE_SEVERITY_LEVEL) return false;
529 
530  StdLockGuard scoped_lock(m_cs);
531  m_category_log_levels[flag] = level.value();
532  return true;
533 }
int ret
static std::string LogLevelToStr(BCLog::Level level)
Returns the string representation of a log level.
Definition: logging.cpp:237
bool WillLogCategory(LogFlags category) const
Definition: logging.cpp:147
std::string LogTimestampStr(SystemClock::time_point now, std::chrono::seconds mocktime) const
Definition: logging.cpp:301
bool DefaultShrinkDebugFile() const
Definition: logging.cpp:165
void SetCategoryLogLevel(const std::unordered_map< LogFlags, Level > &levels) EXCLUSIVE_LOCKS_REQUIRED(!m_cs)
Definition: logging.h:196
void SetLogLevel(Level level)
Definition: logging.h:204
bool WillLogCategoryLevel(LogFlags category, Level level) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs)
Definition: logging.cpp:152
fs::path m_file_path
Definition: logging.h:145
void DisableLogging() EXCLUSIVE_LOCKS_REQUIRED(!m_cs)
Disable logging This offers a slight speedup and slightly smaller memory usage compared to leaving th...
Definition: logging.cpp:109
std::vector< LogCategory > LogCategoriesList() const
Returns a vector of the log categories in alphabetical order.
Definition: logging.cpp:278
bool StartLogging() EXCLUSIVE_LOCKS_REQUIRED(!m_cs)
Start logging (and flush all buffered messages)
Definition: logging.cpp:51
void EnableCategory(LogFlags flag)
Definition: logging.cpp:121
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
Definition: logging.cpp:375
std::string GetLogPrefix(LogFlags category, Level level) const
Definition: logging.cpp:344
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) EXCLUSIVE_LOCKS_REQUIRED(!m_cs)
Send a string to the log output.
Definition: logging.cpp:390
void DisconnectTestLogger() EXCLUSIVE_LOCKS_REQUIRED(!m_cs)
Only for testing.
Definition: logging.cpp:95
std::string LogLevelsString() const
Returns a string with all user-selectable log levels.
Definition: logging.cpp:295
void ShrinkDebugFile()
Definition: logging.cpp:473
bool m_print_to_file
Definition: logging.h:137
bool m_print_to_console
Definition: logging.h:136
StdMutex m_cs
Definition: logging.h:98
void DisableCategory(LogFlags flag)
Definition: logging.cpp:134
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) EXCLUSIVE_LOCKS_REQUIRED(m_cs)
Send a string to the log output (internal)
Definition: logging.cpp:396
static int FileWriteStr(std::string_view str, FILE *fp)
Definition: logging.cpp:46
bool GetLogCategory(BCLog::LogFlags &flag, std::string_view str)
Return true if str parses as a log category and set the flag.
Definition: logging.cpp:223
static constexpr std::array< BCLog::Level, 3 > LogLevelsList()
Log severity levels that can be selected by the user.
Definition: logging.cpp:290
static size_t MemUsage(const BCLog::Logger::BufferedLog &buflog)
Definition: logging.cpp:370
static std::optional< BCLog::Level > GetLogLevel(std::string_view level_str)
Definition: logging.cpp:261
std::string LogCategoryToStr(BCLog::LogFlags category)
Definition: logging.cpp:254
static const std::map< std::string, BCLog::LogFlags, std::less<> > LOG_CATEGORIES_BY_STR
Definition: logging.cpp:170
bool fLogIPs
Definition: logging.cpp:44
static const std::unordered_map< BCLog::LogFlags, std::string > LOG_CATEGORIES_BY_FLAG
Definition: logging.cpp:208
const char *const DEFAULT_DEBUGLOGFILE
Definition: logging.cpp:20
constexpr auto MAX_USER_SETABLE_SEVERITY_LEVEL
Definition: logging.cpp:21
BCLog::Logger & LogInstance()
Definition: logging.cpp:23
static const bool DEFAULT_LOGIPS
Definition: logging.h:25
#define LogPrintf(...)
Definition: logging.h:274
Definition: timer.h:19
Level
Definition: logging.h:75
std::string LogEscapeMessage(std::string_view str)
Belts and suspenders: make sure outgoing log messages don't contain potentially suspicious characters...
Definition: logging.cpp:330
constexpr size_t DEFAULT_MAX_LOG_BUFFER
Definition: logging.h:83
LogFlags
Definition: logging.h:40
@ ESTIMATEFEE
Definition: logging.h:50
@ TXRECONCILIATION
Definition: logging.h:70
@ RAND
Definition: logging.h:55
@ BLOCKSTORAGE
Definition: logging.h:69
@ COINDB
Definition: logging.h:60
@ REINDEX
Definition: logging.h:53
@ TXPACKAGES
Definition: logging.h:72
@ WALLETDB
Definition: logging.h:48
@ SCAN
Definition: logging.h:71
@ ADDRMAN
Definition: logging.h:51
@ ALL
Definition: logging.h:73
@ RPC
Definition: logging.h:49
@ HTTP
Definition: logging.h:45
@ LEVELDB
Definition: logging.h:62
@ NONE
Definition: logging.h:41
@ VALIDATION
Definition: logging.h:63
@ MEMPOOLREJ
Definition: logging.h:58
@ PRUNE
Definition: logging.h:56
@ TOR
Definition: logging.h:43
@ LIBEVENT
Definition: logging.h:59
@ CMPCTBLOCK
Definition: logging.h:54
@ PROXY
Definition: logging.h:57
@ ZMQ
Definition: logging.h:47
@ IPC
Definition: logging.h:65
@ MEMPOOL
Definition: logging.h:44
@ SELECTCOINS
Definition: logging.h:52
@ I2P
Definition: logging.h:64
@ BENCH
Definition: logging.h:46
@ NET
Definition: logging.h:42
@ QT
Definition: logging.h:61
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:26
bool StartLogging(const ArgsManager &args)
Definition: common.cpp:104
static size_t MallocUsage(size_t alloc)
Compute the total memory used by allocating alloc bytes.
Definition: memusage.h:51
std::string ThreadGetInternalName()
Get the thread's internal (in-memory) name; used e.g.
Definition: threadnames.cpp:47
std::string_view RemovePrefixView(std::string_view str, std::string_view prefix)
Definition: string.h:84
auto Join(const C &container, const S &separator, UnaryOp unary_op)
Join all container items.
Definition: string.h:107
std::string threadname
Definition: logging.h:91
std::string source_file
Definition: logging.h:91
SystemClock::time_point now
Definition: logging.h:89
std::string logging_function
Definition: logging.h:91
std::string category
Definition: logging.h:35
#define LOCK(cs)
Definition: sync.h:257
std::chrono::seconds GetMockTime()
For testing.
Definition: time.cpp:39
std::string FormatISO8601DateTime(int64_t nTime)
ISO 8601 formatting is preferred.
Definition: time.cpp:46
constexpr int64_t count_seconds(std::chrono::seconds t)
Definition: time.h:54
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1161
assert(!tx.IsCoinBase())