Skip to content

Conversation

@jkebinger
Copy link
Collaborator

@jkebinger jkebinger commented Oct 23, 2025

Summary

This PR restores dynamic log level functionality from the predecessor project (prefab-cloud-ruby) with a modernized approach using LOG_LEVEL_V2 config evaluation.

Changes

New Files

  • lib/reforge/log_level.rb - Public LogLevel enum (:trace, :debug, :info, :warn, :error, :fatal)
  • lib/reforge/log_level_client.rb - Client for managing dynamic log levels with SemanticLogger and stdlib Logger support
  • test/test_log_level_client.rb - Comprehensive test coverage (12 tests, 35 assertions)

Modified Files

  • lib/reforge/client.rb - Added log_level_client accessor
  • lib/reforge/options.rb - Added logger_key option (defaults to 'log-levels.default')
  • lib/sdk-reforge.rb - Added requires for new log level modules, made semantic_logger optional
  • Gemfile - Moved semantic_logger from runtime to development dependency
  • sdk-reforge.gemspec - Updated dependencies to make semantic_logger optional
  • README.md - Added documentation for both SemanticLogger and stdlib Logger integration
  • lib/prefab_pb.rb - Protobuf update (from previous commit)

Key Features

1. LogLevel Enum

Public API for log levels that abstracts away the protobuf implementation:

Reforge::LogLevel::TRACE  # :trace
Reforge::LogLevel::DEBUG  # :debug
Reforge::LogLevel::INFO   # :info
Reforge::LogLevel::WARN   # :warn
Reforge::LogLevel::ERROR  # :error
Reforge::LogLevel::FATAL  # :fatal

2. LogLevelClient Methods

  • get_log_level(logger_name) - Evaluates LOG_LEVEL_V2 config and returns the appropriate log level
  • should_log?(severity, path) - Compares numeric severity against configured level
  • semantic_filter(log) - SemanticLogger integration for automatic filtering (optional)
  • stdlib_formatter(logger_name) - Ruby stdlib Logger integration via custom formatter

3. Context-Based Evaluation

Log levels are evaluated with the following context:

{
  "reforge-sdk-logging" => {
    "lang" => "ruby",
    "logger-path" => logger_name  # e.g., "my_app.my_class"
  }
}

4. Flexible Logger Integration

SemanticLogger (optional dependency):

client = Reforge::Client.new
SemanticLogger.add_appender(
  io: $stdout,
  formatter: :json,
  filter: client.log_level_client.method(:semantic_filter)
)

Ruby stdlib Logger:

client = Reforge::Client.new
logger = Logger.new($stdout)
logger.formatter = client.log_level_client.stdlib_formatter('MyApp')

5. Optional Dependencies

  • semantic_logger is now a development dependency, not required at runtime
  • The SDK gracefully handles missing SemanticLogger with appropriate warnings
  • Customers can integrate with their preferred logging framework

Key Differences from Predecessor

Unlike the predecessor implementation that walked up a tree of logger names (e.g., log-level.my_app, log-level.my_app.my_class), this implementation:

  • Uses a single LOG_LEVEL_V2 config evaluation
  • Evaluates with Reforge context for targeted criteria
  • Provides a simpler, more explicit approach to log level management
  • Does not include log path aggregator (telemetry collection)
  • Supports multiple logging frameworks (SemanticLogger, stdlib Logger)
  • Reduces required dependencies for easier customer integration

Testing

All tests pass:

12 tests, 35 assertions, 0 failures, 0 errors, 0 skips

Test coverage includes:

  • Basic get_log_level functionality
  • Criteria-based evaluation (different log levels per logger path)
  • All log level types (trace, debug, info, warn, error, fatal)
  • Edge cases (nil key, empty key, wrong config type)
  • should_log? with different severities
  • Helper method conversions (class_path_name, underscore)
  • SemanticLogger level mapping

Configuration

In Reforge Launch, create a LOG_LEVEL_V2 config that can use criteria on the reforge-sdk-logging.logger-path property to set different log levels for different classes/modules.

🤖 Generated with Claude Code

jkebinger and others added 4 commits October 24, 2025 10:47
- Add Reforge::LogLevel enum for public API (:trace, :debug, :info, :warn, :error, :fatal)
- Add Reforge::LogLevelClient with getLogLevel, should_log?, and semantic_filter methods
- Add logger_key option to Reforge::Options (defaults to 'log-levels.default')
- Implement LOG_LEVEL_V2 config evaluation with "reforge-sdk-logging" context
- Add SemanticLogger integration support for dynamic log level filtering
- Add comprehensive test coverage (12 tests, 35 assertions)
- Update README with SemanticLogger integration documentation
- Include protobuf update from previous commit

This implementation differs from the predecessor by using a single LOG_LEVEL_V2
config evaluation rather than walking up a tree of logger names, providing a
simpler and more explicit approach to log level management.

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Move semantic_logger from runtime to development dependency
- Make semantic_logger optional with graceful fallback
- Add stdlib Logger integration via stdlib_formatter method
- Update README with stdlib Logger documentation
- Improves flexibility for customer integration by removing required dependencies

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

Co-Authored-By: Claude <noreply@anthropic.com>
@jkebinger jkebinger force-pushed the restore-log-level-functionality branch from b574608 to a3b4472 Compare October 24, 2025 15:48
jkebinger and others added 8 commits October 24, 2025 10:51
- Change InternalLogger to check if SemanticLogger is defined
- Fall back to stdlib Logger when SemanticLogger is not available
- Preserve all original functionality for SemanticLogger users
- Add support for trace, debug, info, warn, error, fatal methods
- Update gemspec to include internal_logger.rb

Fixes CI test failures where SemanticLogger is not installed.

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Add SemanticLogger check in common_helpers setup
- Make Reforge.log_filter gracefully handle missing SemanticLogger
- Make bootstrap_log_level return true when SemanticLogger unavailable
- Add warning message when log_filter used without SemanticLogger

Fixes test failures when SemanticLogger is not installed.

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Add level getter method that returns symbol for both SemanticLogger and stdlib Logger
- Make stdlib Logger output dynamically check for $logs (test environment)
- Ensures logs go to $logs during tests instead of only $stderr
- Fixes test failures where assert_logged expects logs in $logs

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Add custom formatter to stdlib Logger that mimics SemanticLogger format
- Remove SemanticLogger check from using_reforge_log_filter! to work with both logger types
- Track all InternalLogger instances regardless of logger type
- Change log_filter warning from WARN to DEBUG level (optional dependency shouldn't warn)
- Formatter outputs "ClassName -- Message" to match test expectations

Fixes CI test failures with unexpected log formats and warnings.

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Add @level_sym instance variable to track exact symbol level (including :trace)
- Fix level getter to return tracked symbol for stdlib Logger (preserves :trace vs :debug distinction)
- Make using_reforge_log_filter! less aggressive for stdlib Logger (stays at :warn instead of :trace)
- Initialize @level_sym properly in create_stdlib_logger
- Prevents debug/info log flooding in CI tests where SemanticLogger is not available

With SemanticLogger, semantic filter controls output at :trace level.
Without SemanticLogger, keeping level at :warn prevents excessive logs.

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Test now checks if SemanticLogger is defined
- With SemanticLogger: expects :trace level after using_reforge_log_filter!
- Without SemanticLogger: expects :warn level (to prevent log flooding)
- Matches the actual behavior of InternalLogger

Fixes CI test failure where SemanticLogger is not available.

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Move semantic_logger from development to test group in Gemfile
- stdlib Logger now always writes to $stderr (not $logs)
- Tests use $logs for SemanticLogger-filtered output only
- Restore using_reforge_log_filter! to always set :trace level
- Restore test to always expect :trace after calling using_reforge_log_filter!

This allows local testing with SemanticLogger while CI can test without it.
stdlib Logger logs go to $stderr and won't appear as unexpected in $logs.

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

Co-Authored-By: Claude <noreply@anthropic.com>
Release includes restored log level functionality with support for both SemanticLogger and stdlib Logger.

Changes:
- Restore log level functionality with LOG_LEVEL_V2 support
- Make SemanticLogger optional - SDK now works with or without it
- Add stdlib Logger support as alternative to SemanticLogger
- Add InternalLogger that automatically uses SemanticLogger or stdlib Logger
- Add logger_key initialization option for configuring dynamic log levels
- Add stdlib_formatter method for stdlib Logger integration

🤖 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 87bd15d into main Oct 31, 2025
3 checks passed
@jkebinger jkebinger deleted the restore-log-level-functionality branch October 31, 2025 18:35
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