From 0de9ea24201fa15e5c5b3a817f8b9dbb9453049e Mon Sep 17 00:00:00 2001 From: Mattia Giuffrida Date: Fri, 29 Nov 2024 14:13:09 +0000 Subject: [PATCH] Add error_cause property to log message. --- lib/sidekiq/exception_utils.rb | 22 ++++++++++++++-------- lib/sidekiq/logging/shared.rb | 9 ++++++++- spec/sidekiq/logstash_spec.rb | 16 ++++++++++++++-- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/lib/sidekiq/exception_utils.rb b/lib/sidekiq/exception_utils.rb index f7e1765..a1b2cc1 100644 --- a/lib/sidekiq/exception_utils.rb +++ b/lib/sidekiq/exception_utils.rb @@ -2,18 +2,13 @@ # Utility that allows us to get a hash representation of an exception module ExceptionUtils - def self.get_exception_with_cause_hash(exc, parent_backtrace = nil, max_depth_left) - backtrace = exc.backtrace || [] - if parent_backtrace - common_lines = backtrace.reverse.zip(parent_backtrace.reverse).take_while { |a, b| a == b } - - backtrace = backtrace[0...-common_lines.length] if common_lines.any? - end + extend self + def get_exception_with_cause_hash(exc, parent_backtrace = nil, max_depth_left) error_hash = { 'class' => exc.class.to_s, 'message' => exc.message, - 'backtrace' => backtrace + 'backtrace' => backtrace_for(exc, parent_backtrace) } if (cause = exc.cause) && max_depth_left.positive? @@ -23,4 +18,15 @@ def self.get_exception_with_cause_hash(exc, parent_backtrace = nil, max_depth_le error_hash end + + def backtrace_for(exception, parent_backtrace) + backtrace = exception.backtrace || [] + if parent_backtrace + common_lines = backtrace.reverse.zip(parent_backtrace.reverse).take_while { |a, b| a == b } + + backtrace = backtrace[0...-common_lines.length] if common_lines.any? + end + + backtrace + end end diff --git a/lib/sidekiq/logging/shared.rb b/lib/sidekiq/logging/shared.rb index 4001fd9..444ed72 100644 --- a/lib/sidekiq/logging/shared.rb +++ b/lib/sidekiq/logging/shared.rb @@ -58,8 +58,15 @@ def log_job_exception(job, started_at, exc) else exc = exc.cause || exc if exc.is_a? Sidekiq::JobRetry::Handled payload['error_message'] = exc.message - payload['error'] = exc.class + payload['error'] = exc.class.to_s payload['error_backtrace'] = %('#{exc.backtrace.join("\n")}') + if (cause = exc.cause) + payload['error_cause'] = { + 'class' => cause.class.to_s, + 'message' => cause.message, + 'backtrace' => ExceptionUtils.backtrace_for(cause, exc.backtrace) + } + end end process_payload(payload) diff --git a/spec/sidekiq/logstash_spec.rb b/spec/sidekiq/logstash_spec.rb index c6bfd1b..efb91e5 100644 --- a/spec/sidekiq/logstash_spec.rb +++ b/spec/sidekiq/logstash_spec.rb @@ -120,9 +120,15 @@ def process(worker, params = [], encrypt: false) it 'logs the exception with job retry' do expect { process(SpecWorker, [true]) }.to raise_error(RuntimeError) - expect(log_message['error_message']).to eq('You know nothing, Jon Snow.') expect(log_message['error']).to eq('RuntimeError') + expect(log_message['error_message']).to eq('You know nothing, Jon Snow.') expect(log_message['error_backtrace'].split("\n").first).to include('workers/spec_worker.rb:') + expect(log_message['error_cause']).to match( + hash_including( + 'class' => 'RuntimeError', + 'message' => 'Error rescuing error' + ) + ) end it 'logs the exception without job retry' do @@ -130,9 +136,15 @@ def process(worker, params = [], encrypt: false) expect { process(SpecWorker, [true]) }.to raise_error(RuntimeError) - expect(log_message['error_message']).to eq('You know nothing, Jon Snow.') expect(log_message['error']).to eq('RuntimeError') + expect(log_message['error_message']).to eq('You know nothing, Jon Snow.') expect(log_message['error_backtrace'].split("\n").first).to include('workers/spec_worker.rb:') + expect(log_message['error_cause']).to match( + hash_including( + 'class' => 'RuntimeError', + 'message' => 'Error rescuing error' + ) + ) end context 'log_job_exception_with_causes enabled' do