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 
35 bool fLogIPs = DEFAULT_LOGIPS;
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_file_mutex);
45 
46  assert(m_fileout == nullptr);
47  assert(!m_file_path.empty());
48 
50  if (!m_fileout) {
51  return false;
52  }
53 
54  setbuf(m_fileout, nullptr); // unbuffered
55  // dump buffered messages from before we opened the log
56  while (!m_msgs_before_open.empty()) {
57  FileWriteStr(m_msgs_before_open.front(), m_fileout);
58  m_msgs_before_open.pop_front();
59  }
60 
61  return true;
62 }
63 
65 {
66  m_categories |= flag;
67 }
68 
69 bool BCLog::Logger::EnableCategory(const std::string& str)
70 {
71  BCLog::LogFlags flag;
72  if (!GetLogCategory(flag, str)) return false;
73  EnableCategory(flag);
74  return true;
75 }
76 
78 {
79  m_categories &= ~flag;
80 }
81 
82 bool BCLog::Logger::DisableCategory(const std::string& str)
83 {
84  BCLog::LogFlags flag;
85  if (!GetLogCategory(flag, str)) return false;
86  DisableCategory(flag);
87  return true;
88 }
89 
91 {
92  return (m_categories.load(std::memory_order_relaxed) & category) != 0;
93 }
94 
96 {
97  return m_categories == BCLog::NONE;
98 }
99 
101 {
103  std::string category;
104 };
105 
107 {
108  {BCLog::NONE, "0"},
109  {BCLog::NONE, "none"},
110  {BCLog::NET, "net"},
111  {BCLog::TOR, "tor"},
112  {BCLog::MEMPOOL, "mempool"},
113  {BCLog::HTTP, "http"},
114  {BCLog::BENCH, "bench"},
115  {BCLog::ZMQ, "zmq"},
116  {BCLog::DB, "db"},
117  {BCLog::RPC, "rpc"},
118  {BCLog::ESTIMATEFEE, "estimatefee"},
119  {BCLog::ADDRMAN, "addrman"},
120  {BCLog::SELECTCOINS, "selectcoins"},
121  {BCLog::REINDEX, "reindex"},
122  {BCLog::CMPCTBLOCK, "cmpctblock"},
123  {BCLog::RAND, "rand"},
124  {BCLog::PRUNE, "prune"},
125  {BCLog::PROXY, "proxy"},
126  {BCLog::MEMPOOLREJ, "mempoolrej"},
127  {BCLog::LIBEVENT, "libevent"},
128  {BCLog::COINDB, "coindb"},
129  {BCLog::QT, "qt"},
130  {BCLog::LEVELDB, "leveldb"},
131  {BCLog::ALL, "1"},
132  {BCLog::ALL, "all"},
133 };
134 
135 bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str)
136 {
137  if (str == "") {
138  flag = BCLog::ALL;
139  return true;
140  }
141  for (const CLogCategoryDesc& category_desc : LogCategories) {
142  if (category_desc.category == str) {
143  flag = category_desc.flag;
144  return true;
145  }
146  }
147  return false;
148 }
149 
150 std::string ListLogCategories()
151 {
152  std::string ret;
153  int outcount = 0;
154  for (const CLogCategoryDesc& category_desc : LogCategories) {
155  // Omit the special cases.
156  if (category_desc.flag != BCLog::NONE && category_desc.flag != BCLog::ALL) {
157  if (outcount != 0) ret += ", ";
158  ret += category_desc.category;
159  outcount++;
160  }
161  }
162  return ret;
163 }
164 
165 std::vector<CLogCategoryActive> ListActiveLogCategories()
166 {
167  std::vector<CLogCategoryActive> ret;
168  for (const CLogCategoryDesc& category_desc : LogCategories) {
169  // Omit the special cases.
170  if (category_desc.flag != BCLog::NONE && category_desc.flag != BCLog::ALL) {
171  CLogCategoryActive catActive;
172  catActive.category = category_desc.category;
173  catActive.active = LogAcceptCategory(category_desc.flag);
174  ret.push_back(catActive);
175  }
176  }
177  return ret;
178 }
179 
180 std::string BCLog::Logger::LogTimestampStr(const std::string& str)
181 {
182  std::string strStamped;
183 
184  if (!m_log_timestamps)
185  return str;
186 
187  if (m_started_new_line) {
188  int64_t nTimeMicros = GetTimeMicros();
189  strStamped = FormatISO8601DateTime(nTimeMicros/1000000);
190  if (m_log_time_micros) {
191  strStamped.pop_back();
192  strStamped += strprintf(".%06dZ", nTimeMicros%1000000);
193  }
194  int64_t mocktime = GetMockTime();
195  if (mocktime) {
196  strStamped += " (mocktime: " + FormatISO8601DateTime(mocktime) + ")";
197  }
198  strStamped += ' ' + str;
199  } else
200  strStamped = str;
201 
202  return strStamped;
203 }
204 
205 void BCLog::Logger::LogPrintStr(const std::string &str)
206 {
207  std::string str_prefixed = str;
208 
210  str_prefixed.insert(0, "[" + util::ThreadGetInternalName() + "] ");
211  }
212 
213  str_prefixed = LogTimestampStr(str_prefixed);
214 
215  m_started_new_line = !str.empty() && str[str.size()-1] == '\n';
216 
217  if (m_print_to_console) {
218  // print to console
219  fwrite(str_prefixed.data(), 1, str_prefixed.size(), stdout);
220  fflush(stdout);
221  }
222  if (m_print_to_file) {
223  std::lock_guard<std::mutex> scoped_lock(m_file_mutex);
224 
225  // buffer if we haven't opened the log yet
226  if (m_fileout == nullptr) {
227  m_msgs_before_open.push_back(str_prefixed);
228  }
229  else
230  {
231  // reopen the log file, if requested
232  if (m_reopen_file) {
233  m_reopen_file = false;
234  FILE* new_fileout = fsbridge::fopen(m_file_path, "a");
235  if (new_fileout) {
236  setbuf(new_fileout, nullptr); // unbuffered
237  fclose(m_fileout);
238  m_fileout = new_fileout;
239  }
240  }
241  FileWriteStr(str_prefixed, m_fileout);
242  }
243  }
244 }
245 
247 {
248  // Amount of debug.log to save at end when shrinking (must fit in memory)
249  constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;
250 
251  assert(!m_file_path.empty());
252 
253  // Scroll debug.log if it's getting too big
254  FILE* file = fsbridge::fopen(m_file_path, "r");
255 
256  // Special files (e.g. device nodes) may not have a size.
257  size_t log_size = 0;
258  try {
259  log_size = fs::file_size(m_file_path);
260  } catch (const fs::filesystem_error&) {}
261 
262  // If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE
263  // trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes
264  if (file && log_size > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10))
265  {
266  // Restart the file with some of the end
267  std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
268  if (fseek(file, -((long)vch.size()), SEEK_END)) {
269  LogPrintf("Failed to shrink debug log file: fseek(...) failed\n");
270  fclose(file);
271  return;
272  }
273  int nBytes = fread(vch.data(), 1, vch.size(), file);
274  fclose(file);
275 
276  file = fsbridge::fopen(m_file_path, "w");
277  if (file)
278  {
279  fwrite(vch.data(), 1, nBytes, file);
280  fclose(file);
281  }
282  }
283  else if (file != nullptr)
284  fclose(file);
285 }
void EnableCategory(LogFlags flag)
Definition: logging.cpp:64
BCLog::Logger & LogInstance()
Definition: logging.cpp:14
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:15
fs::path m_file_path
Definition: logging.h:87
#define strprintf
Definition: tinyformat.h:1066
std::string ListLogCategories()
Returns a string with the log categories.
Definition: logging.cpp:150
BCLog::LogFlags flag
Definition: logging.cpp:102
std::atomic< bool > m_reopen_file
Definition: logging.h:88
std::string FormatISO8601DateTime(int64_t nTime)
ISO 8601 formatting is preferred.
Definition: time.cpp:79
bool m_print_to_console
Definition: logging.h:80
bool m_print_to_file
Definition: logging.h:81
void LogPrintStr(const std::string &str)
Send a string to the log output.
Definition: logging.cpp:205
std::string category
Definition: logging.cpp:103
bool m_log_threadnames
Definition: logging.h:85
bool m_log_time_micros
Definition: logging.h:84
int64_t GetMockTime()
Definition: time.cpp:35
void DisableCategory(LogFlags flag)
Definition: logging.cpp:77
bool WillLogCategory(LogFlags category) const
Definition: logging.cpp:90
std::atomic< uint32_t > m_categories
Log categories bitfield.
Definition: logging.h:75
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:135
int64_t GetTimeMicros()
Definition: time.cpp:48
std::mutex m_file_mutex
Definition: logging.h:64
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:72
FILE * m_fileout
Definition: logging.h:63
const std::string & ThreadGetInternalName()
Get the thread&#39;s internal (in-memory) name; used e.g.
Definition: threadnames.cpp:54
const CLogCategoryDesc LogCategories[]
Definition: logging.cpp:106
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 OpenDebugLog()
Definition: logging.cpp:42
bool m_log_timestamps
Definition: logging.h:83
const char *const DEFAULT_DEBUGLOGFILE
Definition: logging.cpp:12
std::vector< CLogCategoryActive > ListActiveLogCategories()
Returns a vector of the active log categories.
Definition: logging.cpp:165
void ShrinkDebugFile()
Definition: logging.cpp:246
std::string LogTimestampStr(const std::string &str)
Definition: logging.cpp:180
bool DefaultShrinkDebugFile() const
Definition: logging.cpp:95