Class: Foam::Otel::LoggerBridge

Inherits:
Logger
  • Object
show all
Defined in:
lib/foam/otel/logger_bridge.rb

Overview

Rails.logger bridge — a broadcast target (Rails 7.1+ BroadcastLogger) that re-emits every log line as an OTel log record stamped log.rails. Attached via Rails.logger.broadcast_to(bridge) so the app's own logger chain (devices, formatters, TaggedLogging tags) is never wrapped or altered; trace correlation comes from the active context through the stamp/batch pipeline.

Constant Summary collapse

SEVERITY_TEXT =
{ 0 => "DEBUG", 1 => "INFO", 2 => "WARN", 3 => "ERROR", 4 => "FATAL", 5 => "UNKNOWN" }.freeze
SEVERITY_NUMBER =

OTel severity numbers: DEBUG 5, INFO 9, WARN 13, ERROR 17, FATAL 21.

{ 0 => 5, 1 => 9, 2 => 13, 3 => 17, 4 => 21, 5 => 1 }.freeze

Instance Method Summary collapse

Constructor Details

#initialize(tagged_source: nil) ⇒ LoggerBridge

Returns a new instance of LoggerBridge.



20
21
22
23
# File 'lib/foam/otel/logger_bridge.rb', line 20

def initialize(tagged_source: nil)
  super(nil) # no device — emission goes to the OTel logs pipeline
  @tagged_source = tagged_source
end

Instance Method Details

#add(severity, message = nil, progname = nil, &block) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/foam/otel/logger_bridge.rb', line 32

def add(severity, message = nil, progname = nil, &block)
  # The bridge is attached unconditionally by the railtie; it stays
  # inert until init(rails: true) and honors rails: false.
  return true unless Foam::Otel.rails_enabled?

  severity ||= ::Logger::UNKNOWN
  return true if severity < level

  body = message || (block ? yield : progname)
  return true if body.nil?

  attributes = { INSTRUMENTATION_KEY => STAMPS::LOG_RAILS }
  tags = current_tags
  attributes["rails.tags"] = tags.join(" ") unless tags.empty?

  otel_logger.on_emit(
    severity_text: SEVERITY_TEXT.fetch(severity, "UNKNOWN"),
    severity_number: SEVERITY_NUMBER.fetch(severity, 1),
    timestamp: Time.now,
    body: body.to_s,
    attributes: attributes,
    context: OpenTelemetry::Context.current
  )
  true
rescue StandardError
  true # the bridge must never break application logging
end

#otel_loggerObject

Memoized so the hot per-line path is an ivar read, not a LoggerProvider#logger call (which takes a registry mutex + allocates a lookup key on every call).



28
29
30
# File 'lib/foam/otel/logger_bridge.rb', line 28

def otel_logger
  @otel_logger ||= Foam::Otel.logger("foam-otel/rails")
end