Skip to content

Conversation

@jkebinger
Copy link
Collaborator

Summary

This PR adds comprehensive dynamic log level management functionality to the Reforge SDK, including core support and integrations for both Logback and Log4j2 logging frameworks.

Core Features

LoggerClient

  • New LoggerClient interface for retrieving dynamic log levels
  • LogLevel enum wrapping Prefab.LogLevel with efficient switch-based conversion
  • Configuration via Options.loggerKey (default: "log-levels.default")
  • Evaluates LOG_LEVEL_V2 configs with context: {"reforge-sdk-logging": {"lang": "java", "logger-path": "<loggerName>"}}
  • Returns DEBUG as sensible default when no config found
  • 11 comprehensive tests covering all scenarios

Usage

Sdk sdk = new Sdk(new Options());
LogLevel level = sdk.loggerClient().getLogLevel("com.example.MyClass");

Logback Integration (sdk-logback module)

Features

  • TurboFilter-based integration works globally at framework level
  • Compatible with Logback 1.2.x through 1.5.x
  • Works with existing logback.xml - no configuration changes needed
  • Universal appender support (console, file, rolling, syslog, async, etc.)
  • Filters before message formatting for optimal performance

Installation

Sdk sdk = new Sdk(new Options());
ReforgeLogbackTurboFilter.install(sdk.loggerClient());

Log4j2 Integration (sdk-log4j2 module)

Features

  • AbstractFilter-based integration at LoggerContext level
  • Compatible with Log4j2 2.x versions
  • Works with existing log4j2.xml - no configuration changes needed
  • Universal appender support
  • Native FATAL level support
  • Note: Filter removed on dynamic reconfiguration (must be reinstalled)

Installation

Sdk sdk = new Sdk(new Options());
ReforgeLog4j2Filter.install(sdk.loggerClient());

Technical Details

Performance Optimizations

  • Efficient switch-based level mapping (~1-2 CPU cycles vs Map's ~10-20 cycles)
  • Zero initialization overhead
  • Filtering before expensive message construction
  • Recursion protection via ThreadLocal

Robust Error Handling

  • Type checking before casting logging contexts
  • Fail-fast with IllegalStateException if wrong logging framework detected
  • Clear, actionable error messages with diagnostic information
  • Consistent behavior across both integrations

Maximum Compatibility

  • Logging frameworks and SLF4J marked as provided scope
  • Uses only stable APIs across version ranges
  • Honest compatibility documentation (no false testing claims)

Documentation

Each module includes comprehensive README with:

  • Installation instructions
  • Compatibility matrices
  • Usage examples (including Spring Boot)
  • FAQ sections
  • Troubleshooting guides

Test Plan

  • Core SDK tests pass (11 new tests for LoggerClient)
  • Logback module compiles successfully
  • Log4j2 module compiles successfully
  • All modules properly formatted and sorted
  • Error handling verified with type checking

Breaking Changes

None - this is all new functionality.

🤖 Generated with Claude Code

jkebinger and others added 5 commits October 22, 2025 16:21
This commit adds dynamic log level management functionality to the SDK:

- LogLevel enum: Java wrapper around Prefab.LogLevel with efficient
  switch-based conversion (TRACE, DEBUG, INFO, WARN, ERROR, FATAL)

- LoggerClient interface: Provides getLogLevel(String loggerName) method
  for retrieving configured log levels

- LoggerClientImpl: Implementation that evaluates log level configs with
  context containing logger path and language information

- Configuration:
  * Default config key: "log-levels.default"
  * Config type: LOG_LEVEL_V2
  * Evaluation context: {"reforge-sdk-logging": {"lang": "java",
    "logger-path": "<loggerName>"}}
  * Returns DEBUG when no config found

- Options: Added loggerKey field with default value "log-levels.default"

- Sdk: Added loggerClient() method following same lazy initialization
  pattern as other clients

- Tests: Comprehensive test suite with 11 tests covering all scenarios
  including exception handling, context validation, and edge cases

This provides the foundation for logging framework integrations to
dynamically control log levels via Reforge configuration.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit adds a new maven module (sdk-logback) that provides seamless
Logback integration for dynamic log level management.

Key Features:
- TurboFilter-based integration: Works globally at framework level without
  needing to traverse or configure individual loggers
- Maximum compatibility: Works with Logback 1.2.x through 1.5.x
- Zero configuration: Works with existing logback.xml without modifications
- Universal appender support: Works with all appenders (console, file,
  rolling, syslog, async, custom)
- Performance optimized: Filters before message formatting

Implementation:
- BaseTurboFilter: Abstract filter with recursion protection and exception
  handling for safe operation
- ReforgeLogbackTurboFilter: Main filter that retrieves log levels from
  LoggerClient and applies filtering decisions
- LogbackLevelMapper: Bidirectional mapping between Reforge LogLevel and
  Logback Level enums
- LogbackUtils: Utility to install the filter into Logback's LoggerContext

Dependencies:
- Logback and SLF4J use 'provided' scope, ensuring maximum compatibility
  by using the customer's existing versions rather than forcing specific
  versions
- Only stable APIs used that haven't changed across Logback versions

Usage:
  Sdk sdk = new Sdk(new Options());
  ReforgeLogbackTurboFilter.install(sdk.loggerClient());

Documentation:
- Comprehensive README with examples, FAQ, and troubleshooting
- Spring Boot integration examples
- Compatibility matrix for Logback 1.2.x - 1.5.x

Parent POM Changes:
- Added logback module to reactor build
- Added logback-classic and logback-core to dependencyManagement

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Changes to make Logback integration more efficient and robust:

1. Level Mapping Optimization:
   - Replace Map-based level mapping with switch statement
   - LogbackLevelMapper.toLogbackLevel() uses switch for better performance
   - Switch: ~1-2 CPU cycles vs Map: ~10-20 CPU cycles
   - Zero initialization overhead, better CPU cache utilization
   - Remove bidirectional mapping (only need Reforge→Logback direction)

2. Consistent Error Handling:
   - LogbackUtils now throws IllegalStateException instead of just logging
   - Fail-fast behavior prevents silent failures
   - Clear error messages with diagnostic information
   - Consistent with Log4j2 integration behavior
   - Added @throws javadoc to ReforgeLogbackTurboFilter.install()

3. Documentation Updates:
   - Clarify SLF4J version compatibility requirements
   - Note that Logback 1.3+ requires SLF4J 2.0+
   - Document that dependencies are provided scope

These changes ensure the integration fails immediately with helpful
errors rather than silently not working, making debugging much easier
for developers.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit adds a new maven module (sdk-log4j2) that provides
Log4j2 integration for dynamic log level management.

Key Features:
- AbstractFilter-based integration at LoggerContext level
- Maximum compatibility: Works with Log4j2 2.x versions
- No configuration changes needed: Works with existing log4j2.xml
- Universal appender support: Console, file, rolling, syslog, async, etc.
- Performance optimized: Filters before message formatting

Implementation:
- ReforgeLog4j2Filter: Main filter that retrieves log levels from
  LoggerClient and applies filtering decisions
- Log4jLevelMapper: Efficient switch-based mapping between Reforge
  LogLevel and Log4j2 Level enums (including native FATAL support)
- Type checking: install() method validates Log4j2 Core is being used
  and throws IllegalStateException with helpful error if not

Dependencies:
- Log4j2 and SLF4J use 'provided' scope for maximum compatibility
- We compile against Log4j2 2.19.0 but APIs are stable across 2.x
- Works with both SLF4J 1.7.x and 2.0.x

Usage:
  Sdk sdk = new Sdk(new Options());
  ReforgeLog4j2Filter.install(sdk.loggerClient());

Note: Unlike Logback's persistent TurboFilter, Log4j2 filters are
removed on dynamic reconfiguration and must be reinstalled.

Documentation:
- Comprehensive README with examples, FAQ, and troubleshooting
- Spring Boot integration examples
- Reconfiguration handling guidance
- Comparison with Logback integration

Parent POM Changes:
- Added log4j2 module to reactor build
- Added log4j-api and log4j-core to dependencyManagement (version 2.19.0)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add logback-core test dependency with matching version range [1.4.12,) to fix NoClassDefFoundError in tests
- Bump version from 1.0.3 to 1.1.0 across all modules
- Ensures logback-classic and logback-core versions stay in sync during test execution

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

@jdwyah jdwyah left a comment

Choose a reason for hiding this comment

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

thanks

@jkebinger jkebinger merged commit 54c9b0c into main Oct 31, 2025
1 check passed
@jkebinger jkebinger deleted the feature/log-level-support branch October 31, 2025 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants