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) ⇒ Object

computes a Java stack trace digest



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
114
115
116
117
# File 'lib/logstash/filters/java_stack_digest.rb', line 73

def compute_digest(stack_trace)
  md5 = Digest::MD5.new

  # 1: extract error class from first line
  cur_stack_trace_line = stack_trace.shift
  error_class = @error_pattern.match(cur_stack_trace_line)

  # 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?
    cur_stack_trace_line = stack_trace.first
    if cur_stack_trace_line.start_with?(' ') or cur_stack_trace_line.start_with?("\t")
      # current line starts with a whitespace: is it a stack trace element ?
      stack_element = @stack_element_pattern.match(cur_stack_trace_line)
      if stack_element
        # current line is a stack trace element
        ste_count+=1
        if not is_excluded?(stack_element)
          # 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: it looks like 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)
  end

  return md5.hexdigest
end

#filter(event) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/logstash/filters/java_stack_digest.rb', line 59

def filter(event)

  stack_trace = event.get(@source)

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

  # compute digest add to the event
  event.set(@target, compute_digest(stack_trace.split("\n")))

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

#is_excluded?(stack_element) ⇒ Boolean

Determines whether the given stack trace element (Regexp match) should be excluded from digest computation

Returns:

  • (Boolean)


120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/logstash/filters/java_stack_digest.rb', line 120

def is_excluded?(stack_element)
  # 1: exclude elements without source info ?
  if @exclude_no_source and (stack_element[3].nil? or stack_element[3].empty?)
    return true
  end

  # 2: Regex based inclusions
  classname_and_method = stack_element[1]
  if not @includes.empty?
    match_idx = @includes.index do |pattern|
      pattern.match(classname_and_method)
    end
    if match_idx.nil?
      return true
    end
  end

  # 3: Regex based exclusions
  @excludes.each do |pattern|
    if pattern.match(classname_and_method)
      return true
    end
  end
  return false
end

#registerObject



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# 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 includes to an array of Regexp
  @includes = @includes.collect {|pattern| Regexp::new(pattern)}

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