Class: Fluent::ExceptionDetector

Inherits:
Object
  • Object
show all
Defined in:
lib/fluent/plugin/exception_detector.rb

Overview

State machine that consumes individual log lines and detects multi-line stack traces.

Instance Method Summary collapse

Constructor Details

#initialize(*languages) ⇒ ExceptionDetector

Returns a new instance of ExceptionDetector.



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/fluent/plugin/exception_detector.rb', line 177

def initialize(*languages)
  @state = :start_state
  @rules = Hash.new { |h, k| h[k] = [] }

  languages = [:all] if languages.empty?

  languages.each do |lang|
    rule_config =
      ExceptionDetectorConfig::RULES_BY_LANG.fetch(lang.downcase) do |_k|
        raise ArgumentError, "Unknown language: #{lang}"
      end

    rule_config.each do |r|
      target = ExceptionDetectorConfig::RuleTarget.new(r[:pattern],
                                                       r[:to_state])
      r[:from_states].each do |from_state|
        @rules[from_state] << target
      end
    end
  end

  @rules.each_value(&:uniq!)
end

Instance Method Details

#resetObject



227
228
229
# File 'lib/fluent/plugin/exception_detector.rb', line 227

def reset
  @state = :start_state
end

#update(line) ⇒ Object

Updates the state machine and returns the trace detection status:

  • no_trace: ‘line’ does not belong to an exception trace,

  • start_trace: ‘line’ starts a detected exception trace,

  • inside: ‘line’ is part of a detected exception trace,

  • end: the detected exception trace ends after ‘line’.



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/fluent/plugin/exception_detector.rb', line 206

def update(line)
  trace_seen_before = transition(line)
  # If the state machine fell back to the start state because there is no
  # defined transition for 'line', trigger another state transition because
  # 'line' may contain the beginning of another exception.
  transition(line) unless trace_seen_before
  new_state = @state
  trace_seen_after = new_state != :start_state

  case [trace_seen_before, trace_seen_after]
  when [true, true]
    :inside_trace
  when [true, false]
    :end_trace
  when [false, true]
    :start_trace
  else
    :no_trace
  end
end