Skip to content

feat(logging): add Loggers registry (6/6)#737

Open
kamcheungting-db wants to merge 3 commits into
apache:mainfrom
kamcheungting-db:logging-block6-registry
Open

feat(logging): add Loggers registry (6/6)#737
kamcheungting-db wants to merge 3 commits into
apache:mainfrom
kamcheungting-db:logging-block6-registry

Conversation

@kamcheungting-db

@kamcheungting-db kamcheungting-db commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

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 the logger-impl property.
  • Built-ins: noop, cerr, and (when built with spdlog) spdlog. With no logger-impl set, 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 testslogging_end_to_end_test drives 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.

@kamcheungting-db kamcheungting-db force-pushed the logging-block6-registry branch 15 times, most recently from 19003d8 to 51e997b Compare June 22, 2026 10:24
@kamcheungting-db kamcheungting-db force-pushed the logging-block6-registry branch 5 times, most recently from 5246e60 to faed95d Compare June 24, 2026 17:58
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
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
@kamcheungting-db kamcheungting-db force-pushed the logging-block6-registry branch from faed95d to d0066d4 Compare June 24, 2026 18:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant