fluent-plugin-detect-ft-memb-exceptions 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,212 @@
1
+ # Copyright 2016 Google Inc. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require_relative '../helper'
16
+ require 'fluent/plugin/out_detect_exceptions'
17
+
18
+ class DetectExceptionsOutputTest < Test::Unit::TestCase
19
+ def setup
20
+ Fluent::Test.setup
21
+ end
22
+
23
+ CONFIG = <<END.freeze
24
+ remove_tag_prefix prefix
25
+ END
26
+
27
+ DEFAULT_TAG = 'prefix.test.tag'.freeze
28
+
29
+ ARBITRARY_TEXT = 'This line is not an exception.'.freeze
30
+
31
+ JAVA_EXC = <<END.freeze
32
+ SomeException: foo
33
+ at bar
34
+ Caused by: org.AnotherException
35
+ at bar2
36
+ at bar3
37
+ END
38
+
39
+ PYTHON_EXC = <<END.freeze
40
+ Traceback (most recent call last):
41
+ File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1535, in __call__
42
+ rv = self.handle_exception(request, response, e)
43
+ Exception: ('spam', 'eggs')
44
+ END
45
+
46
+ def create_driver(conf = CONFIG, tag = DEFAULT_TAG)
47
+ d = Fluent::Test::OutputTestDriver.new(Fluent::DetectExceptionsOutput, tag)
48
+ d.configure(conf)
49
+ d
50
+ end
51
+
52
+ def log_entry(message, count, stream)
53
+ log_entry = { 'message' => message, 'count' => count }
54
+ log_entry['stream'] = stream unless stream.nil?
55
+ log_entry
56
+ end
57
+
58
+ def feed_lines(driver, t, *messages, stream: nil)
59
+ count = 0
60
+ messages.each do |m|
61
+ m.each_line do |line|
62
+ driver.emit(log_entry(line, count, stream), t + count)
63
+ count += 1
64
+ end
65
+ end
66
+ end
67
+
68
+ def run_driver(driver, *messages)
69
+ t = Time.now.to_i
70
+ driver.run do
71
+ feed_lines(driver, t, *messages)
72
+ end
73
+ end
74
+
75
+ def make_logs(t, *messages, stream: nil)
76
+ count = 0
77
+ logs = []
78
+ messages.each do |m|
79
+ logs << [t + count, log_entry(m, count, stream)]
80
+ count += m.lines.count
81
+ end
82
+ logs
83
+ end
84
+
85
+ def test_configure
86
+ assert_nothing_raised do
87
+ create_driver
88
+ end
89
+ end
90
+
91
+ def test_exception_detection
92
+ d = create_driver
93
+ t = Time.now.to_i
94
+ messages = [ARBITRARY_TEXT, JAVA_EXC, ARBITRARY_TEXT]
95
+ d.run do
96
+ feed_lines(d, t, *messages)
97
+ end
98
+ assert_equal(make_logs(t, *messages), d.events)
99
+ end
100
+
101
+ def test_single_language_config
102
+ cfg = 'languages java'
103
+ d = create_driver(cfg)
104
+ t = Time.now.to_i
105
+ d.run do
106
+ feed_lines(d, t, ARBITRARY_TEXT, JAVA_EXC, PYTHON_EXC)
107
+ end
108
+ expected = ARBITRARY_TEXT.lines + [JAVA_EXC] + PYTHON_EXC.lines
109
+ assert_equal(make_logs(t, *expected), d.events)
110
+ end
111
+
112
+ def test_multi_language_config
113
+ cfg = 'languages python, java'
114
+ d = create_driver(cfg)
115
+ t = Time.now.to_i
116
+ d.run do
117
+ feed_lines(d, t, ARBITRARY_TEXT, JAVA_EXC, PYTHON_EXC)
118
+ end
119
+ expected = ARBITRARY_TEXT.lines + [JAVA_EXC] + [PYTHON_EXC]
120
+ assert_equal(make_logs(t, *expected), d.events)
121
+ end
122
+
123
+ def test_split_exception_after_timeout
124
+ cfg = 'multiline_flush_interval 1'
125
+ d = create_driver(cfg)
126
+ t1 = 0
127
+ t2 = 0
128
+ d.run do
129
+ t1 = Time.now.to_i
130
+ feed_lines(d, t1, JAVA_EXC)
131
+ sleep 2
132
+ t2 = Time.now.to_i
133
+ feed_lines(d, t2, " at x\n at y\n")
134
+ end
135
+ assert_equal(make_logs(t1, JAVA_EXC) +
136
+ make_logs(t2, " at x\n", " at y\n"),
137
+ d.events)
138
+ end
139
+
140
+ def test_do_not_split_exception_after_pause
141
+ d = create_driver
142
+ t1 = 0
143
+ t2 = 0
144
+ d.run do
145
+ t1 = Time.now.to_i
146
+ feed_lines(d, t1, JAVA_EXC)
147
+ sleep 1
148
+ t2 = Time.now.to_i
149
+ feed_lines(d, t2, " at x\n at y\n")
150
+ d.instance.before_shutdown
151
+ end
152
+ assert_equal(make_logs(t1, JAVA_EXC + " at x\n at y\n"), d.events)
153
+ end
154
+
155
+ def get_out_tags(remove_tag_prefix, original_tag)
156
+ cfg = "remove_tag_prefix #{remove_tag_prefix}"
157
+ d = create_driver(cfg, original_tag)
158
+ run_driver(d, ARBITRARY_TEXT, JAVA_EXC, ARBITRARY_TEXT)
159
+ d.emits.collect { |e| e[0] }.sort.uniq
160
+ end
161
+
162
+ def test_remove_tag_prefix
163
+ tags = get_out_tags('prefix.plus', 'prefix.plus.rest.of.the.tag')
164
+ assert_equal(['rest.of.the.tag'], tags)
165
+ tags = get_out_tags('prefix.pl', 'prefix.plus.rest.of.the.tag')
166
+ assert_equal(['prefix.plus.rest.of.the.tag'], tags)
167
+ tags = get_out_tags('does.not.occur', 'prefix.plus.rest.of.the.tag')
168
+ assert_equal(['prefix.plus.rest.of.the.tag'], tags)
169
+ end
170
+
171
+ def test_flush_after_max_lines
172
+ cfg = 'max_lines 2'
173
+ d = create_driver(cfg)
174
+ t = Time.now.to_i
175
+ d.run do
176
+ feed_lines(d, t, PYTHON_EXC, JAVA_EXC)
177
+ end
178
+ # Expected: the first two lines of the exception are buffered and combined.
179
+ # Then the max_lines setting kicks in and the rest of the Python exception
180
+ # is logged line-by-line (since it's not an exception stack in itself).
181
+ # For the following Java stack trace, the two lines of the first exception
182
+ # are buffered and combined. So are the first two lines of the second
183
+ # exception. Then the rest is logged line-by-line.
184
+ expected = [PYTHON_EXC.lines[0..1].join] + PYTHON_EXC.lines[2..-1] + \
185
+ [JAVA_EXC.lines[0..1].join] + [JAVA_EXC.lines[2..3].join] + \
186
+ JAVA_EXC.lines[4.. -1]
187
+ assert_equal(make_logs(t, *expected), d.events)
188
+ end
189
+
190
+ def test_separate_streams
191
+ cfg = 'stream stream'
192
+ d = create_driver(cfg)
193
+ t = Time.now.to_i
194
+ d.run do
195
+ feed_lines(d, t, JAVA_EXC.lines[0], stream: 'java')
196
+ feed_lines(d, t, PYTHON_EXC.lines[0..1].join, stream: 'python')
197
+ feed_lines(d, t, JAVA_EXC.lines[1..-1].join, stream: 'java')
198
+ feed_lines(d, t, JAVA_EXC, stream: 'java')
199
+ feed_lines(d, t, PYTHON_EXC.lines[2..-1].join, stream: 'python')
200
+ feed_lines(d, t, 'something else', stream: 'java')
201
+ end
202
+ # Expected: the Python and the Java exceptions are handled separately
203
+ # because they belong to different streams.
204
+ # Note that the Java exception is only detected when 'something else'
205
+ # is processed.
206
+ expected = make_logs(t, JAVA_EXC, stream: 'java') +
207
+ make_logs(t, PYTHON_EXC, stream: 'python') +
208
+ make_logs(t, JAVA_EXC, stream: 'java') +
209
+ make_logs(t, 'something else', stream: 'java')
210
+ assert_equal(expected, d.events)
211
+ end
212
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-detect-ft-memb-exceptions
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Naomi stern
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-10-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fluentd
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.10'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 0.42.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 0.42.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: test-unit
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: |2
70
+ Fluentd output plugin which detects ft membership specific exception stack traces in a stream of
71
+ JSON log messages and combines all single-line messages that belong to the
72
+ same stack trace into one multi-line message.
73
+ This is an adaption of an official Google Ruby gem.
74
+ email:
75
+ - sally.dixon@ft.com
76
+ executables: []
77
+ extensions: []
78
+ extra_rdoc_files: []
79
+ files:
80
+ - CONTRIBUTING
81
+ - Gemfile
82
+ - Gemfile.lock
83
+ - LICENSE
84
+ - README.rdoc
85
+ - Rakefile
86
+ - fluent-plugin-detect-ft-memb-exceptions.gemspec
87
+ - lib/fluent/plugin/exception_detector.rb
88
+ - lib/fluent/plugin/out_detect_exceptions.rb
89
+ - pkg/fluent-plugin-detect-memb-exceptions-0.0.3.gem
90
+ - test/helper.rb
91
+ - test/plugin/bench_exception_detector.rb
92
+ - test/plugin/test_exception_detector.rb
93
+ - test/plugin/test_out_detect_exceptions.rb
94
+ homepage: https://github.com/Financial-Times/fluent-plugin-detect-exceptions
95
+ licenses:
96
+ - Apache-2.0
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '2.0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.5.1
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: fluentd output plugin for combining stack traces as multi-line JSON logs
118
+ test_files:
119
+ - test/helper.rb
120
+ - test/plugin/bench_exception_detector.rb
121
+ - test/plugin/test_exception_detector.rb
122
+ - test/plugin/test_out_detect_exceptions.rb