Skip to content

Implement JSON Logger configuration#74

Open
JavaSaBr wants to merge 2 commits into
developfrom
improve-logger-part-4
Open

Implement JSON Logger configuration#74
JavaSaBr wants to merge 2 commits into
developfrom
improve-logger-part-4

Conversation

@JavaSaBr

@JavaSaBr JavaSaBr commented Jun 21, 2026

Copy link
Copy Markdown
Owner

Overview

This branch adds JSON-based logger configuration support through a new rlib-logger-impl-json module integrated into the existing loader pipeline. It introduces a structured JSON config model for loggers, renders, and consumers (including custom implementations loaded reflectively), and wires custom consumers to use configured renders. The branch also normalizes root-logger naming in API/impl layers and updates logger factory naming from “default” to “root”.

Changes Summary

1. New feature: JSON logger configuration module

  • Added new Gradle module :rlib-logger-impl-json and included it in settings.gradle.
  • Added Jackson dependencies in gradle/libs.versions.toml and module dependencies in rlib-logger-impl-json/build.gradle.
  • Added JsonLoggerConfigLoader:
    • Resource resolution order: rlib.logger-test.json -> rlib.logger.json
    • Parses DTO with ObjectMapper
    • Creates render and consumer registries by name
    • Registers logger levels and level-bound consumers into LoggerConfigBuilder
  • Added DTO model JsonLoggerConfigDto with nested records/enums:
    • RenderType: SIMPLE, PATTERN, CUSTOM
    • ConsumerType: CONSOLE, CUSTOM
    • Defensive null normalization for lists/maps/sets and basic validation for render entries

2. Loader SPI integration

  • Added JSON provider JsonLoggerConfigLoadersProvider and service registration:
    • rlib-logger-impl-json/src/main/resources/META-INF/services/javasabr.rlib.logger.impl.config.loader.spi.LoggerConfigLoadersProvider
  • Updated LoggerConfigResolver to load providers from javasabr.rlib.logger.impl.config.loader.spi.LoggerConfigLoadersProvider.
  • LoggerConfigLoadersProvider interface moved to ...config.loader.spi package.

3. Custom render/consumer extensibility updates

  • Added abstract extension base CustomLogMessageRender.
  • Updated CustomLogMessageConsumer constructor to accept both:
    • LogMessageRender render
    • Map<String, Object> args
  • Updated JSON loader to instantiate custom consumers via (LogMessageRender, Map<String, Object>), so configured render is now available to custom consumers.
  • Extended PatternLogMessageRender with argument-based constructor:
    • pattern (required, string)
    • initBufferSize (optional, int or parsable string, default 256)

4. API/refactoring changes around root logger naming

  • LoggerFactory now defines ROOT_LOGGER_NAME = "ROOT".
  • LoggerFactory#getDefault() was renamed to getRootLogger(); implementations updated:
    • DefaultLoggerFactory
    • NoOpsLoggerFactory
    • Slf4jLoggerFactory
  • LoggerManager#getDefaultLogger() now delegates to getRootLogger().
  • Root logger constant usage in impl/config code was centralized to LoggerFactory.ROOT_LOGGER_NAME (replacing impl-local constant usage).

5. Tests and fixtures

  • Added JsonLoggerConfigLoaderTest with custom test render/consumer classes and assertions for:
    • logger-level filtering across multiple loggers
    • root logger behavior
    • custom render output passing through custom consumer
  • Added JSON fixture rlib.logger-test.json covering:
    • pattern + custom renders
    • console + custom consumers
    • per-logger level/consumer bindings

6. Runtime flow diagram

flowchart TD
  A["Logger config resolver starts"] --> B["Register default and properties loaders"]
  B --> C["Load loaders from SPI providers"]
  C --> D["Sort loaders by order"]
  D --> E["Try loaders in order"]
  E -->|json found| F["Parse JSON config DTO"]
  F --> G["Build renders and consumers"]
  G --> H["Build logger config"]
  E -->|none found| I["Fallback default config"]
Loading

7. Usage samples

{
  "renders": [
    { "name": "consolePattern", "type": "PATTERN", "args": { "pattern": "%level %msg" } }
  ],
  "consumers": [
    { "name": "console", "type": "CONSOLE", "render": "consolePattern" }
  ],
  "loggers": [
    { "name": "ROOT", "level": "INFO", "consumers": ["console"] }
  ]
}
public final class MyConsumer extends CustomLogMessageConsumer {

  public MyConsumer(LogMessageRender render, Map<String, Object> args) {
    super(render, args);
  }
}

@JavaSaBr JavaSaBr self-assigned this Jun 21, 2026
Copilot AI review requested due to automatic review settings June 21, 2026 11:46
@github-actions

Copy link
Copy Markdown
Overall Project 57.45% -0.17% 🍏
Files changed 18.99%

File Coverage
DefaultLoggerConfigLoader.java 100% 🍏
DefaultLoggerConfig.java 99.02% 🍏
PropertyLoggerConfigLoader.java 97.3% 🍏
DefaultLoggerFactory.java 84.62% -15.38%
LoggerConfigResolver.java 76.79% 🍏
DefaultLoggerService.java 75.09% 🍏
NoOpsLoggerFactory.java 70% 🍏
LoggerManager.java 68.27% -2.88%
Slf4jLoggerFactory.java 65.45% 🍏
PatternLogMessageRender.java 16.33% -48.98%
CustomLogMessageRender.java 0%
CustomLogMessageConsumer.java 0%

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a JSON-based logger configuration loader (via Java ServiceLoader) and updates the logger API/implementations to consistently refer to the “root logger” (instead of “default logger”), along with related config/constant updates across the logger modules.

Changes:

  • Added new :rlib-logger-impl-json module that loads rlib.logger.json / rlib.logger-test.json and registers itself via SPI.
  • Introduced/updated SPI package for providing additional LoggerConfigLoader implementations discovered via ServiceLoader.
  • Renamed LoggerFactory#getDefault() to getRootLogger() and propagated the change across implementations and tests; centralized ROOT logger name under LoggerFactory.

Reviewed changes

Copilot reviewed 27 out of 27 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
settings.gradle Registers new JSON logger module and repositions SLF4J impl module include.
rlib-logger-slf4j/src/main/java/javasabr/rlib/logger/slf4j/Slf4jLoggerFactory.java Renames factory method to getRootLogger().
rlib-logger-impl/src/test/java/javasabr/rlib/logger/impl/DefaultLoggerTest.java Updates root logger name constant usage in tests.
rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerService.java Exposes/stores a root logger and uses LoggerFactory.ROOT_LOGGER_NAME.
rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/DefaultLoggerFactory.java Renames factory method to getRootLogger().
rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/pattern/PatternLogMessageRender.java Adds args-map constructor and constants for buffer sizing/pattern extraction.
rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/render/impl/CustomLogMessageRender.java Introduces base class for custom renders with args-based ctor.
rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/spi/package-info.java Marks SPI package as @NullMarked.
rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/spi/LoggerConfigLoadersProvider.java Moves provider interface into loader.spi package.
rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/LoggerConfigResolver.java Loads additional config loaders via ServiceLoader SPI.
rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/PropertyLoggerConfigLoader.java Switches ROOT name constant source to LoggerFactory.
rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/loader/impl/DefaultLoggerConfigLoader.java Switches ROOT name constant source to LoggerFactory.
rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/impl/DefaultLoggerConfig.java Switches ROOT name constant source to LoggerFactory when resolving levels/keys.
rlib-logger-impl/src/main/java/javasabr/rlib/logger/impl/config/consumer/impl/CustomLogMessageConsumer.java Introduces base class for custom consumers with args-based ctor.
rlib-logger-impl-json/src/test/resources/rlib.logger-test.json Adds JSON test configuration fixture.
rlib-logger-impl-json/src/test/java/javasabr/rlib/logger/impl/config/loader/json/JsonLoggerConfigLoaderTest.java Adds coverage for JSON loader end-to-end behavior with custom consumer/render.
rlib-logger-impl-json/src/main/resources/META-INF/services/javasabr.rlib.logger.impl.config.loader.spi.LoggerConfigLoadersProvider Registers JSON loaders provider for ServiceLoader.
rlib-logger-impl-json/src/main/java/javasabr/rlib/logger/impl/config/loader/json/package-info.java Marks JSON loader package as @NullMarked.
rlib-logger-impl-json/src/main/java/javasabr/rlib/logger/impl/config/loader/json/JsonLoggerConfigLoadersProvider.java Supplies the JSON loader via SPI.
rlib-logger-impl-json/src/main/java/javasabr/rlib/logger/impl/config/loader/json/JsonLoggerConfigLoader.java Implements JSON parsing + config building + reflection for custom components.
rlib-logger-impl-json/src/main/java/javasabr/rlib/logger/impl/config/loader/json/dto/package-info.java Marks DTO package as @NullMarked.
rlib-logger-impl-json/src/main/java/javasabr/rlib/logger/impl/config/loader/json/dto/JsonLoggerConfigDto.java Adds DTO model for JSON config (renders/consumers/loggers).
rlib-logger-impl-json/build.gradle Declares new module plugins and Jackson dependencies.
rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerManager.java Routes “default logger” accessor to getRootLogger().
rlib-logger-api/src/main/java/javasabr/rlib/logger/api/LoggerFactory.java Adds ROOT_LOGGER_NAME constant and renames getDefault() to getRootLogger().
rlib-logger-api/src/main/java/javasabr/rlib/logger/api/impl/NoOpsLoggerFactory.java Renames factory method to getRootLogger().
gradle/libs.versions.toml Adds Jackson version and library coordinates to the version catalog.

import javasabr.rlib.logger.impl.config.render.impl.pattern.PatternLogMessageRender;
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
import tools.jackson.databind.ObjectMapper;
Comment on lines +128 to +130
if (StringUtils.isBlank(className)) {
throw new IllegalArgumentException("'class'' is required for custom render");
}
Comment on lines +135 to +137
var targetClass = (Class<? extends CustomLogMessageRender>) classLoader.loadClass(className);
Constructor<? extends CustomLogMessageRender> constructor = targetClass.getDeclaredConstructor(Map.class);
return constructor.newInstance(renderDto.args());
Comment on lines +158 to +160
if (StringUtils.isBlank(className)) {
throw new IllegalArgumentException("'class'' is required for custom consumer");
}
Comment on lines +165 to +168
var targetClass = (Class<? extends CustomLogMessageConsumer>) classLoader.loadClass(className);
Constructor<? extends CustomLogMessageConsumer> constructor = targetClass
.getDeclaredConstructor(LogMessageRender.class, Map.class);
return constructor.newInstance(render, consumerDto.args());
Comment on lines +27 to +29
public LoggerDto {
consumerNames = consumerNames == null ? Set.of() : Set.copyOf(consumerNames);
}
Comment on lines +61 to +63
public ConsumerDto {
args = args == null ? Map.of() : Map.copyOf(args);
}
var loader = new JsonLoggerConfigLoader();
MutableArray<String> receivedMessages = CONSUMED_MESSAGES.get();

//when:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants