Improve new LogDebug
, LogTrace
, LogInfo
, LogWarning
, LogError
macros introduced in #28318 by allowing metadata and log instances to be specified.
This allows categories to be specified at all log levels, not just debug and trace levels:
0LogError(BCLog::NET, "Something failed and needs to be fixed.\n");
1LogWarning(BCLog::NET, "Something seems wrong and may need to be fixed.\n");
2LogInfo(BCLog::NET, "Something happened you may want to know about.\n");
3LogDebug(BCLog::NET, "Something happened that may help you debug a problem.\n");
4LogTrace(BCLog::NET, "A low level event happened.\n");
It also allows log “source” objects to be specified and used:
0const BCLog::Source m_log{BCLog::NET};
1...
2LogError(m_log, "Something failed and needs to be fixed.\n");
3LogWarning(m_log, "Something seems wrong and may need to be fixed.\n");
4LogInfo(m_log, "Something happened you may want to know about.\n");
5LogDebug(m_log, "Something happened that may help you debug a problem.\n");
6LogTrace(m_log, "A low level event happened.\n");
The advantage of source objects is that they allow more metadata, not just categories, to be attached to log messages, such as wallet names, index names, chainstate names, RPC request ids, and other information to provide more context. Source objects also allow controlling which BCLog::Logger
instance is logged to, so unit tests and libbitcoinkernel applications can direct log output from different sources to different places, and not have log output from all sources combined into one stream.
The macros also support log statements with no sources or categories for convenience:
0LogError("Something failed and needs to be fixed.\n");
1LogWarning("Something seems wrong and may need to be fixed.\n");
2LogInfo("Something happened you may want to know about.\n");
3LogDebug("Something happened that may help you debug a problem.\n");
4LogTrace("A low level event happened.\n");
The PR is fully backward compatible and does not change any current behavior or require switching to any new syntax. Existing log prints continue to work exactly the same as before.
A new overview of the macros can be found in the logging header. To summarize, the changes in this PR make the macros:
- Consistent, now accepting the same parameters
- Compatible with log categories, to make it possible to filter or highlight log messages from a particular component
- Compatible with wallet logging, which includes the wallet name in log messages
- Require less verbosity, by not needing category constants to be repeated in log prints from a common source.
- Not tied to one hardcoded global Logger instance
Problems this PR attempts to solve
The new log macros introduced in #28318 are generally great. They allow writing code that is succinct and clear, and make it a lot easier to figure out what log levels are being used. Unfortunately, the new macros are slightly less general than than needed to be used throughout the codebase. Particularly:
- The new macros cannot be used conveniently in wallet code because wallet log prints are supposed to include wallet names in log messages. This PR allows adding a format hook, which #30343 uses to begin using the new macros in wallet code without boilerplate or nonstandard logging functions.
- The new macros cannot be used in libbitcoinkernel code because they do not allow specifying a logger instance. This PR allows specifying a logger instance, which #30342 uses so kernel code can specify which objects to log to.
Without changing the new macros, the only alternative approach to solving these problems would be to reimplement the macros outside the logging framework so they could be used by wallet and validation code. This PR just takes the approach of slightly generalizing these macros so they work everywhere.
Note to reviewers
I’d encourage first looking at the actual logging API changes in the PR to evaluate it and try to come an independent judgement before looking at the discussion history. Unfortunately and regrettably, I made some dismissive comments on the previous PR, so the discussion here starts out immediately heated.
A summary of the disagreement is that ajtowns believes allowing log syntax LogDebug(m_log, "debug message\n")
is harmful if log category is part of the m_log
argument instead of being an explicit category constant, because the codebase will be harder to grep. I think being able to log with source objects instead of category constants is a benefit not just for reducing verbosity, but also for outputting categories consistently instead of haphazardly, for outputting other contextual information like wallet names, index names, and chainstate names, and for being able to log to different instances and not hardcode logging macros to use one global logger.