Class: LogStash::Filters::JavaStackDigest

Inherits:
Base
  • Object
show all
Defined in:
lib/logstash/filters/java_stack_digest.rb

Overview

If the input event contains a Java stack trace, this filter computes a stable digest of it and adds it in a field of the output event

Instance Method Summary collapse

Instance Method Details

#compute_digest(stack_trace, level) ⇒ Object

computes a Java stack trace digest



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/logstash/filters/java_stack_digest.rb', line 69

def compute_digest(stack_trace, level)

  # 1: extract error class from first line
  error_class = @error_pattern.match(stack_trace.shift)
  puts "Error (#{level}) #{error_class}:" if @debug
  md5 = Digest::MD5.new
  # digest: error classname
  md5.update error_class[1]

  # 2: read all stack trace elements until stack trace is empty or we hit the next error
  ste_count = 0
  while not stack_trace.empty?
    if stack_trace.first.start_with?(' ') or stack_trace.first.start_with?("\t")
      # current line starts with a whitespace: is it a stack trace element ?
      stack_element = @stack_element_pattern.match(stack_trace.first)
      if stack_element
        # current line is a stack trace element
        ste_count+=1
        if is_excluded?(stack_element)
          puts "  (-) at #{stack_element[1]}(#{stack_element[2]}:#{stack_element[3]})" if @debug
        else
          puts "  (+) at #{stack_element[1]}(#{stack_element[2]}:#{stack_element[3]})" if @debug
          # digest: STE classname and method
          md5.update stack_element[1]
          # digest: line number (if present)
          if not (stack_element[3].nil? or stack_element[3].empty?)
            md5.update stack_element[3]
          end
        end
      end
    elsif(ste_count > 0)
      # current line doesn't start with a whitespace and we've already read stack trace elements: is it the next error in the stack
      break
    end
    # move to next line
    stack_trace.shift
  end

  # 3: if stack trace not empty, compute digest for next error
  if not stack_trace.empty?
    md5.update compute_digest(stack_trace, level+1)
  end

  return md5.hexdigest
end

#filter(event) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
# File 'lib/logstash/filters/java_stack_digest.rb', line 56

def filter(event)

  stack_trace = event.get(@source)

  return if stack_trace.nil? || stack_trace.empty?

  event.set(@target, compute_digest(stack_trace.split("\n"), 0))

  # filter_matched should go in the last line of our successful code
  filter_matched(event)
end

#is_excluded?(stack_element) ⇒ Boolean

Returns:

  • (Boolean)


115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/logstash/filters/java_stack_digest.rb', line 115

def is_excluded?(stack_element)
  # 1: exclude elements without source info ?
  if @exclude_no_source and (stack_element[2].nil? or stack_element[2].empty?) and (stack_element[3].nil? or stack_element[3].empty?)
    return true
  end
  # 2: Regex based exclusion
  @excludes.each do |pattern|
    if pattern.match(stack_element[1])
      return true
    end
  end
  return false
end

#registerObject



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/logstash/filters/java_stack_digest.rb', line 38

def register
  # Add instance variables

  # Regexp to capture the Error classname from the first stack trace line
  # group 1: error classname
  @error_pattern = /((?:[\w$]+\.){2,}[\w$]+):/

  # Regexp to extract stack trace elements information
  # group 1: classname+method
  # group 2: filename (optional)
  # group 3: line number (optional)
  @stack_element_pattern = /^\s+at\s+((?:[\w$]+\.){2,}[\w$]+)\((?:([^:]+)(?::(\d+))?)?\)/

  # coerce excludes to an array of Regexp
  @excludes = @excludes.collect {|pattern| Regexp::new(pattern)}
end