feat(logging): add Loggers registry (6/6)#737
Open
kamcheungting-db wants to merge 7 commits into
Open
Conversation
19003d8 to
51e997b
Compare
faed95d to
d0066d4
Compare
49a68c1 to
b68bd93
Compare
Member
|
@kamcheungting-db can you please rebase your PR? |
b68bd93 to
0367553
Compare
Fourth block: the application-facing macros, the only part most callers touch.
- ICEBERG_LOG_{TRACE,DEBUG,INFO,WARN,ERROR,CRITICAL,FATAL} plus the generic
ICEBERG_LOG(level, ...), ICEBERG_LOG_TO(logger, level, ...) for an explicit
logger, and ICEBERG_LOG_RUNTIME_FMT for a runtime (non-literal) format string.
- ICEBERG_LOG_ACTIVE_LEVEL is a compile-time severity floor: statements below it
are removed entirely via `if constexpr` (no format call site, no source
location emitted). ICEBERG_LOG_FATAL is never gated by the floor -- its abort
is always compiled in; it emits, best-effort Flush()es the same logger it
emitted to, then std::abort().
- Filtering is decided solely by Logger::ShouldLog(); formatting is wrapped in
try/catch so logging never throws (a format failure routes to EmitFormatError).
- Bare Java-style aliases (LOG_INFO, ...) are opt-in via ICEBERG_LOG_SHORT_MACROS
to avoid polluting consumers / colliding with glog/abseil.
Header-only addition to logger.h. macros_test covers injection, the
guard-before-format short-circuit, never-throws, and FATAL aborts;
macros_active_level_test verifies compile-time stripping in a kOff translation unit.
Co-authored-by: Isaac
Note in FormatAndEmit and the ICEBERG_INTERNAL_LOG comment that the only throws are std::format_error/std::bad_alloc (same recovery), and that catching std::exception rather than (...) lets a non-std unwind such as abi::__forced_unwind (thread cancellation) propagate. Co-authored-by: Isaac
… docs, FATAL test) - Revert the 6 catch sites to catch(...) so the noexcept "logging never throws" guarantee holds even when a user-defined std::formatter throws a non-std type (catch(const std::exception&) would let it reach std::terminate). - Apply /Zc:preprocessor to the iceberg library targets PUBLICly on MSVC, not only to tests: logger.h is public and uses __VA_OPT__, so the library build and consumers need the conforming preprocessor too. - Soften the compile-time-floor doc: `if constexpr` discards the emit but the statement must still be well-formed (bad format string is still a compile error). - Add the missing opening '[' to the logger.h example output lines to match CerrLogger's [file:line] layout. - Add MacrosDeathTest.FatalRoutesThroughScopedLogger locking in that ICEBERG_LOG_FATAL routes through the active ScopedLogger (GetCurrentLogger). Co-authored-by: Isaac
0367553 to
3e34c76
Compare
Adopt the structure from the apache#824 prototype (keeping our if constexpr gating): - logger.h is now the C++ API only; ICEBERG_LOG_* macros move to log_macros.h, and the bare LOG_* aliases move behind an opt-in short_log_macros.h (replacing the ICEBERG_LOG_SHORT_MACROS define). - Dedup the five macro bodies onto shared internal helpers (EmitIfEnabled + LogToCurrent / LogToCurrentRuntime / LogToExplicitRuntime / LogFatal) that take a lazy [&]()->std::string message thunk invoked only past ShouldLog, so disabled logs still don't evaluate their args. Keeps catch(...), the GetCurrentLogger() fatal path, and if constexpr compile-time floor. - VFormat moves to log_macros.h (only ICEBERG_LOG_RUNTIME_FMT uses it). Co-authored-by: Isaac
4035f88 to
8d4515e
Compare
…review ⑤) Address the extensibility comment: let an embedder (JNI, Python host, crash reporter) run a hook on the fatal path before std::abort() to flush resources or print a stack trace. - Add FatalHandler = std::function<void(const std::source_location&, std::string_view)> plus thread-safe SetFatalHandler/GetFatalHandler (leaked, teardown-safe slot in logger.cc). - Wire it into LogFatal: format the message once, emit-if-enabled + flush, run the handler (message passed even when the record is filtered out), then abort. A throwing handler cannot prevent the abort. - Death tests: handler runs with the formatted message, receives the call-site location, and still fires when the record is suppressed. Co-authored-by: Isaac
Fifth block: the default production backend and the build option that selects it. - SpdLogger wraps spdlog::logger (kCritical/kFatal -> spdlog critical, others 1:1), forwarding the pre-formatted message and source location. Synchronous only in v1 (spdlog's source_loc is a non-owning const char*, unsafe with async sinks). It lives in logging/internal/, is gated by #ifdef ICEBERG_HAS_SPDLOG, and is NOT installed -- consumers obtain it via the default logger or the registry, never by including spdlog headers. - New ICEBERG_SPDLOG CMake option (default ON). config.h is ALWAYS generated (only ICEBERG_HAS_SPDLOG's definedness varies) so logger.cc compiles in both configurations; MakeDefaultLogger() prefers SpdLogger when compiled in, else CerrLogger. - Critically, ICEBERG_SPDLOG=OFF now UNWIRES the previously-unconditional spdlog link (interface-lib lists + resolve_spdlog_dependency), not just the new source -- so an OFF build has no spdlog dependency at all. spdlog_logger_test (compiled only on the ON path) covers the level mapping including fatal->critical and source-location forwarding. Co-authored-by: Isaac
Final block: configuration-driven backend selection, mirroring MetricsReporters. - Loggers::Register(type, factory) registers a named backend; Loggers::Load(props) builds one, selecting the type from the "logger-impl" property key. - Built-in factories: "noop", "cerr", and (only when built with ICEBERG_SPDLOG) "spdlog". With no logger-impl set, the default is spdlog when compiled in, else cerr -- logs by default, an intentional divergence from the metrics registry's noop default. - Loggers::LoadAndSetDefault(props) loads a logger and installs it as the process default. This completes the system end to end: levels -> Logger interface + default logger -> CerrLogger/SpdLogger backends -> macros -> configuration-driven selection. loggers_test covers load default/noop/cerr, unknown-type errors, empty-factory rejection, custom Register, and LoadAndSetDefault. Adds logging_end_to_end_test, which drives the public surface as an application does -- now that every layer is present: configure a backend via the registry, install it as the default, log through the LOG_* macros, and observe real output. Covers registry -> default-slot -> macro -> backend -> std::cerr output, level filtering through the full macro path, the compiled-backend identity of the default (spdlog when ON, cerr when OFF), the "spdlog" factory by name, and a macro statement reaching a real spdlog sink. Co-authored-by: Isaac
8d4515e to
aaa1ebf
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part 6 of the logging stack (builds on #726). Completes the system with configuration-driven backend selection, mirroring
MetricsReporters.What's here
Loggers::Register(type, factory)registers a named backend;Loggers::Load(properties)builds one, choosing the type from thelogger-implproperty.noop,cerr, and (when built with spdlog)spdlog. With nologger-implset, the default is spdlog when compiled in, else cerr — i.e. logs by default.Loggers::LoadAndSetDefault(properties)builds a logger and installs it as the process default.End-to-end tests —
logging_end_to_end_testdrives the public surface the way an app does: configure a backend + level via properties, install it, log through the macros, and check the real output. Also covers the compiled-in default backend and a macro reaching a real spdlog sink. clang/libc++, spdlog ON and OFF.This pull request and its description were written by Isaac.