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