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.



229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/fluent/plugin/exception_detector.rb', line 229

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



279
280
281
# File 'lib/fluent/plugin/exception_detector.rb', line 279

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’.



258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/fluent/plugin/exception_detector.rb', line 258

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