tl;dr: kernel logging is cumbersome. This PR enables structured logging and a much simplified kernel logging interface. Closes #34062.
Motivation
The bitcoinkernel library (#27587) exposes functionality to interface with the kernel logging. This includes registering callbacks for log statements, level/category filtering, string formatting options, and more.
Kernel logging has a few problems:
- callbacks operate on formatted strings, so users need to parse the string to get the timestamp, category, level, ... based on which options are set. This is cumbersome, brittle, and inefficient.
- the filtering interface is not really intuitive, requiring users to call combinations of
btck_logging_set_level_categoryandbtck_logging_enable_categorywhen they want to producedebugortracelogs. The level/category system makes sense for node, because it directly controls what gets written to disk and stdout, and there are quite a lot more categories producing logs. Kernel doesn't really need this - users control what happens to the logs, and can do any filtering/manipulation in the callback they provide. - the node logging infrastructure has quite a bit more functionality than is necessary for a library, including ratelimiting, log formatting, outputting, buffering, ... This introduces unnecessary code and interface complexity.
Approach
Most of the logic in logging.h is not necessary for bitcoinkernel, so we first separate it into util/log.h and logging.h (common), then upgrade the bitcoinkernel logging interface, and finally remove the logging.cpp dependency from kernel entirely.
- Separate log generation: Add a minimal
util::log::Dispatcherthat is used to generate logs, and forwards structured log entries to registered callbacks. No formatting, rate-limiting, or output handling - that's the consumer's responsibility. Dispatcher can be configured with afilterpredicate (e.g.WillLogCategoryLevel()fornode, or a simpler levels-based filter forbitcoinkernel) to avoid unnecessary string formatting and other overhead. - Register
BCLog::Loggeron Dispatcher: Register a callback on the global Dispatcher to receive entries and handle node-specific concerns (formatting, rate-limiting, file output) without changing most of its logic. - Move logging macros to
util/log.h: Allows the entire codebase (including kernel code) to use the same macros without depending onlogging.h. - Update bitcoinkernel C API: Replace the string-based callback with
btck_LogEntrycontaining full metadata. Removebtck_LoggingOptionsand category enable/disable functions. Addbtck_logging_set_min_level()for early filtering. - Move
logging.cpptocommon: remove it as a kernel dependency entirely.
Appendix
bitcoinkernel C logging interface
struct btck_LogEntry {
const char* message; //!< Log message
size_t message_len; //!< Log message length
const char* file_name; //!< Source file name
size_t file_name_len; //!< Source file name length
const char* function_name; //!< Source function name
size_t function_name_len; //!< Source function name length
const char* thread_name; //!< Thread name
size_t thread_name_len; //!< Thread name length
int64_t timestamp_ns; //!< Timestamp in nanoseconds since epoch
uint32_t line; //!< Source line number
btck_LogLevel level; //!< Log level
btck_LogCategory category; //!< Log category
};
typedef void (*btck_LogCallback)(void* user_data, const btck_LogEntry* entry);
BITCOINKERNEL_API void btck_logging_set_min_level(btck_LogLevel level);
BITCOINKERNEL_API btck_LoggingConnection* BITCOINKERNEL_WARN_UNUSED_RESULT btck_logging_connection_create(
btck_LogCallback log_callback,
void* user_data,
btck_DestroyCallback user_data_destroy_callback) BITCOINKERNEL_ARG_NONNULL(1);
BITCOINKERNEL_API void btck_logging_connection_destroy(btck_LoggingConnection* logging_connection);