@@ -137,9 +137,7 @@ def start
137137
138138 @thread = Thread . new do
139139 error_log_params = -> ( e ) {
140- default_logging_keys (
141- :exception => e ,
142- :backtrace => e . backtrace ,
140+ exception_logging_keys ( e ,
143141 "pipeline.sources" => pipeline_source_details
144142 )
145143 }
@@ -312,7 +310,7 @@ def start_workers
312310 @crash_detected . make_true
313311 @logger . error (
314312 "Pipeline worker error, the pipeline will be stopped" ,
315- default_logging_keys ( :error => e . cause . message , :exception => e . cause . class , :backtrace => e . cause . backtrace )
313+ exception_logging_keys ( e . cause )
316314 )
317315 end
318316 end
@@ -422,21 +420,14 @@ def inputworker(plugin)
422420 if plugin . stop?
423421 @logger . debug (
424422 "Input plugin raised exception during shutdown, ignoring it." ,
425- default_logging_keys (
426- :plugin => plugin . class . config_name ,
427- :exception => e . message ,
428- :backtrace => e . backtrace ) )
423+ exception_logging_keys ( e , :plugin => plugin . class . config_name ) )
429424 return
430425 end
431426
432427 # otherwise, report error and restart
433428 @logger . error ( I18n . t (
434429 "logstash.pipeline.worker-error-debug" ,
435- **default_logging_keys (
436- :plugin => plugin . inspect ,
437- :error => e . message ,
438- :exception => e . class ,
439- :stacktrace => e . backtrace . join ( "\n " ) ) ) )
430+ **exception_logging_keys ( e , :plugin => plugin . inspect ) ) )
440431
441432 # Assuming the failure that caused this exception is transient,
442433 # let's sleep for a bit and execute #run again
@@ -580,10 +571,7 @@ def close_plugin_and_ignore(plugin)
580571 rescue => e
581572 @logger . warn (
582573 "plugin raised exception while closing, ignoring" ,
583- default_logging_keys (
584- :plugin => plugin . class . config_name ,
585- :exception => e . message ,
586- :backtrace => e . backtrace ) )
574+ exception_logging_keys ( e , :plugin => plugin . class . config_name ) )
587575 end
588576 end
589577
@@ -607,12 +595,12 @@ def init_worker_loop
607595 rescue => e
608596 @logger . error (
609597 "Worker loop initialization error" ,
610- default_logging_keys ( :error => e . message , :exception => e . class , :stacktrace => e . backtrace . join ( " \n " ) ) )
598+ exception_logging_keys ( e ) )
611599 nil
612600 rescue Java ::java . lang . StackOverflowError => se
613601 @logger . error (
614602 "Stack overflow error while compiling Pipeline. Please increase thread stack size using -Xss" ,
615- default_logging_keys ( ) )
603+ exception_logging_keys ( se ) )
616604 nil
617605 end
618606 end
@@ -630,6 +618,42 @@ def default_logging_keys(other_keys = {})
630618 keys
631619 end
632620
621+ def exception_logging_keys ( active_exception = $!, other_keys = { } )
622+ base = active_exception ? unwind_cause_chain ( active_exception ) : { }
623+ default_logging_keys ( base . merge ( other_keys ) )
624+ end
625+
626+ ##
627+ # Yields once per exception in the provided exception's cause chain
628+ # @param exception [Exception]
629+ # @yield_param [Exception]
630+ def cause_chain ( exception , &block )
631+ return enum_for ( :cause_chain , exception ) unless block_given?
632+
633+ current = exception
634+ while !current . nil?
635+ yield current
636+ cause = current . cause
637+ current = ( cause == current ? nil : cause )
638+ end
639+ end
640+
641+ ##
642+ # unwinds the provided exception to create a deeply-nested structure
643+ # representing the exception and its cause chain
644+ # @param [Exception] exception
645+ # @return [Hash{Symbol=>[String|Hash]}]
646+ def unwind_cause_chain ( exception )
647+ cause_chain ( exception ) . reverse_each . reduce ( nil ) do |cause , exception |
648+ {
649+ :exception => exception . class . name ,
650+ :error => exception . message ,
651+ :stacktrace => exception . backtrace . join ( "\n " ) ,
652+ :cause => cause ,
653+ } . compact
654+ end
655+ end
656+
633657 def preserve_event_order? ( pipeline_workers )
634658 case settings . get ( "pipeline.ordered" )
635659 when "auto"
0 commit comments