Class: OpenTrace::LogForwarder

Inherits:
Logger
  • Object
show all
Defined in:
lib/opentrace/log_forwarder.rb

Overview

Minimal Logger-compatible class that forwards log messages to OpenTrace. Designed to be used as a broadcast target with Rails 7.1+ BroadcastLogger. Does NOT wrap another logger — its only job is to forward to OpenTrace.

Constant Summary collapse

SEVERITY_MAP =
{
  ::Logger::DEBUG   => "DEBUG",
  ::Logger::INFO    => "INFO",
  ::Logger::WARN    => "WARN",
  ::Logger::ERROR   => "ERROR",
  ::Logger::FATAL   => "FATAL",
  ::Logger::UNKNOWN => "UNKNOWN"
}.freeze

Instance Method Summary collapse

Constructor Details

#initializeLogForwarder

Returns a new instance of LogForwarder.



19
20
21
22
23
24
25
26
27
# File 'lib/opentrace/log_forwarder.rb', line 19

def initialize
  super(nil)
  # Match OpenTrace's min_level so BroadcastLogger doesn't downgrade
  # the effective log level for the entire app. Without this, having
  # level=DEBUG here causes BroadcastLogger.level to drop to DEBUG,
  # which forces evaluation of all debug blocks and processing of all
  # debug messages across ALL broadcast targets — even in production.
  self.level = OpenTrace.config.logger_severity
end

Instance Method Details

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



29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/opentrace/log_forwarder.rb', line 29

def add(severity, message = nil, progname = nil, &block)
  severity ||= ::Logger::UNKNOWN
  return true if severity < level

  msg = resolve_message(message, progname, &block)
  return true if msg.nil? || (msg.is_a?(String) && msg.strip.empty?)

  level_str = SEVERITY_MAP.fetch(severity, "UNKNOWN")
  OpenTrace.log(level_str, msg.to_s)

  true
rescue StandardError
  true
end

#clear_tags!Object



53
# File 'lib/opentrace/log_forwarder.rb', line 53

def clear_tags!; end

#closeObject



44
45
46
# File 'lib/opentrace/log_forwarder.rb', line 44

def close
  # no-op — nothing to close
end

#current_tagsObject



55
56
57
# File 'lib/opentrace/log_forwarder.rb', line 55

def current_tags
  []
end

#flushObject

DO NOT implement ‘tagged` here.

Rails’ ActiveSupport::BroadcastLogger routes ‘tagged` through `method_missing` (it’s not in LOGGER_METHODS), which calls ‘logger.send(:tagged, *tags, &block)` on EVERY sink that responds to `:tagged` — without the block-cache guard that `dispatch` uses for info/debug/warn/etc. So if LogForwarder implements `tagged(*tags) { yield self }`, the block passed to the BroadcastLogger’s tagged call runs ONCE PER SINK. For ActiveJob — which wraps both ‘around_enqueue` and `around_perform` in `logger.tagged(…) { … }` — that means:

* enqueue flow runs twice  → adapter.enqueue fires twice
* each dispatched perform runs twice
* net effect: 4 performs (and 4 add_assistant_message rows) per
  single perform_later call on a BroadcastLogger with 2 sinks.

By simply NOT responding to ‘:tagged`, BroadcastLogger’s method_missing does ‘@broadcasts.select { |l| l.respond_to?(name) }` and filters us out — only the real TaggedLogging sink receives the call, its block yields exactly once, and dispatch is single. `push_tags` / `pop_tags` / `clear_tags!` DO stay defined as no-ops because they never take blocks, so calling them on every sink is harmless.



86
# File 'lib/opentrace/log_forwarder.rb', line 86

def flush; end

#pop_tagsObject



52
# File 'lib/opentrace/log_forwarder.rb', line 52

def pop_tags(*); end

#push_tagsObject

ActiveSupport::TaggedLogging interface — BroadcastLogger delegates push_tags/pop_tags to ALL sinks. Without these, method_missing on older Rails versions forwards blindly and raises NoMethodError.



51
# File 'lib/opentrace/log_forwarder.rb', line 51

def push_tags(*); end

#tags_textObject



59
60
61
# File 'lib/opentrace/log_forwarder.rb', line 59

def tags_text
  ""
end