Bitcoin ABC 0.30.5
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#include <util/fs.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
18const char *const DEFAULT_DEBUGLOGFILE = "debug.log";
19
36 static BCLog::Logger *g_logger{new BCLog::Logger()};
37 return *g_logger;
38}
39
40static 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 }
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 }
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::TXPACKAGES, "txpackages"},
138 {BCLog::ALL, "1"},
139 {BCLog::ALL, "all"},
140};
141
142bool GetLogCategory(BCLog::LogFlags &flag, const std::string &str) {
143 if (str == "") {
144 flag = BCLog::ALL;
145 return true;
146 }
147 for (const CLogCategoryDesc &category_desc : LogCategories) {
148 if (category_desc.category == str) {
149 flag = category_desc.flag;
150 return true;
151 }
152 }
153 return false;
154}
155
156std::vector<LogCategory> BCLog::Logger::LogCategoriesList() const {
157 // Sort log categories by alphabetical order.
158 std::array<CLogCategoryDesc, std::size(LogCategories)> categories;
159 std::copy(std::begin(LogCategories), std::end(LogCategories),
160 categories.begin());
161 std::sort(categories.begin(), categories.end(),
162 [](auto a, auto b) { return a.category < b.category; });
163
164 std::vector<LogCategory> ret;
165 for (const CLogCategoryDesc &category_desc : categories) {
166 if (category_desc.flag == BCLog::NONE ||
167 category_desc.flag == BCLog::ALL) {
168 continue;
169 }
170 LogCategory catActive;
171 catActive.category = category_desc.category;
172 catActive.active = WillLogCategory(category_desc.flag);
173 ret.push_back(catActive);
174 }
175 return ret;
176}
177
179 if (m_fileout) {
180 fclose(m_fileout);
181 }
182}
183
184std::string BCLog::Logger::LogTimestampStr(const std::string &str) {
185 std::string strStamped;
186
187 if (!m_log_timestamps) {
188 return str;
189 }
190
191 if (m_started_new_line) {
192 int64_t nTimeMicros = GetTimeMicros();
193 strStamped = FormatISO8601DateTime(nTimeMicros / 1000000);
194 if (m_log_time_micros) {
195 strStamped.pop_back();
196 strStamped += strprintf(".%06dZ", nTimeMicros % 1000000);
197 }
198 std::chrono::seconds mocktime = GetMockTime();
199 if (mocktime > 0s) {
200 strStamped += " (mocktime: " +
201 FormatISO8601DateTime(count_seconds(mocktime)) + ")";
202 }
203 strStamped += ' ' + str;
204 } else {
205 strStamped = str;
206 }
207
208 return strStamped;
209}
210
211namespace BCLog {
219std::string LogEscapeMessage(const std::string &str) {
220 std::string ret;
221 for (char ch_in : str) {
222 uint8_t ch = (uint8_t)ch_in;
223 if ((ch >= 32 || ch == '\n') && ch != '\x7f') {
224 ret += ch_in;
225 } else {
226 ret += strprintf("\\x%02x", ch);
227 }
228 }
229 return ret;
230}
231} // namespace BCLog
232
233void BCLog::Logger::LogPrintStr(const std::string &str,
234 const std::string &logging_function,
235 const std::string &source_file,
236 const int source_line) {
237 StdLockGuard scoped_lock(m_cs);
238 std::string str_prefixed = LogEscapeMessage(str);
239
240 if (m_log_sourcelocations && m_started_new_line) {
241 str_prefixed.insert(0, "[" + RemovePrefix(source_file, "./") + ":" +
242 ToString(source_line) + "] [" +
243 logging_function + "] ");
244 }
245
246 if (m_log_threadnames && m_started_new_line) {
247 str_prefixed.insert(0, "[" + util::ThreadGetInternalName() + "] ");
248 }
249
250 str_prefixed = LogTimestampStr(str_prefixed);
251
252 m_started_new_line = !str.empty() && str[str.size() - 1] == '\n';
253
254 if (m_buffering) {
255 // buffer if we haven't started logging yet
256 m_msgs_before_open.push_back(str_prefixed);
257 return;
258 }
259
260 if (m_print_to_console) {
261 // Print to console.
262 fwrite(str_prefixed.data(), 1, str_prefixed.size(), stdout);
263 fflush(stdout);
264 }
265 for (const auto &cb : m_print_callbacks) {
266 cb(str_prefixed);
267 }
268 if (m_print_to_file) {
269 assert(m_fileout != nullptr);
270
271 // Reopen the log file, if requested.
272 if (m_reopen_file) {
273 m_reopen_file = false;
274 FILE *new_fileout = fsbridge::fopen(m_file_path, "a");
275 if (new_fileout) {
276 // unbuffered.
277 setbuf(m_fileout, nullptr);
278 fclose(m_fileout);
279 m_fileout = new_fileout;
280 }
281 }
282 FileWriteStr(str_prefixed, m_fileout);
283 }
284}
285
287 // Amount of debug.log to save at end when shrinking (must fit in memory)
288 constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;
289
290 assert(!m_file_path.empty());
291
292 // Scroll debug.log if it's getting too big.
293 FILE *file = fsbridge::fopen(m_file_path, "r");
294
295 // Special files (e.g. device nodes) may not have a size.
296 size_t log_size = 0;
297 try {
298 log_size = fs::file_size(m_file_path);
299 } catch (const fs::filesystem_error &) {
300 }
301
302 // If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE
303 // trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes.
304 if (file && log_size > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10)) {
305 // Restart the file with some of the end.
306 std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
307 if (fseek(file, -((long)vch.size()), SEEK_END)) {
308 LogPrintf("Failed to shrink debug log file: fseek(...) failed\n");
309 fclose(file);
310 return;
311 }
312 int nBytes = fread(vch.data(), 1, vch.size(), file);
313 fclose(file);
314
315 file = fsbridge::fopen(m_file_path, "w");
316 if (file) {
317 fwrite(vch.data(), 1, nBytes, file);
318 fclose(file);
319 }
320 } else if (file != nullptr) {
321 fclose(file);
322 }
323}
324
326 m_categories |= category;
327}
328
329bool BCLog::Logger::EnableCategory(const std::string &str) {
330 BCLog::LogFlags flag;
331 if (!GetLogCategory(flag, str)) {
332 return false;
333 }
334 EnableCategory(flag);
335 return true;
336}
337
339 m_categories &= ~category;
340}
341
342bool BCLog::Logger::DisableCategory(const std::string &str) {
343 BCLog::LogFlags flag;
344 if (!GetLogCategory(flag, str)) {
345 return false;
346 }
347 DisableCategory(flag);
348 return true;
349}
350
352 // ALL is not meant to be used as a logging category, but only as a mask
353 // representing all categories.
354 if (category == BCLog::NONE || category == BCLog::ALL) {
355 LogPrintf("Error trying to log using a category mask instead of an "
356 "explicit category.\n");
357 return true;
358 }
359
360 return (m_categories.load(std::memory_order_relaxed) & category) != 0;
361}
362
364 return m_categories != BCLog::NONE;
365}
bool WillLogCategory(LogFlags category) const
Return true if log accepts specified category.
Definition: logging.cpp:351
std::string LogTimestampStr(const std::string &str)
Definition: logging.cpp:184
void DisconnectTestLogger()
Only for testing.
Definition: logging.cpp:89
bool DefaultShrinkDebugFile() const
Default for whether ShrinkDebugFile should be run.
Definition: logging.cpp:363
fs::path m_file_path
Definition: logging.h:111
std::vector< LogCategory > LogCategoriesList() const
Returns a vector of the log categories in alphabetical order.
Definition: logging.cpp:156
void DisableCategory(LogFlags category)
Definition: logging.cpp:338
void EnableCategory(LogFlags category)
Definition: logging.cpp:325
bool StartLogging()
Start logging (and flush all buffered messages)
Definition: logging.cpp:44
void ShrinkDebugFile()
Definition: logging.cpp:286
bool m_print_to_file
Definition: logging.h:104
bool m_print_to_console
Definition: logging.h:103
StdMutex m_cs
Definition: logging.h:78
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:233
const CLogCategoryDesc LogCategories[]
Definition: logging.cpp:104
static int FileWriteStr(const std::string &str, FILE *fp)
Definition: logging.cpp:40
BCLog::Logger & LogInstance()
Definition: logging.cpp:20
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:142
bool fLogIPs
Definition: logging.cpp:17
const char *const DEFAULT_DEBUGLOGFILE
Definition: logging.cpp:18
static const bool DEFAULT_LOGIPS
Definition: logging.h:23
#define LogPrintf(...)
Definition: logging.h:207
std::string LogEscapeMessage(const std::string &str)
Belts and suspenders: make sure outgoing log messages don't contain potentially suspicious characters...
Definition: logging.cpp:219
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
@ TXPACKAGES
Definition: logging.h:70
@ WALLETDB
Definition: logging.h:46
@ ADDRMAN
Definition: logging.h:49
@ ALL
Definition: logging.h:71
@ 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:30
const std::string & ThreadGetInternalName()
Get the thread's internal (in-memory) name; used e.g.
Definition: threadnames.cpp:39
std::string RemovePrefix(std::string_view str, std::string_view prefix)
Definition: string.h:50
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition: string.h:100
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())