rails_semantic_logger 4.1.3 → 4.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +17 -10
  3. data/Rakefile +9 -9
  4. data/lib/rails_semantic_logger/action_controller/log_subscriber.rb +125 -0
  5. data/lib/rails_semantic_logger/action_mailer/log_subscriber.rb +135 -0
  6. data/lib/rails_semantic_logger/action_view/log_subscriber.rb +111 -0
  7. data/lib/rails_semantic_logger/active_job/log_subscriber.rb +126 -0
  8. data/lib/rails_semantic_logger/active_record/log_subscriber.rb +218 -0
  9. data/lib/rails_semantic_logger/delayed_job/plugin.rb +11 -0
  10. data/lib/rails_semantic_logger/engine.rb +189 -194
  11. data/lib/rails_semantic_logger/extensions/action_cable/tagged_logger_proxy.rb +1 -1
  12. data/lib/rails_semantic_logger/extensions/action_controller/live.rb +8 -4
  13. data/lib/rails_semantic_logger/extensions/action_dispatch/debug_exceptions.rb +11 -7
  14. data/lib/rails_semantic_logger/extensions/action_view/streaming_template_renderer.rb +10 -6
  15. data/lib/rails_semantic_logger/extensions/active_job/logging.rb +10 -6
  16. data/lib/rails_semantic_logger/extensions/active_model_serializers/logging.rb +12 -9
  17. data/lib/rails_semantic_logger/extensions/active_support/logger.rb +24 -0
  18. data/lib/rails_semantic_logger/extensions/active_support/tagged_logging.rb +8 -0
  19. data/lib/rails_semantic_logger/extensions/mongoid/config.rb +11 -0
  20. data/lib/rails_semantic_logger/extensions/rack/server.rb +12 -0
  21. data/lib/rails_semantic_logger/extensions/rails/server.rb +9 -5
  22. data/lib/rails_semantic_logger/options.rb +122 -0
  23. data/lib/rails_semantic_logger/rack/logger.rb +100 -0
  24. data/lib/rails_semantic_logger/version.rb +2 -2
  25. data/lib/rails_semantic_logger.rb +58 -3
  26. metadata +46 -24
  27. data/lib/rails_semantic_logger/extensions/action_controller/log_subscriber.rb +0 -107
  28. data/lib/rails_semantic_logger/extensions/action_controller/log_subscriber_processing.rb +0 -28
  29. data/lib/rails_semantic_logger/extensions/action_view/log_subscriber.rb +0 -12
  30. data/lib/rails_semantic_logger/extensions/active_record/log_subscriber.rb +0 -44
  31. data/lib/rails_semantic_logger/extensions/rails/rack/logger.rb +0 -63
  32. data/lib/rails_semantic_logger/extensions/rails/rack/logger_info_as_debug.rb +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 607046851ee5bfb0335e577fbb87f9c3ae6ab93f
4
- data.tar.gz: 3375c64b102e5461ba50412a3495c898524f63df
2
+ SHA256:
3
+ metadata.gz: 73a37ac27f2cf94d083cc75aa557a778f32e2de852b3be6447b072dc1da89047
4
+ data.tar.gz: 681f2145e71def6b336792fe3d581dfd89da6fd3ca471befcbd8ffa4f11abb50
5
5
  SHA512:
6
- metadata.gz: 44f58b19256318c9fa3acb07fb08a862000acf7e15bfe27dda9fdb29052627da9c484da91fbefde02840cacdd8d7ec7556189a5297c898db39b9fde19fd1d491
7
- data.tar.gz: 860b06c8b1083e12befe6b074e1a8d0281186fa30a3f02f5342465bd44c50905a3703f90071b376a04db8c01b897d6273ab6b4fac4d81a0d6115cbd6ca5b5322
6
+ metadata.gz: 8d299a14cb4c3eaf282e4bf502d8e60c2a36095b138c17969cf0a8f79b0431a731adbe8963ae2017bf429f12b7f42fe65d5c199a2c5f88e984a71d4605766bea
7
+ data.tar.gz: d837dc46c0dcd38b19dcf2a62c926c91ef1775542d55c8919d3a76db2e62764ab8675890238da78ab19b157f3b920e9d92257d5b2e347bb66d0c5a2bde60441f
data/README.md CHANGED
@@ -1,26 +1,33 @@
1
- # rails_semantic_logger
2
- ![](https://img.shields.io/gem/v/rails_semantic_logger.svg) ![](https://img.shields.io/gem/dt/semantic_logger.svg) ![](https://img.shields.io/badge/status-production%20ready-blue.svg)
1
+ # Rails Semantic Logger
2
+ [![Gem Version](https://img.shields.io/gem/v/rails_semantic_logger.svg)](https://rubygems.org/gems/rails_semantic_logger) [![Build Status](https://github.com/reidmorrison/rails_semantic_logger/workflows/build/badge.svg)](https://github.com/reidmorrison/rails_semantic_logger/actions?query=workflow%3Abuild) [![Downloads](https://img.shields.io/gem/dt/rails_semantic_logger.svg)](https://rubygems.org/gems/rails_semantic_logger) [![License](https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg)](http://opensource.org/licenses/Apache-2.0) ![](https://img.shields.io/badge/status-Production%20Ready-blue.svg)
3
3
 
4
- Next generation logging system for Rails to support highly concurrent, high throughput, low latency systems
4
+ Rails Semantic Logger replaces the Rails default logger with [Semantic Logger](https://logger.rocketjob.io/)
5
5
 
6
- Rails Semantic Logger replaces the Rails default logger with [Semantic Logger](http://github.com/rocketjob/semantic_logger)
7
-
8
- * http://github.com/rocketjob/rails_semantic_logger
6
+ * http://github.com/reidmorrison/rails_semantic_logger
9
7
 
10
8
  ## Documentation
11
9
 
12
- For complete documentation see: http://rocketjob.github.io/semantic_logger/rails
10
+ For complete documentation see: https://logger.rocketjob.io/rails
11
+
12
+ ## Upgrading to Semantic Logger v4.4
13
+
14
+ With some forking frameworks it is necessary to call `reopen` after the fork. With v4.4 the
15
+ workaround for Ruby 2.5 crashes is no longer needed.
16
+ I.e. Please remove the following line if being called anywhere:
17
+
18
+ ~~~ruby
19
+ SemanticLogger::Processor.instance.instance_variable_set(:@queue, Queue.new)
20
+ ~~~
13
21
 
14
22
  ## Supports
15
23
 
16
- - Ruby 1.9.3, 2.0, 2.1, 2.2 (or above) Or, JRuby 1.7, 9.0 (or above)
17
- - Rails 3.2, 4, 5 (or above)
24
+ For the complete list of supported Ruby and Rails versions, see the [Testing file](https://github.com/reidmorrison/rails_semantic_logger/blob/master/.github/workflows/ci.yml).
18
25
 
19
26
  ## Author
20
27
 
21
28
  [Reid Morrison](https://github.com/reidmorrison)
22
29
 
23
- [Contributors](https://github.com/rocketjob/rails_semantic_logger/graphs/contributors)
30
+ [Contributors](https://github.com/reidmorrison/rails_semantic_logger/graphs/contributors)
24
31
 
25
32
  ## Versioning
26
33
 
data/Rakefile CHANGED
@@ -1,30 +1,30 @@
1
1
  # Setup bundler to avoid having to run bundle exec all the time.
2
- require 'rubygems'
3
- require 'bundler/setup'
2
+ require "rubygems"
3
+ require "bundler/setup"
4
4
 
5
- require 'rake/testtask'
6
- require_relative 'lib/rails_semantic_logger/version'
5
+ require "rake/testtask"
6
+ require_relative "lib/rails_semantic_logger/version"
7
7
 
8
8
  task :gem do
9
- system 'gem build rails_semantic_logger.gemspec'
9
+ system "gem build rails_semantic_logger.gemspec"
10
10
  end
11
11
 
12
- task :publish => :gem do
12
+ task publish: :gem do
13
13
  system "git tag -a v#{RailsSemanticLogger::VERSION} -m 'Tagging #{RailsSemanticLogger::VERSION}'"
14
- system 'git push --tags'
14
+ system "git push --tags"
15
15
  system "gem push rails_semantic_logger-#{RailsSemanticLogger::VERSION}.gem"
16
16
  system "rm rails_semantic_logger-#{RailsSemanticLogger::VERSION}.gem"
17
17
  end
18
18
 
19
19
  Rake::TestTask.new(:test) do |t|
20
- t.pattern = 'test/**/*_test.rb'
20
+ t.pattern = "test/**/*_test.rb"
21
21
  t.verbose = true
22
22
  t.warning = false
23
23
  end
24
24
 
25
25
  # By default run tests against all appraisals
26
26
  if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
27
- require 'appraisal'
27
+ require "appraisal"
28
28
  task default: :appraisal
29
29
  else
30
30
  task default: :test
@@ -0,0 +1,125 @@
1
+ module RailsSemanticLogger
2
+ module ActionController
3
+ class LogSubscriber < ActiveSupport::LogSubscriber
4
+ INTERNAL_PARAMS = %w[controller action format _method only_path].freeze
5
+
6
+ # Log as debug to hide Processing messages in production
7
+ def start_processing(event)
8
+ controller_logger(event).debug { "Processing ##{event.payload[:action]}" }
9
+ end
10
+
11
+ def process_action(event)
12
+ controller_logger(event).info do
13
+ payload = event.payload.dup
14
+
15
+ # Unused, but needed for Devise 401 status code monkey patch to still work.
16
+ ::ActionController::Base.log_process_action(payload)
17
+
18
+ params = payload[:params]
19
+
20
+ if params.kind_of?(Hash) || params.kind_of?(::ActionController::Parameters)
21
+ # According to PR https://github.com/reidmorrison/rails_semantic_logger/pull/37/files
22
+ # params is not always a Hash.
23
+ payload[:params] = params.to_unsafe_h unless params.is_a?(Hash)
24
+ payload[:params] = params.except(*INTERNAL_PARAMS)
25
+
26
+ if payload[:params].empty?
27
+ payload.delete(:params)
28
+ elsif params["file"]
29
+ # When logging to JSON the entire tempfile is logged, so convert it to a string.
30
+ payload[:params]["file"] = params["file"].inspect
31
+ end
32
+ end
33
+
34
+ format = payload[:format]
35
+ payload[:format] = format.to_s.upcase if format.is_a?(Symbol)
36
+
37
+ payload[:path] = extract_path(payload[:path]) if payload.key?(:path)
38
+
39
+ exception = payload.delete(:exception)
40
+ if payload[:status].nil? && exception.present?
41
+ exception_class_name = exception.first
42
+ payload[:status] = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name)
43
+ end
44
+
45
+ # Rounds off the runtimes. For example, :view_runtime, :mongo_runtime, etc.
46
+ payload.keys.each do |key|
47
+ payload[key] = payload[key].to_f.round(2) if key.to_s =~ /(.*)_runtime/
48
+ end
49
+
50
+ # Rails 6+ includes allocation count
51
+ payload[:allocations] = event.allocations if event.respond_to?(:allocations)
52
+
53
+ payload[:status_message] = ::Rack::Utils::HTTP_STATUS_CODES[payload[:status]] if payload[:status].present?
54
+
55
+ # Causes excessive log output with Rails 5 RC1
56
+ payload.delete(:headers)
57
+ # Causes recursion in Rails 6.1.rc1
58
+ payload.delete(:request)
59
+ payload.delete(:response)
60
+
61
+ {
62
+ message: "Completed ##{payload[:action]}",
63
+ duration: event.duration,
64
+ payload: payload
65
+ }
66
+ end
67
+ end
68
+
69
+ def halted_callback(event)
70
+ controller_logger(event).info { "Filter chain halted as #{event.payload[:filter].inspect} rendered or redirected" }
71
+ end
72
+
73
+ def send_file(event)
74
+ controller_logger(event).info(message: "Sent file", payload: {path: event.payload[:path]}, duration: event.duration)
75
+ end
76
+
77
+ def redirect_to(event)
78
+ controller_logger(event).info(message: "Redirected to", payload: {location: event.payload[:location]})
79
+ end
80
+
81
+ def send_data(event)
82
+ controller_logger(event).info(message: "Sent data", payload: {file_name: event.payload[:filename]}, duration: event.duration)
83
+ end
84
+
85
+ def unpermitted_parameters(event)
86
+ controller_logger(event).debug do
87
+ unpermitted_keys = event.payload[:keys]
88
+ "Unpermitted parameter#{'s' if unpermitted_keys.size > 1}: #{unpermitted_keys.join(', ')}"
89
+ end
90
+ end
91
+
92
+ %w[write_fragment read_fragment exist_fragment?
93
+ expire_fragment expire_page write_page].each do |method|
94
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
95
+ def #{method}(event)
96
+ # enable_fragment_cache_logging as of Rails 5
97
+ return if ::ActionController::Base.respond_to?(:enable_fragment_cache_logging) && !::ActionController::Base.enable_fragment_cache_logging
98
+ controller_logger(event).info do
99
+ key_or_path = event.payload[:key] || event.payload[:path]
100
+ {message: "#{method.to_s.humanize} \#{key_or_path}", duration: event.duration}
101
+ end
102
+ end
103
+ METHOD
104
+ end
105
+
106
+ private
107
+
108
+ # Returns the logger for the supplied event.
109
+ # Returns ActionController::Base.logger if no controller is present
110
+ def controller_logger(event)
111
+ controller = event.payload[:controller]
112
+ return ::ActionController::Base.logger unless controller
113
+
114
+ controller.constantize.logger || ::ActionController::Base.logger
115
+ rescue NameError
116
+ ::ActionController::Base.logger
117
+ end
118
+
119
+ def extract_path(path)
120
+ index = path.index("?")
121
+ index ? path[0, index] : path
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,135 @@
1
+ require "active_support/log_subscriber"
2
+ require "action_mailer"
3
+
4
+ module RailsSemanticLogger
5
+ module ActionMailer
6
+ class LogSubscriber < ::ActiveSupport::LogSubscriber
7
+ def deliver(event)
8
+ ex = event.payload[:exception_object]
9
+ message_id = event.payload[:message_id]
10
+ duration = event.duration.round(1)
11
+ if ex
12
+ log_with_formatter event: event, log_duration: true, level: :error do |fmt|
13
+ {
14
+ message: "Error delivering mail #{message_id} (#{duration}ms)",
15
+ exception: ex
16
+ }
17
+ end
18
+ else
19
+ message = begin
20
+ if event.payload[:perform_deliveries]
21
+ "Delivered mail #{message_id} (#{duration}ms)"
22
+ else
23
+ "Skipped delivery of mail #{message_id} as `perform_deliveries` is false"
24
+ end
25
+ end
26
+ log_with_formatter event: event, log_duration: true do |fmt|
27
+ { message: message }
28
+ end
29
+ end
30
+ end
31
+
32
+ # An email was generated.
33
+ def process(event)
34
+ mailer = event.payload[:mailer]
35
+ action = event.payload[:action]
36
+ duration = event.duration.round(1)
37
+ log_with_formatter event: event do |fmt|
38
+ { message: "#{mailer}##{action}: processed outbound mail in #{duration}ms" }
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ class EventFormatter
45
+ def initialize(event:, log_duration: false)
46
+ @event = event
47
+ @log_duration = log_duration
48
+ end
49
+
50
+ def mailer
51
+ event.payload[:mailer]
52
+ end
53
+
54
+ def payload
55
+ {}.tap do |h|
56
+ h[:event_name] = event.name
57
+ h[:mailer] = mailer
58
+ h[:action] = action
59
+ h[:message_id] = event.payload[:message_id]
60
+ h[:perform_deliveries] = event.payload[:perform_deliveries]
61
+ h[:subject] = event.payload[:subject]
62
+ h[:to] = event.payload[:to]
63
+ h[:from] = event.payload[:from]
64
+ h[:bcc] = event.payload[:bcc]
65
+ h[:cc] = event.payload[:cc]
66
+ h[:date] = date
67
+ h[:duration] = event.duration.round(2) if log_duration?
68
+ h[:args] = formatted_args
69
+ end
70
+ end
71
+
72
+ def date
73
+ if event.payload[:date].respond_to?(:to_time)
74
+ event.payload[:date].to_time.utc
75
+ elsif event.payload[:date].is_a?(String)
76
+ Time.parse(date).utc
77
+ else
78
+ nil
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ attr_reader :event
85
+
86
+ def mailer
87
+ event.payload[:mailer]
88
+ end
89
+
90
+ def action
91
+ event.payload[:action]
92
+ end
93
+
94
+ def formatted_args
95
+ if defined?(mailer.contantize.log_arguments?) && !mailer.contantize.log_arguments?
96
+ ""
97
+ else
98
+ JSON.pretty_generate(event.payload[:args].map { |arg| format(arg) }) if event.payload[:args].present?
99
+ end
100
+ end
101
+
102
+ def format(arg)
103
+ case arg
104
+ when Hash
105
+ arg.transform_values { |value| format(value) }
106
+ when Array
107
+ arg.map { |value| format(value) }
108
+ when GlobalID::Identification
109
+ begin
110
+ arg.to_global_id
111
+ rescue StandardError
112
+ arg
113
+ end
114
+ else
115
+ arg
116
+ end
117
+ end
118
+
119
+ def log_duration?
120
+ @log_duration
121
+ end
122
+ end
123
+
124
+ def log_with_formatter(level: :info, **kw_args)
125
+ fmt = EventFormatter.new(**kw_args)
126
+ msg = yield fmt
127
+ logger.public_send(level, **msg, payload: fmt.payload)
128
+ end
129
+
130
+ def logger
131
+ ::ActionMailer::Base.logger
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,111 @@
1
+ require "active_support/log_subscriber"
2
+
3
+ module RailsSemanticLogger
4
+ module ActionView
5
+ # Output Semantic logs from Action View.
6
+ class LogSubscriber < ActiveSupport::LogSubscriber
7
+ VIEWS_PATTERN = %r{^app/views/}.freeze
8
+
9
+ class << self
10
+ attr_reader :logger
11
+ attr_accessor :rendered_log_level
12
+ end
13
+
14
+ def initialize
15
+ @rails_root = nil
16
+ super
17
+ end
18
+
19
+ def render_template(event)
20
+ return unless should_log?
21
+
22
+ payload = {
23
+ template: from_rails_root(event.payload[:identifier])
24
+ }
25
+ payload[:within] = from_rails_root(event.payload[:layout]) if event.payload[:layout]
26
+ payload[:allocations] = event.allocations if event.respond_to?(:allocations)
27
+
28
+ logger.measure(
29
+ self.class.rendered_log_level,
30
+ "Rendered",
31
+ payload: payload,
32
+ duration: event.duration
33
+ )
34
+ end
35
+
36
+ def render_partial(event)
37
+ return unless should_log?
38
+
39
+ payload = {
40
+ partial: from_rails_root(event.payload[:identifier])
41
+ }
42
+ payload[:within] = from_rails_root(event.payload[:layout]) if event.payload[:layout]
43
+ payload[:cache] = event.payload[:cache_hit] unless event.payload[:cache_hit].nil?
44
+ payload[:allocations] = event.allocations if event.respond_to?(:allocations)
45
+
46
+ logger.measure(
47
+ self.class.rendered_log_level,
48
+ "Rendered",
49
+ payload: payload,
50
+ duration: event.duration
51
+ )
52
+ end
53
+
54
+ def render_collection(event)
55
+ return unless should_log?
56
+
57
+ identifier = event.payload[:identifier] || "templates"
58
+
59
+ payload = {
60
+ template: from_rails_root(identifier),
61
+ count: event.payload[:count]
62
+ }
63
+ payload[:cache_hits] = event.payload[:cache_hits] if event.payload[:cache_hits]
64
+ payload[:allocations] = event.allocations if event.respond_to?(:allocations)
65
+
66
+ logger.measure(
67
+ self.class.rendered_log_level,
68
+ "Rendered",
69
+ payload: payload,
70
+ duration: event.duration
71
+ )
72
+ end
73
+
74
+ def start(name, id, payload)
75
+ if (name == "render_template.action_view") && should_log?
76
+ payload = {template: from_rails_root(payload[:identifier])}
77
+ payload[:within] = from_rails_root(payload[:layout]) if payload[:layout]
78
+
79
+ logger.send(self.class.rendered_log_level, message: "Rendering", payload: payload)
80
+ end
81
+
82
+ super
83
+ end
84
+
85
+ private
86
+
87
+ @logger = SemanticLogger["ActionView"]
88
+ @rendered_log_level = :debug
89
+
90
+ EMPTY = "".freeze
91
+
92
+ def should_log?
93
+ logger.send("#{self.class.rendered_log_level}?")
94
+ end
95
+
96
+ def from_rails_root(string)
97
+ string = string.sub(rails_root, EMPTY)
98
+ string.sub!(VIEWS_PATTERN, EMPTY)
99
+ string
100
+ end
101
+
102
+ def rails_root
103
+ @rails_root ||= "#{Rails.root}/"
104
+ end
105
+
106
+ def logger
107
+ self.class.logger
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,126 @@
1
+ require "active_job"
2
+
3
+ module RailsSemanticLogger
4
+ module ActiveJob
5
+ class LogSubscriber < ::ActiveSupport::LogSubscriber
6
+ def enqueue(event)
7
+ log_with_formatter event: event do |fmt|
8
+ {message: "Enqueued #{fmt.job_info}"}
9
+ end
10
+ end
11
+
12
+ def enqueue_at(event)
13
+ log_with_formatter event: event do |fmt|
14
+ {message: "Enqueued #{fmt.job_info} at #{fmt.scheduled_at}"}
15
+ end
16
+ end
17
+
18
+ def perform_start(event)
19
+ log_with_formatter event: event do |fmt|
20
+ {message: "Performing #{fmt.job_info}"}
21
+ end
22
+ end
23
+
24
+ def perform(event)
25
+ ex = event.payload[:exception_object]
26
+ if ex
27
+ log_with_formatter event: event, log_duration: true, level: :error do |fmt|
28
+ {
29
+ message: "Error performing #{fmt.job_info} in #{event.duration.round(2)}ms",
30
+ exception: ex
31
+ }
32
+ end
33
+ else
34
+ log_with_formatter event: event, log_duration: true do |fmt|
35
+ {message: "Performed #{fmt.job_info} in #{event.duration.round(2)}ms"}
36
+ end
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ class EventFormatter
43
+ def initialize(event:, log_duration: false)
44
+ @event = event
45
+ @log_duration = log_duration
46
+ end
47
+
48
+ def job_info
49
+ "#{job.class.name} (Job ID: #{job.job_id}) to #{queue_name}"
50
+ end
51
+
52
+ def payload
53
+ {}.tap do |h|
54
+ h[:event_name] = event.name
55
+ h[:adapter] = adapter_name
56
+ h[:queue] = job.queue_name
57
+ h[:job_class] = job.class.name
58
+ h[:job_id] = job.job_id
59
+ h[:provider_job_id] = job.try(:provider_job_id) # Not available in Rails 4.2
60
+ h[:duration] = event.duration.round(2) if log_duration?
61
+ h[:arguments] = formatted_args
62
+ end
63
+ end
64
+
65
+ def queue_name
66
+ adapter_name + "(#{job.queue_name})"
67
+ end
68
+
69
+ def scheduled_at
70
+ Time.at(event.payload[:job].scheduled_at).utc
71
+ end
72
+
73
+ private
74
+
75
+ attr_reader :event
76
+
77
+ def job
78
+ event.payload[:job]
79
+ end
80
+
81
+ def adapter_name
82
+ event.payload[:adapter].class.name.demodulize.remove("Adapter")
83
+ end
84
+
85
+ def formatted_args
86
+ if defined?(job.class.log_arguments?) && !job.class.log_arguments?
87
+ ""
88
+ else
89
+ JSON.pretty_generate(job.arguments.map { |arg| format(arg) })
90
+ end
91
+ end
92
+
93
+ def format(arg)
94
+ case arg
95
+ when Hash
96
+ arg.transform_values { |value| format(value) }
97
+ when Array
98
+ arg.map { |value| format(value) }
99
+ when GlobalID::Identification
100
+ begin
101
+ arg.to_global_id
102
+ rescue StandardError
103
+ arg
104
+ end
105
+ else
106
+ arg
107
+ end
108
+ end
109
+
110
+ def log_duration?
111
+ @log_duration
112
+ end
113
+ end
114
+
115
+ def log_with_formatter(level: :info, **kw_args)
116
+ fmt = EventFormatter.new(**kw_args)
117
+ msg = yield fmt
118
+ logger.public_send(level, **msg, payload: fmt.payload)
119
+ end
120
+
121
+ def logger
122
+ ::ActiveJob::Base.logger
123
+ end
124
+ end
125
+ end
126
+ end