Bitcoin ABC  0.29.2
P2P Digital Currency
logging.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2016 The Bitcoin Core developers
3 // Copyright (c) 2017-2019 The Bitcoin developers
4 // Distributed under the MIT software license, see the accompanying
5 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 
7 #include <fs.h>
8 #include <logging.h>
9 
10 #include <util/string.h>
11 #include <util/threadnames.h>
12 #include <util/time.h>
13 
14 #include <algorithm>
15 #include <array>
16 
18 const char *const DEFAULT_DEBUGLOGFILE = "debug.log";
19 
36  static BCLog::Logger *g_logger{new BCLog::Logger()};
37  return *g_logger;
38 }
39 
40 static int FileWriteStr(const std::string &str, FILE *fp) {
41  return fwrite(str.data(), 1, str.size(), fp);
42 }
43 
45  StdLockGuard scoped_lock(m_cs);
46 
47  assert(m_buffering);
48  assert(m_fileout == nullptr);
49 
50  if (m_print_to_file) {
51  assert(!m_file_path.empty());
52  m_fileout = fsbridge::fopen(m_file_path, "a");
53  if (!m_fileout) {
54  return false;
55  }
56 
57  // Unbuffered.
58  setbuf(m_fileout, nullptr);
59 
60  // Add newlines to the logfile to distinguish this execution from the
61  // last one.
62  FileWriteStr("\n\n\n\n\n", m_fileout);
63  }
64 
65  // Dump buffered messages from before we opened the log.
66  m_buffering = false;
67  while (!m_msgs_before_open.empty()) {
68  const std::string &s = m_msgs_before_open.front();
69 
70  if (m_print_to_file) {
71  FileWriteStr(s, m_fileout);
72  }
73  if (m_print_to_console) {
74  fwrite(s.data(), 1, s.size(), stdout);
75  }
76  for (const auto &cb : m_print_callbacks) {
77  cb(s);
78  }
79 
80  m_msgs_before_open.pop_front();
81  }
82  if (m_print_to_console) {
83  fflush(stdout);
84  }
85 
86  return true;
87 }
88 
90  StdLockGuard scoped_lock(m_cs);
91  m_buffering = true;
92  if (m_fileout != nullptr) {
93  fclose(m_fileout);
94  }
95  m_fileout = nullptr;
96  m_print_callbacks.clear();
97 }
98 
101  std::string category;
102 };
103 
105  {BCLog::NONE, "0"},
106  {BCLog::NONE, "none"},
107  {BCLog::NET, "net"},
108  {BCLog::TOR, "tor"},
109  {BCLog::MEMPOOL, "mempool"},
110  {BCLog::HTTP, "http"},
111  {BCLog::BENCH, "bench"},
112  {BCLog::ZMQ, "zmq"},
113  {BCLog::WALLETDB, "walletdb"},
114  {BCLog::RPC, "rpc"},
115  {BCLog::ESTIMATEFEE, "estimatefee"},
116  {BCLog::ADDRMAN, "addrman"},
117  {BCLog::SELECTCOINS, "selectcoins"},
118  {BCLog::REINDEX, "reindex"},
119  {BCLog::CMPCTBLOCK, "cmpctblock"},
120  {BCLog::RAND, "rand"},
121  {BCLog::PRUNE, "prune"},
122  {BCLog::PROXY, "proxy"},
123  {BCLog::MEMPOOLREJ, "mempoolrej"},
124  {BCLog::LIBEVENT, "libevent"},
125  {BCLog::COINDB, "coindb"},
126  {BCLog::QT, "qt"},
127  {BCLog::LEVELDB, "leveldb"},
128  {BCLog::VALIDATION, "validation"},
129  {BCLog::AVALANCHE, "avalanche"},
130  {BCLog::I2P, "i2p"},
131  {BCLog::CHRONIK, "chronik"},
132 #ifdef DEBUG_LOCKCONTENTION
133  {BCLog::LOCK, "lock"},
134 #endif
135  {BCLog::BLOCKSTORE, "blockstorage"},
136  {BCLog::NETDEBUG, "netdebug"},
137  {BCLog::ALL, "1"},
138  {BCLog::ALL, "all"},
139 };
140 
141 bool GetLogCategory(BCLog::LogFlags &flag, const std::string &str) {
142  if (str == "") {
143  flag = BCLog::ALL;
144  return true;
145  }
146  for (const CLogCategoryDesc &category_desc : LogCategories) {
147  if (category_desc.category == str) {
148  flag = category_desc.flag;
149  return true;
150  }
151  }
152  return false;
153 }
154 
155 std::vector<LogCategory> BCLog::Logger::LogCategoriesList() const {
156  // Sort log categories by alphabetical order.
157  std::array<CLogCategoryDesc, std::size(LogCategories)> categories;
158  std::copy(std::begin(LogCategories), std::end(LogCategories),
159  categories.begin());
160  std::sort(categories.begin(), categories.end(),
161  [](auto a, auto b) { return a.category < b.category; });
162 
163  std::vector<LogCategory> ret;
164  for (const CLogCategoryDesc &category_desc : categories) {
165  if (category_desc.flag == BCLog::NONE ||
166  category_desc.flag == BCLog::ALL) {
167  continue;
168  }
169  LogCategory catActive;
170  catActive.category = category_desc.category;
171  catActive.active = WillLogCategory(category_desc.flag);
172  ret.push_back(catActive);
173  }
174  return ret;
175 }
176 
178  if (m_fileout) {
179  fclose(m_fileout);
180  }
181 }
182 
183 std::string BCLog::Logger::LogTimestampStr(const std::string &str) {
184  std::string strStamped;
185 
186  if (!m_log_timestamps) {
187  return str;
188  }
189 
190  if (m_started_new_line) {
191  int64_t nTimeMicros = GetTimeMicros();
192  strStamped = FormatISO8601DateTime(nTimeMicros / 1000000);
193  if (m_log_time_micros) {
194  strStamped.pop_back();
195  strStamped += strprintf(".%06dZ", nTimeMicros % 1000000);
196  }
197  std::chrono::seconds mocktime = GetMockTime();
198  if (mocktime > 0s) {
199  strStamped += " (mocktime: " +
200  FormatISO8601DateTime(count_seconds(mocktime)) + ")";
201  }
202  strStamped += ' ' + str;
203  } else {
204  strStamped = str;
205  }
206 
207  return strStamped;
208 }
209 
210 namespace BCLog {
218 std::string LogEscapeMessage(const std::string &str) {
219  std::string ret;
220  for (char ch_in : str) {
221  uint8_t ch = (uint8_t)ch_in;
222  if ((ch >= 32 || ch == '\n') && ch != '\x7f') {
223  ret += ch_in;
224  } else {
225  ret += strprintf("\\x%02x", ch);
226  }
227  }
228  return ret;
229 }
230 } // namespace BCLog
231 
232 void BCLog::Logger::LogPrintStr(const std::string &str,
233  const std::string &logging_function,
234  const std::string &source_file,
235  const int source_line) {
236  StdLockGuard scoped_lock(m_cs);
237  std::string str_prefixed = LogEscapeMessage(str);
238 
239  if (m_log_sourcelocations && m_started_new_line) {
240  str_prefixed.insert(0, "[" + RemovePrefix(source_file, "./") + ":" +
241  ToString(source_line) + "] [" +
242  logging_function + "] ");
243  }
244 
245  if (m_log_threadnames && m_started_new_line) {
246  str_prefixed.insert(0, "[" + util::ThreadGetInternalName() + "] ");
247  }
248 
249  str_prefixed = LogTimestampStr(str_prefixed);
250 
251  m_started_new_line = !str.empty() && str[str.size() - 1] == '\n';
252 
253  if (m_buffering) {
254  // buffer if we haven't started logging yet
255  m_msgs_before_open.push_back(str_prefixed);
256  return;
257  }
258 
259  if (m_print_to_console) {
260  // Print to console.
261  fwrite(str_prefixed.data(), 1, str_prefixed.size(), stdout);
262  fflush(stdout);
263  }
264  for (const auto &cb : m_print_callbacks) {
265  cb(str_prefixed);
266  }
267  if (m_print_to_file) {
268  assert(m_fileout != nullptr);
269 
270  // Reopen the log file, if requested.
271  if (m_reopen_file) {
272  m_reopen_file = false;
273  FILE *new_fileout = fsbridge::fopen(m_file_path, "a");
274  if (new_fileout) {
275  // unbuffered.
276  setbuf(m_fileout, nullptr);
277  fclose(m_fileout);
278  m_fileout = new_fileout;
279  }
280  }
281  FileWriteStr(str_prefixed, m_fileout);
282  }
283 }
284 
286  // Amount of debug.log to save at end when shrinking (must fit in memory)
287  constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;
288 
289  assert(!m_file_path.empty());
290 
291  // Scroll debug.log if it's getting too big.
292  FILE *file = fsbridge::fopen(m_file_path, "r");
293 
294  // Special files (e.g. device nodes) may not have a size.
295  size_t log_size = 0;
296  try {
297  log_size = fs::file_size(m_file_path);
298  } catch (const fs::filesystem_error &) {
299  }
300 
301  // If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE
302  // trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes.
303  if (file && log_size > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10)) {
304  // Restart the file with some of the end.
305  std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
306  if (fseek(file, -((long)vch.size()), SEEK_END)) {
307  LogPrintf("Failed to shrink debug log file: fseek(...) failed\n");
308  fclose(file);
309  return;
310  }
311  int nBytes = fread(vch.data(), 1, vch.size(), file);
312  fclose(file);
313 
314  file = fsbridge::fopen(m_file_path, "w");
315  if (file) {
316  fwrite(vch.data(), 1, nBytes, file);
317  fclose(file);
318  }
319  } else if (file != nullptr) {
320  fclose(file);
321  }
322 }
323 
325  m_categories |= category;
326 }
327 
328 bool BCLog::Logger::EnableCategory(const std::string &str) {
329  BCLog::LogFlags flag;
330  if (!GetLogCategory(flag, str)) {
331  return false;
332  }
333  EnableCategory(flag);
334  return true;
335 }
336 
338  m_categories &= ~category;
339 }
340 
341 bool BCLog::Logger::DisableCategory(const std::string &str) {
342  BCLog::LogFlags flag;
343  if (!GetLogCategory(flag, str)) {
344  return false;
345  }
346  DisableCategory(flag);
347  return true;
348 }
349 
351  // ALL is not meant to be used as a logging category, but only as a mask
352  // representing all categories.
353  if (category == BCLog::NONE || category == BCLog::ALL) {
354  LogPrintf("Error trying to log using a category mask instead of an "
355  "explicit category.\n");
356  return true;
357  }
358 
359  return (m_categories.load(std::memory_order_relaxed) & category) != 0;
360 }
361 
363  return m_categories != BCLog::NONE;
364 }
bool WillLogCategory(LogFlags category) const
Return true if log accepts specified category.
Definition: logging.cpp:350
std::string LogTimestampStr(const std::string &str)
Definition: logging.cpp:183
void DisconnectTestLogger()
Only for testing.
Definition: logging.cpp:89
bool DefaultShrinkDebugFile() const
Default for whether ShrinkDebugFile should be run.
Definition: logging.cpp:362
fs::path m_file_path
Definition: logging.h:110
std::vector< LogCategory > LogCategoriesList() const
Returns a vector of the log categories in alphabetical order.
Definition: logging.cpp:155
void DisableCategory(LogFlags category)
Definition: logging.cpp:337
void EnableCategory(LogFlags category)
Definition: logging.cpp:324
bool StartLogging()
Start logging (and flush all buffered messages)
Definition: logging.cpp:44
void ShrinkDebugFile()
Definition: logging.cpp:285
bool m_print_to_file
Definition: logging.h:103
bool m_print_to_console
Definition: logging.h:102
StdMutex m_cs
Definition: logging.h:77
void LogPrintStr(const std::string &str, const std::string &logging_function, const std::string &source_file, const int source_line)
Send a string to the log output.
Definition: logging.cpp:232
const CLogCategoryDesc LogCategories[]
Definition: logging.cpp:104
static int FileWriteStr(const std::string &str, FILE *fp)
Definition: logging.cpp:40
bool GetLogCategory(BCLog::LogFlags &flag, const std::string &str)
Return true if str parses as a log category and set the flag.
Definition: logging.cpp:141
bool fLogIPs
Definition: logging.cpp:17
const char *const DEFAULT_DEBUGLOGFILE
Definition: logging.cpp:18
BCLog::Logger & LogInstance()
Definition: logging.cpp:20
static const bool DEFAULT_LOGIPS
Definition: logging.h:23
#define LogPrintf(...)
Definition: logging.h:206
Definition: timer.h:17
std::string LogEscapeMessage(const std::string &str)
Belts and suspenders: make sure outgoing log messages don't contain potentially suspicious characters...
Definition: logging.cpp:218
LogFlags
Definition: logging.h:38
@ ESTIMATEFEE
Definition: logging.h:48
@ AVALANCHE
Definition: logging.h:62
@ RAND
Definition: logging.h:53
@ COINDB
Definition: logging.h:58
@ REINDEX
Definition: logging.h:51
@ WALLETDB
Definition: logging.h:46
@ ADDRMAN
Definition: logging.h:49
@ ALL
Definition: logging.h:70
@ NETDEBUG
Definition: logging.h:69
@ RPC
Definition: logging.h:47
@ HTTP
Definition: logging.h:43
@ LEVELDB
Definition: logging.h:60
@ NONE
Definition: logging.h:39
@ VALIDATION
Definition: logging.h:61
@ MEMPOOLREJ
Definition: logging.h:56
@ PRUNE
Definition: logging.h:54
@ TOR
Definition: logging.h:41
@ LIBEVENT
Definition: logging.h:57
@ CMPCTBLOCK
Definition: logging.h:52
@ PROXY
Definition: logging.h:55
@ CHRONIK
Definition: logging.h:64
@ ZMQ
Definition: logging.h:45
@ MEMPOOL
Definition: logging.h:42
@ SELECTCOINS
Definition: logging.h:50
@ I2P
Definition: logging.h:63
@ BENCH
Definition: logging.h:44
@ NET
Definition: logging.h:40
@ QT
Definition: logging.h:59
@ BLOCKSTORE
Definition: logging.h:68
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:28
const std::string & ThreadGetInternalName()
Get the thread's internal (in-memory) name; used e.g.
Definition: threadnames.cpp:39
std::string RemovePrefix(const std::string &str, const std::string &prefix)
Definition: string.h:38
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition: string.h:87
BCLog::LogFlags flag
Definition: logging.cpp:100
std::string category
Definition: logging.cpp:101
bool active
Definition: logging.h:33
std::string category
Definition: logging.h:32
#define LOCK(cs)
Definition: sync.h:306
int64_t GetTimeMicros()
Returns the system time (not mockable)
Definition: time.cpp:105
std::chrono::seconds GetMockTime()
For testing.
Definition: time.cpp:97
std::string FormatISO8601DateTime(int64_t nTime)
ISO 8601 formatting is preferred.
Definition: time.cpp:113
constexpr int64_t count_seconds(std::chrono::seconds t)
Definition: time.h:55
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1202
assert(!tx.IsCoinBase())