Bitcoin Core  0.18.99
P2P Digital Currency
logging.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2018 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/time.h>
9 
10 #include <mutex>
11 
12 const char * const DEFAULT_DEBUGLOGFILE = "debug.log";
13 
15 {
31  static BCLog::Logger* g_logger{new BCLog::Logger()};
32  return *g_logger;
33 }
34 
36 
37 static int FileWriteStr(const std::string &str, FILE *fp)
38 {
39  return fwrite(str.data(), 1, str.size(), fp);
40 }
41 
43 {
44  std::lock_guard<std::mutex> scoped_lock(m_cs);
45 
46  assert(m_buffering);
47  assert(m_fileout == nullptr);
48 
49  if (m_print_to_file) {
50  assert(!m_file_path.empty());
52  if (!m_fileout) {
53  return false;
54  }
55 
56  setbuf(m_fileout, nullptr); // unbuffered
57 
58  // Add newlines to the logfile to distinguish this execution from the
59  // last one.
60  FileWriteStr("\n\n\n\n\n", m_fileout);
61  }
62 
63  // dump buffered messages from before we opened the log
64  m_buffering = false;
65  while (!m_msgs_before_open.empty()) {
66  const std::string& s = m_msgs_before_open.front();
67 
69  if (m_print_to_console) fwrite(s.data(), 1, s.size(), stdout);
70 
71  m_msgs_before_open.pop_front();
72  }
73  if (m_print_to_console) fflush(stdout);
74 
75  return true;
76 }
77 
79 {
80  std::lock_guard<std::mutex> scoped_lock(m_cs);
81  m_buffering = true;
82  if (m_fileout != nullptr) fclose(m_fileout);
83  m_fileout = nullptr;
84 }
85 
87 {
88  m_categories |= flag;
89 }
90 
91 bool BCLog::Logger::EnableCategory(const std::string& str)
92 {
93  BCLog::LogFlags flag;
94  if (!GetLogCategory(flag, str)) return false;
95  EnableCategory(flag);
96  return true;
97 }
98 
100 {
101  m_categories &= ~flag;
102 }
103 
104 bool BCLog::Logger::DisableCategory(const std::string& str)
105 {
106  BCLog::LogFlags flag;
107  if (!GetLogCategory(flag, str)) return false;
108  DisableCategory(flag);
109  return true;
110 }
111 
113 {
114  return (m_categories.load(std::memory_order_relaxed) & category) != 0;
115 }
116 
118 {
119  return m_categories == BCLog::NONE;
120 }
121 
123 {
125  std::string category;
126 };
127 
129 {
130  {BCLog::NONE, "0"},
131  {BCLog::NONE, "none"},
132  {BCLog::NET, "net"},
133  {BCLog::TOR, "tor"},
134  {BCLog::MEMPOOL, "mempool"},
135  {BCLog::HTTP, "http"},
136  {BCLog::BENCH, "bench"},
137  {BCLog::ZMQ, "zmq"},
138  {BCLog::DB, "db"},
139  {BCLog::RPC, "rpc"},
140  {BCLog::ESTIMATEFEE, "estimatefee"},
141  {BCLog::ADDRMAN, "addrman"},
142  {BCLog::SELECTCOINS, "selectcoins"},
143  {BCLog::REINDEX, "reindex"},
144  {BCLog::CMPCTBLOCK, "cmpctblock"},
145  {BCLog::RAND, "rand"},
146  {BCLog::PRUNE, "prune"},
147  {BCLog::PROXY, "proxy"},
148  {BCLog::MEMPOOLREJ, "mempoolrej"},
149  {BCLog::LIBEVENT, "libevent"},
150  {BCLog::COINDB, "coindb"},
151  {BCLog::QT, "qt"},
152  {BCLog::LEVELDB, "leveldb"},
153  {BCLog::ALL, "1"},
154  {BCLog::ALL, "all"},
155 };
156 
157 bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str)
158 {
159  if (str == "") {
160  flag = BCLog::ALL;
161  return true;
162  }
163  for (const CLogCategoryDesc& category_desc : LogCategories) {
164  if (category_desc.category == str) {
165  flag = category_desc.flag;
166  return true;
167  }
168  }
169  return false;
170 }
171 
172 std::string ListLogCategories()
173 {
174  std::string ret;
175  int outcount = 0;
176  for (const CLogCategoryDesc& category_desc : LogCategories) {
177  // Omit the special cases.
178  if (category_desc.flag != BCLog::NONE && category_desc.flag != BCLog::ALL) {
179  if (outcount != 0) ret += ", ";
180  ret += category_desc.category;
181  outcount++;
182  }
183  }
184  return ret;
185 }
186 
187 std::vector<CLogCategoryActive> ListActiveLogCategories()
188 {
189  std::vector<CLogCategoryActive> ret;
190  for (const CLogCategoryDesc& category_desc : LogCategories) {
191  // Omit the special cases.
192  if (category_desc.flag != BCLog::NONE && category_desc.flag != BCLog::ALL) {
193  CLogCategoryActive catActive;
194  catActive.category = category_desc.category;
195  catActive.active = LogAcceptCategory(category_desc.flag);
196  ret.push_back(catActive);
197  }
198  }
199  return ret;
200 }
201 
202 std::string BCLog::Logger::LogTimestampStr(const std::string& str)
203 {
204  std::string strStamped;
205 
206  if (!m_log_timestamps)
207  return str;
208 
209  if (m_started_new_line) {
210  int64_t nTimeMicros = GetTimeMicros();
211  strStamped = FormatISO8601DateTime(nTimeMicros/1000000);
212  if (m_log_time_micros) {
213  strStamped.pop_back();
214  strStamped += strprintf(".%06dZ", nTimeMicros%1000000);
215  }
216  int64_t mocktime = GetMockTime();
217  if (mocktime) {
218  strStamped += " (mocktime: " + FormatISO8601DateTime(mocktime) + ")";
219  }
220  strStamped += ' ' + str;
221  } else
222  strStamped = str;
223 
224  return strStamped;
225 }
226 
227 void BCLog::Logger::LogPrintStr(const std::string& str)
228 {
229  std::lock_guard<std::mutex> scoped_lock(m_cs);
230  std::string str_prefixed = str;
231 
233  str_prefixed.insert(0, "[" + util::ThreadGetInternalName() + "] ");
234  }
235 
236  str_prefixed = LogTimestampStr(str_prefixed);
237 
238  m_started_new_line = !str.empty() && str[str.size()-1] == '\n';
239 
240  if (m_buffering) {
241  // buffer if we haven't started logging yet
242  m_msgs_before_open.push_back(str_prefixed);
243  return;
244  }
245 
246  if (m_print_to_console) {
247  // print to console
248  fwrite(str_prefixed.data(), 1, str_prefixed.size(), stdout);
249  fflush(stdout);
250  }
251  if (m_print_to_file) {
252  assert(m_fileout != nullptr);
253 
254  // reopen the log file, if requested
255  if (m_reopen_file) {
256  m_reopen_file = false;
257  FILE* new_fileout = fsbridge::fopen(m_file_path, "a");
258  if (new_fileout) {
259  setbuf(new_fileout, nullptr); // unbuffered
260  fclose(m_fileout);
261  m_fileout = new_fileout;
262  }
263  }
264  FileWriteStr(str_prefixed, m_fileout);
265  }
266 }
267 
269 {
270  // Amount of debug.log to save at end when shrinking (must fit in memory)
271  constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;
272 
273  assert(!m_file_path.empty());
274 
275  // Scroll debug.log if it's getting too big
276  FILE* file = fsbridge::fopen(m_file_path, "r");
277 
278  // Special files (e.g. device nodes) may not have a size.
279  size_t log_size = 0;
280  try {
281  log_size = fs::file_size(m_file_path);
282  } catch (const fs::filesystem_error&) {}
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  {
288  // Restart the file with some of the end
289  std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
290  if (fseek(file, -((long)vch.size()), SEEK_END)) {
291  LogPrintf("Failed to shrink debug log file: fseek(...) failed\n");
292  fclose(file);
293  return;
294  }
295  int nBytes = fread(vch.data(), 1, vch.size(), file);
296  fclose(file);
297 
298  file = fsbridge::fopen(m_file_path, "w");
299  if (file)
300  {
301  fwrite(vch.data(), 1, nBytes, file);
302  fclose(file);
303  }
304  }
305  else if (file != nullptr)
306  fclose(file);
307 }
void EnableCategory(LogFlags flag)
Definition: logging.cpp:86
BCLog::Logger & LogInstance()
Definition: logging.cpp:14
std::mutex m_cs
Definition: logging.h:63
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:15
fs::path m_file_path
Definition: logging.h:88
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1067
std::string ListLogCategories()
Returns a string with the log categories.
Definition: logging.cpp:172
BCLog::LogFlags flag
Definition: logging.cpp:124
std::atomic< bool > m_reopen_file
Definition: logging.h:89
static void LogPrintf(const char *fmt, const Args &... args)
Definition: logging.h:144
std::string FormatISO8601DateTime(int64_t nTime)
ISO 8601 formatting is preferred.
Definition: time.cpp:93
bool m_print_to_console
Definition: logging.h:81
bool m_print_to_file
Definition: logging.h:82
void LogPrintStr(const std::string &str)
Send a string to the log output.
Definition: logging.cpp:227
std::string category
Definition: logging.cpp:125
bool m_log_threadnames
Definition: logging.h:86
bool m_log_time_micros
Definition: logging.h:85
int64_t GetMockTime()
For testing.
Definition: time.cpp:49
void DisableCategory(LogFlags flag)
Definition: logging.cpp:99
bool WillLogCategory(LogFlags category) const
Definition: logging.cpp:112
static bool LogAcceptCategory(BCLog::LogFlags category)
Return true if log accepts specified category.
Definition: logging.h:125
std::atomic< uint32_t > m_categories
Log categories bitfield.
Definition: logging.h:76
void DisconnectTestLogger()
Only for testing.
Definition: logging.cpp:78
bool StartLogging()
Start logging (and flush all buffered messages)
Definition: logging.cpp:42
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:157
int64_t GetTimeMicros()
Returns the system time (not mockable)
Definition: time.cpp:62
std::atomic_bool m_started_new_line
m_started_new_line is a state variable that will suppress printing of the timestamp when multiple cal...
Definition: logging.h:73
FILE * m_fileout
Definition: logging.h:64
const std::string & ThreadGetInternalName()
Get the thread&#39;s internal (in-memory) name; used e.g.
Definition: threadnames.cpp:54
static int FileWriteStr(const std::string &str, FILE *fp)
Definition: logging.cpp:37
const CLogCategoryDesc LogCategories[]
Definition: logging.cpp:128
bool fLogIPs
Definition: logging.cpp:35
LogFlags
Definition: logging.h:34
std::string category
Definition: logging.h:29
std::list< std::string > m_msgs_before_open
Definition: logging.h:65
bool m_buffering
Buffer messages before logging can be started. GUARDED_BY(m_cs)
Definition: logging.h:66
bool m_log_timestamps
Definition: logging.h:84
static const bool DEFAULT_LOGIPS
Definition: logging.h:20
const char *const DEFAULT_DEBUGLOGFILE
Definition: logging.cpp:12
std::vector< CLogCategoryActive > ListActiveLogCategories()
Returns a vector of the active log categories.
Definition: logging.cpp:187
void ShrinkDebugFile()
Definition: logging.cpp:268
std::string LogTimestampStr(const std::string &str)
Definition: logging.cpp:202
bool DefaultShrinkDebugFile() const
Definition: logging.cpp:117