Skip to content

Commit 90e49c1

Browse files
committed
Merge bitcoin#24464: logging: Add severity level to logs
e11cdc9 logging: Add log severity level to net.cpp (klementtan) a829064 logging: Add severity level to logs. (klementtan) Pull request description: **Overview**: This PR introduces a new macro, `LogPrintLevel`, that allows developers to add logs with the severity level. Additionally, it will also print the log category if it is specified. Sample log: ``` 2022-03-04T16:41:15Z [opencon] [net:debug] trying connection XX.XX.XXX.XXX:YYYYY lastseen=2.7hrs ``` **Motivation**: This feature was suggested in bitcoin#20576 and I believe that it will bring the following benefits: * Allow for easier filtering of logs in `debug.log` * Can be extended to allow users to select the minimum level of logs they would like to view (not in the scope of this PR) **Details**: * New log format. `... [category:level]...`. ie: * Do not print category if `category == NONE` * Do not print level if `level == NONE` * If `category == NONE` and `level == NONE`, do not print any fields (current behaviour) * Previous logging functions: * `LogPrintf`: no changes in log as it calls `LogPrintf_` with `category = NONE` and `level = NONE` * `LogPrint`: prints additional `[category]` field as it calls `LogPrintf_` with `category = category` and `level = NONE` * `net.cpp`: As a proof of concept, updated logs with obvious severity (ie prefixed with `Warning/Error:..`) to use the new logging with severity. **Testing**: * Compiling and running `bitcoind` with this PR should instantly display logs with the category name (ie `net/tor/...`) * Grepping for `net:debug` in `debug.log` should display the updated logs with severity level: <details> <summary>Code</summary> ``` $ grep "net:debug" debug.log 2022-03-04T16:41:15Z [opencon] [net:debug] trying connection XXX:YYY lastseen=2.7hrs 2022-03-04T16:41:16Z [opencon] [net:debug] trying connection XXX:YYY lastseen=16.9hrs 2022-03-04T16:41:17Z [opencon] [net:debug] trying connection XXX:YYY lastseen=93.2hrs 2022-03-04T16:41:18Z [opencon] [net:debug] trying connection XXX:YYY lastseen=2.7hrs ``` </details> ACKs for top commit: laanwj: Code review and lightly tested ACK e11cdc9 Tree-SHA512: 89a8c86667ccc0688e5acfdbd399aac1f5bec9f978a160e40b0210b0d9b8fdc338479583fc5bd2e2bc785821363f174f578d52136d228e8f638a20abbf0a568f
2 parents 7008087 + e11cdc9 commit 90e49c1

File tree

4 files changed

+265
-23
lines changed

4 files changed

+265
-23
lines changed

src/logging.cpp

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ const CLogCategoryDesc LogCategories[] =
171171

172172
bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str)
173173
{
174-
if (str == "") {
174+
if (str.empty()) {
175175
flag = BCLog::ALL;
176176
return true;
177177
}
@@ -184,6 +184,91 @@ bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str)
184184
return false;
185185
}
186186

187+
std::string LogLevelToStr(BCLog::Level level)
188+
{
189+
switch (level) {
190+
case BCLog::Level::None:
191+
return "none";
192+
case BCLog::Level::Debug:
193+
return "debug";
194+
case BCLog::Level::Info:
195+
return "info";
196+
case BCLog::Level::Warning:
197+
return "warning";
198+
case BCLog::Level::Error:
199+
return "error";
200+
}
201+
assert(false);
202+
}
203+
204+
std::string LogCategoryToStr(BCLog::LogFlags category)
205+
{
206+
// Each log category string representation should sync with LogCategories
207+
switch (category) {
208+
case BCLog::LogFlags::NONE:
209+
return "none";
210+
case BCLog::LogFlags::NET:
211+
return "net";
212+
case BCLog::LogFlags::TOR:
213+
return "tor";
214+
case BCLog::LogFlags::MEMPOOL:
215+
return "mempool";
216+
case BCLog::LogFlags::HTTP:
217+
return "http";
218+
case BCLog::LogFlags::BENCH:
219+
return "bench";
220+
case BCLog::LogFlags::ZMQ:
221+
return "zmq";
222+
case BCLog::LogFlags::WALLETDB:
223+
return "walletdb";
224+
case BCLog::LogFlags::RPC:
225+
return "rpc";
226+
case BCLog::LogFlags::ESTIMATEFEE:
227+
return "estimatefee";
228+
case BCLog::LogFlags::ADDRMAN:
229+
return "addrman";
230+
case BCLog::LogFlags::SELECTCOINS:
231+
return "selectcoins";
232+
case BCLog::LogFlags::REINDEX:
233+
return "reindex";
234+
case BCLog::LogFlags::CMPCTBLOCK:
235+
return "cmpctblock";
236+
case BCLog::LogFlags::RAND:
237+
return "rand";
238+
case BCLog::LogFlags::PRUNE:
239+
return "prune";
240+
case BCLog::LogFlags::PROXY:
241+
return "proxy";
242+
case BCLog::LogFlags::MEMPOOLREJ:
243+
return "mempoolrej";
244+
case BCLog::LogFlags::LIBEVENT:
245+
return "libevent";
246+
case BCLog::LogFlags::COINDB:
247+
return "coindb";
248+
case BCLog::LogFlags::QT:
249+
return "qt";
250+
case BCLog::LogFlags::LEVELDB:
251+
return "leveldb";
252+
case BCLog::LogFlags::VALIDATION:
253+
return "validation";
254+
case BCLog::LogFlags::I2P:
255+
return "i2p";
256+
case BCLog::LogFlags::IPC:
257+
return "ipc";
258+
#ifdef DEBUG_LOCKCONTENTION
259+
case BCLog::LogFlags::LOCK:
260+
return "lock";
261+
#endif
262+
case BCLog::LogFlags::UTIL:
263+
return "util";
264+
case BCLog::LogFlags::BLOCKSTORE:
265+
return "blockstorage";
266+
case BCLog::LogFlags::ALL:
267+
return "all";
268+
}
269+
assert(false);
270+
}
271+
187272
std::vector<LogCategory> BCLog::Logger::LogCategoriesList() const
188273
{
189274
// Sort log categories by alphabetical order.
@@ -249,11 +334,31 @@ namespace BCLog {
249334
}
250335
} // namespace BCLog
251336

252-
void BCLog::Logger::LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, const int source_line)
337+
void BCLog::Logger::LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, const int source_line, const BCLog::LogFlags category, const BCLog::Level level)
253338
{
254339
StdLockGuard scoped_lock(m_cs);
255340
std::string str_prefixed = LogEscapeMessage(str);
256341

342+
if ((category != LogFlags::NONE || level != Level::None) && m_started_new_line) {
343+
std::string s{"["};
344+
345+
if (category != LogFlags::NONE) {
346+
s += LogCategoryToStr(category);
347+
}
348+
349+
if (category != LogFlags::NONE && level != Level::None) {
350+
// Only add separator if both flag and level are not NONE
351+
s += ":";
352+
}
353+
354+
if (level != Level::None) {
355+
s += LogLevelToStr(level);
356+
}
357+
358+
s += "] ";
359+
str_prefixed.insert(0, s);
360+
}
361+
257362
if (m_log_sourcelocations && m_started_new_line) {
258363
str_prefixed.insert(0, "[" + RemovePrefix(source_file, "./") + ":" + ToString(source_line) + "] [" + logging_function + "] ");
259364
}

src/logging.h

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ namespace BCLog {
6767
BLOCKSTORE = (1 << 26),
6868
ALL = ~(uint32_t)0,
6969
};
70+
enum class Level {
71+
Debug = 0,
72+
None = 1,
73+
Info = 2,
74+
Warning = 3,
75+
Error = 4,
76+
};
7077

7178
class Logger
7279
{
@@ -105,7 +112,7 @@ namespace BCLog {
105112
std::atomic<bool> m_reopen_file{false};
106113

107114
/** Send a string to the log output */
108-
void LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, const int source_line);
115+
void LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, const int source_line, const BCLog::LogFlags category, const BCLog::Level level);
109116

110117
/** Returns whether logs will be written to any output */
111118
bool Enabled() const
@@ -173,7 +180,7 @@ bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str);
173180
// peer can fill up a user's disk with debug.log entries.
174181

175182
template <typename... Args>
176-
static inline void LogPrintf_(const std::string& logging_function, const std::string& source_file, const int source_line, const char* fmt, const Args&... args)
183+
static inline void LogPrintf_(const std::string& logging_function, const std::string& source_file, const int source_line, const BCLog::LogFlags flag, const BCLog::Level level, const char* fmt, const Args&... args)
177184
{
178185
if (LogInstance().Enabled()) {
179186
std::string log_msg;
@@ -183,19 +190,29 @@ static inline void LogPrintf_(const std::string& logging_function, const std::st
183190
/* Original format string will have newline so don't add one here */
184191
log_msg = "Error \"" + std::string(fmterr.what()) + "\" while formatting log message: " + fmt;
185192
}
186-
LogInstance().LogPrintStr(log_msg, logging_function, source_file, source_line);
193+
LogInstance().LogPrintStr(log_msg, logging_function, source_file, source_line, flag, level);
187194
}
188195
}
189196

190-
#define LogPrintf(...) LogPrintf_(__func__, __FILE__, __LINE__, __VA_ARGS__)
197+
198+
#define LogPrintLevel_(category, level, ...) LogPrintf_(__func__, __FILE__, __LINE__, category, level, __VA_ARGS__)
199+
200+
#define LogPrintf(...) LogPrintLevel_(BCLog::LogFlags::NONE, BCLog::Level::None, __VA_ARGS__)
191201

192202
// Use a macro instead of a function for conditional logging to prevent
193203
// evaluating arguments when logging for the category is not enabled.
194-
#define LogPrint(category, ...) \
195-
do { \
196-
if (LogAcceptCategory((category))) { \
197-
LogPrintf(__VA_ARGS__); \
198-
} \
204+
#define LogPrint(category, ...) \
205+
do { \
206+
if (LogAcceptCategory((category))) { \
207+
LogPrintLevel_(category, BCLog::Level::None, __VA_ARGS__); \
208+
} \
209+
} while (0)
210+
211+
#define LogPrintLevel(level, category, ...) \
212+
do { \
213+
if (LogAcceptCategory((category))) { \
214+
LogPrintLevel_(category, level, __VA_ARGS__); \
215+
} \
199216
} while (0)
200217

201218
#endif // BITCOIN_LOGGING_H

src/net.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ static CAddress GetBindAddress(SOCKET sock)
430430
if (!getsockname(sock, (struct sockaddr*)&sockaddr_bind, &sockaddr_bind_len)) {
431431
addr_bind.SetSockAddr((const struct sockaddr*)&sockaddr_bind);
432432
} else {
433-
LogPrint(BCLog::NET, "Warning: getsockname failed\n");
433+
LogPrintLevel(BCLog::Level::Warning, BCLog::NET, "getsockname failed\n");
434434
}
435435
}
436436
return addr_bind;
@@ -454,9 +454,9 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
454454
}
455455

456456
/// debug print
457-
LogPrint(BCLog::NET, "trying connection %s lastseen=%.1fhrs\n",
458-
pszDest ? pszDest : addrConnect.ToString(),
459-
pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);
457+
LogPrintLevel(BCLog::Level::Debug, BCLog::NET, "trying connection %s lastseen=%.1fhrs\n",
458+
pszDest ? pszDest : addrConnect.ToString(),
459+
pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime) / 3600.0);
460460

461461
// Resolve
462462
const uint16_t default_port{pszDest != nullptr ? Params().GetDefaultPort(pszDest) :
@@ -1140,7 +1140,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
11401140
}
11411141

11421142
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) {
1143-
LogPrintf("Warning: Unknown socket family\n");
1143+
LogPrintLevel(BCLog::Level::Warning, BCLog::NET, "Unknown socket family\n");
11441144
} else {
11451145
addr = CAddress{MaybeFlipIPv6toCJDNS(addr), NODE_NONE};
11461146
}
@@ -2397,15 +2397,15 @@ bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError,
23972397
socklen_t len = sizeof(sockaddr);
23982398
if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
23992399
{
2400-
strError = strprintf(Untranslated("Error: Bind address family for %s not supported"), addrBind.ToString());
2401-
LogPrintf("%s\n", strError.original);
2400+
strError = strprintf(Untranslated("Bind address family for %s not supported"), addrBind.ToString());
2401+
LogPrintLevel(BCLog::Level::Error, BCLog::NET, "%s\n", strError.original);
24022402
return false;
24032403
}
24042404

24052405
std::unique_ptr<Sock> sock = CreateSock(addrBind);
24062406
if (!sock) {
2407-
strError = strprintf(Untranslated("Error: Couldn't open socket for incoming connections (socket returned error %s)"), NetworkErrorString(WSAGetLastError()));
2408-
LogPrintf("%s\n", strError.original);
2407+
strError = strprintf(Untranslated("Couldn't open socket for incoming connections (socket returned error %s)"), NetworkErrorString(WSAGetLastError()));
2408+
LogPrintLevel(BCLog::Level::Error, BCLog::NET, "%s\n", strError.original);
24092409
return false;
24102410
}
24112411

@@ -2441,16 +2441,16 @@ bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError,
24412441
strError = strprintf(_("Unable to bind to %s on this computer. %s is probably already running."), addrBind.ToString(), PACKAGE_NAME);
24422442
else
24432443
strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr));
2444-
LogPrintf("%s\n", strError.original);
2444+
LogPrintLevel(BCLog::Level::Error, BCLog::NET, "%s\n", strError.original);
24452445
return false;
24462446
}
24472447
LogPrintf("Bound to %s\n", addrBind.ToString());
24482448

24492449
// Listen for incoming connections
24502450
if (listen(sock->Get(), SOMAXCONN) == SOCKET_ERROR)
24512451
{
2452-
strError = strprintf(_("Error: Listening for incoming connections failed (listen returned error %s)"), NetworkErrorString(WSAGetLastError()));
2453-
LogPrintf("%s\n", strError.original);
2452+
strError = strprintf(_("Listening for incoming connections failed (listen returned error %s)"), NetworkErrorString(WSAGetLastError()));
2453+
LogPrintLevel(BCLog::Level::Error, BCLog::NET, "%s\n", strError.original);
24542454
return false;
24552455
}
24562456

0 commit comments

Comments
 (0)