Module: AIA::LoggerManager

Defined in:
lib/aia/logger.rb

Constant Summary collapse

LOG_LEVELS =

Log level mapping from config strings to Lumberjack severity constants

{
  'debug' => Lumberjack::Severity::DEBUG,
  'info'  => Lumberjack::Severity::INFO,
  'warn'  => Lumberjack::Severity::WARN,
  'error' => Lumberjack::Severity::ERROR,
  'fatal' => Lumberjack::Severity::FATAL
}.freeze

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.test_modeObject

Track whether we’re in test mode



47
48
49
# File 'lib/aia/logger.rb', line 47

def test_mode
  @test_mode
end

Class Method Details

.aia_loggerLumberjack::Logger

Get or create the AIA application logger

Returns:

  • (Lumberjack::Logger)

    The AIA logger instance



52
53
54
# File 'lib/aia/logger.rb', line 52

def aia_logger
  @aia_logger ||= create_logger(:aia)
end

.clear_test_logs!Object

Clear all test log entries (call between tests)



195
196
197
198
199
200
201
# File 'lib/aia/logger.rb', line 195

def clear_test_logs!
  return unless test_mode?

  [@aia_logger, @llm_logger, @mcp_logger].each do |logger|
    logger&.device&.clear if logger&.device.respond_to?(:clear)
  end
end

.configure_llm_loggerObject

Configure RubyLLM’s logger RubyLLM.logger is a memoized method that uses config.logger or creates a new one. We need to:

  1. Set config.logger to our logger

  2. Set config.log_file in case the logger gets recreated

  3. Reset the memoized @logger so next call uses our config



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/aia/logger.rb', line 76

def configure_llm_logger
  return unless defined?(RubyLLM)

  logger = llm_logger

  # Set our logger on the RubyLLM config object
  if RubyLLM.config.respond_to?(:logger=)
    RubyLLM.config.logger = logger
  end

  # Also set log_file and log_level in case the logger gets recreated
  if RubyLLM.config.respond_to?(:log_file=)
    file = effective_log_file(logger_config_for(:llm))
    RubyLLM.config.log_file = resolve_log_file_io(file)
  end

  if RubyLLM.config.respond_to?(:log_level=)
    level = effective_log_level(logger_config_for(:llm))
    RubyLLM.config.log_level = LOG_LEVELS.fetch(level, Lumberjack::Severity::WARN)
  end

  # Reset the memoized @logger on RubyLLM module so next call uses our config
  # RubyLLM.logger does: @logger ||= config.logger || Logger.new(...)
  RubyLLM.instance_variable_set(:@logger, nil) if RubyLLM.instance_variable_defined?(:@logger)
end

.configure_mcp_loggerObject

Configure RubyLLM::MCP’s logger RubyLLM::MCP.config has attr_writer :logger and a memoized getter. We need to set both the config.logger and reset any memoization.



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/aia/logger.rb', line 105

def configure_mcp_logger
  return unless defined?(RubyLLM::MCP)

  logger = mcp_logger

  # First reset the memoized @logger so our settings take effect
  # RubyLLM::MCP.config.logger does: @logger ||= Logger.new(...)
  config = RubyLLM::MCP.config
  config.instance_variable_set(:@logger, nil) if config.instance_variable_defined?(:@logger)

  # Set our logger on the MCP config object
  # RubyLLM::MCP.config has attr_writer :logger (which sets @logger directly)
  if config.respond_to?(:logger=)
    config.logger = logger
  end

  # Also set log_file and log_level in case the logger gets recreated
  if config.respond_to?(:log_file=)
    file = effective_log_file(logger_config_for(:mcp))
    config.log_file = resolve_log_file_io(file)
  end

  if config.respond_to?(:log_level=)
    level = effective_log_level(logger_config_for(:mcp))
    config.log_level = LOG_LEVELS.fetch(level, Lumberjack::Severity::WARN)
  end
end

.last_test_entry(system = :aia) ⇒ Lumberjack::LogEntry?

Get the last entry from a specific test logger

Parameters:

  • system (Symbol) (defaults to: :aia)

    The logger to get entry from (:aia, :llm, :mcp)

Returns:

  • (Lumberjack::LogEntry, nil)

    The last log entry or nil



224
225
226
# File 'lib/aia/logger.rb', line 224

def last_test_entry(system = :aia)
  test_entries(system).last
end

.llm_log_level_symbolSymbol

Get the log level symbol for RubyLLM configuration

Returns:

  • (Symbol)

    The log level as a symbol (e.g., :warn, :debug)



149
150
151
152
153
# File 'lib/aia/logger.rb', line 149

def llm_log_level_symbol
  config = logger_config_for(:llm)
  level = effective_log_level(config)
  level.to_sym
end

.llm_loggerLumberjack::Logger

Get or create the RubyLLM logger

Returns:

  • (Lumberjack::Logger)

    The LLM logger instance



59
60
61
# File 'lib/aia/logger.rb', line 59

def llm_logger
  @llm_logger ||= create_logger(:llm)
end

.mcp_loggerLumberjack::Logger

Get or create the RubyLLM::MCP logger

Returns:

  • (Lumberjack::Logger)

    The MCP logger instance



66
67
68
# File 'lib/aia/logger.rb', line 66

def mcp_logger
  @mcp_logger ||= create_logger(:mcp)
end

.reset!Object

Reset all cached loggers (useful for testing or reconfiguration)



156
157
158
159
160
161
# File 'lib/aia/logger.rb', line 156

def reset!
  @aia_logger = nil
  @llm_logger = nil
  @mcp_logger = nil
  @test_mode = false
end

.resolve_log_file_io(file) ⇒ Object

Convert log file specification to IO object or file path RubyLLM::MCP expects an IO object or file path for log_file config



135
136
137
138
139
140
141
142
143
144
# File 'lib/aia/logger.rb', line 135

def resolve_log_file_io(file)
  case file.to_s.upcase
  when 'STDOUT'
    $stdout
  when 'STDERR'
    $stderr
  else
    File.expand_path(file)
  end
end

.test_entries(system = :aia) ⇒ Array<Lumberjack::LogEntry>

Get all entries from a specific test logger

Parameters:

  • system (Symbol) (defaults to: :aia)

    The logger to get entries from (:aia, :llm, :mcp)

Returns:

  • (Array<Lumberjack::LogEntry>)

    Array of log entries



207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/aia/logger.rb', line 207

def test_entries(system = :aia)
  logger = case system
           when :aia then aia_logger
           when :llm then llm_logger
           when :mcp then mcp_logger
           else raise ArgumentError, "Unknown logger: #{system}"
           end

  return [] unless logger&.device.respond_to?(:entries)

  logger.device.entries
end

.test_mode!(level: :debug) ⇒ Object

Enable test mode - all loggers will use Lumberjack’s :test device which captures entries in memory for inspection and assertions.

Parameters:

  • level (Symbol, String) (defaults to: :debug)

    Log level for test loggers (default: :debug)



173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/aia/logger.rb', line 173

def test_mode!(level: :debug)
  reset!
  @test_mode = true
  @test_level = LOG_LEVELS.fetch(level.to_s, Lumberjack::Severity::DEBUG)

  # Pre-create loggers with test devices
  @aia_logger = create_test_logger(:aia)
  @llm_logger = create_test_logger(:llm)
  @mcp_logger = create_test_logger(:mcp)

  # Surface logging errors in tests instead of swallowing them
  Lumberjack.raise_logger_errors = true
end

.test_mode?Boolean

Check if test mode is enabled

Returns:

  • (Boolean)

    true if in test mode



190
191
192
# File 'lib/aia/logger.rb', line 190

def test_mode?
  @test_mode == true
end