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