Reputation: 51093
ActiveSupport::TaggedLogging
works by appending ActiveSupport::TaggedLogging::Formatter
to the inheritance chain of the current formatter via Object#extend
.
Unfortunately, ActiveSupport::TaggedLogging::Formatter#call
assumes the msg
argument is always a string, resulting in
garbage when it prepends tags to a hash (e.g. with Lograge and Ougai). And certain standard libraries, like Webpacker, insist on injecting TaggedLogging
.
I've come up with the metaprogramming hack below to prevent ActiveSupport::TaggedLogging::Formatter#call
from overriding the superclass implementation (in this case from Ougai):
class MyBunyanFormatter < Ougai::Formatters::Bunyan
def extend(mod)
return super unless mod.method_defined?(:call)
call_original = self.method(:call) # 1. preserve original
super(mod) # 2. overridden here
define_singleton_method(:call, call_original) # 3. de-overridden here
end
end
But it's clunky and counterintuitive, and I'm not excited about it.
The other alternative, at least in the case of Webpacker, seems to be to write a custom logger that implements tagged()
:
class MyLogger < Ougai::Logger
def tagged(*tags)
# do something with tags
yield self
end
end
This at least doesn't involve any metaprogramming shenanigans, but I wonder if I can count on other libraries besides Webpacker not to inject TaggedLogging
anyway.
Surely I'm not the first person to have this problem since people started trying to do structured logging from Rails apps. What's the right solution?
Upvotes: 3
Views: 764
Reputation: 51093
The solution given in the Ougai docs is to monkey-patch TaggedLogging
to eliminate this behavior.
module ActiveSupport::TaggedLogging::Formatter
def call(severity, time, progname, data)
data = { msg: data.to_s } unless data.is_a?(Hash)
tags = current_tags
data[:tags] = tags if tags.present?
_call(severity, time, progname, data)
end
end
Note that _call
only works if for Ougai-based Formatters
.
Upvotes: 2