fluent-plugin-detect-exceptions 0.0.13 → 0.0.15

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.
@@ -22,45 +22,47 @@ class DetectExceptionsOutputTest < Test::Unit::TestCase
22
22
  Fluent::Test.setup
23
23
  end
24
24
 
25
- CONFIG = <<END.freeze
26
- remove_tag_prefix prefix
27
- END
25
+ CONFIG = <<~END_CONFIG.freeze
26
+ remove_tag_prefix prefix
27
+ END_CONFIG
28
28
 
29
29
  DEFAULT_TAG = 'prefix.test.tag'.freeze
30
30
 
31
+ DEFAULT_TAG_STRIPPED = 'test.tag'.freeze
32
+
31
33
  ARBITRARY_TEXT = 'This line is not an exception.'.freeze
32
34
 
33
- JAVA_EXC = <<END.freeze
34
- SomeException: foo
35
- at bar
36
- Caused by: org.AnotherException
37
- at bar2
38
- at bar3
39
- END
40
-
41
- PHP_EXC = <<END.freeze
42
- exception 'Exception' with message 'Custom exception' in /home/joe/work/test-php/test.php:5
43
- Stack trace:
44
- #0 /home/joe/work/test-php/test.php(9): func1()
45
- #1 /home/joe/work/test-php/test.php(13): func2()
46
- #2 {main}
47
- END
48
-
49
- PYTHON_EXC = <<END.freeze
50
- Traceback (most recent call last):
51
- File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1535, in __call__
52
- rv = self.handle_exception(request, response, e)
53
- Exception: ('spam', 'eggs')
54
- END
55
-
56
- RUBY_EXC = <<END.freeze
57
- examble.rb:18:in `thrower': An error has occurred. (RuntimeError)
58
- from examble.rb:14:in `caller'
59
- from examble.rb:10:in `helper'
60
- from examble.rb:6:in `writer'
61
- from examble.rb:2:in `runner'
62
- from examble.rb:21:in `<main>'
63
- END
35
+ JAVA_EXC = <<~END_JAVA.freeze
36
+ SomeException: foo
37
+ at bar
38
+ Caused by: org.AnotherException
39
+ at bar2
40
+ at bar3
41
+ END_JAVA
42
+
43
+ PHP_EXC = <<~END_PHP.freeze
44
+ exception 'Exception' with message 'Custom exception' in /home/joe/work/test-php/test.php:5
45
+ Stack trace:
46
+ #0 /home/joe/work/test-php/test.php(9): func1()
47
+ #1 /home/joe/work/test-php/test.php(13): func2()
48
+ #2 {main}
49
+ END_PHP
50
+
51
+ PYTHON_EXC = <<~END_PYTHON.freeze
52
+ Traceback (most recent call last):
53
+ File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1535, in __call__
54
+ rv = self.handle_exception(request, response, e)
55
+ Exception: ('spam', 'eggs')
56
+ END_PYTHON
57
+
58
+ RUBY_EXC = <<~END_RUBY.freeze
59
+ examble.rb:18:in `thrower': An error has occurred. (RuntimeError)
60
+ from examble.rb:14:in `caller'
61
+ from examble.rb:10:in `helper'
62
+ from examble.rb:6:in `writer'
63
+ from examble.rb:2:in `runner'
64
+ from examble.rb:21:in `<main>'
65
+ END_RUBY
64
66
 
65
67
  def create_driver(conf = CONFIG, tag = DEFAULT_TAG)
66
68
  d = Fluent::Test::OutputTestDriver.new(Fluent::DetectExceptionsOutput, tag)
@@ -74,11 +76,22 @@ END
74
76
  log_entry
75
77
  end
76
78
 
77
- def feed_lines(driver, t, *messages, stream: nil)
79
+ def feed_lines_without_line_breaks(driver, timestamp, *messages, stream: nil)
80
+ count = 0
81
+ messages.each do |m|
82
+ m.each_line do |line|
83
+ line.delete!("\n")
84
+ driver.emit(log_entry(line, count, stream), timestamp + count)
85
+ count += 1
86
+ end
87
+ end
88
+ end
89
+
90
+ def feed_lines(driver, timestamp, *messages, stream: nil)
78
91
  count = 0
79
92
  messages.each do |m|
80
93
  m.each_line do |line|
81
- driver.emit(log_entry(line, count, stream), t + count)
94
+ driver.emit(log_entry(line, count, stream), timestamp + count)
82
95
  count += 1
83
96
  end
84
97
  end
@@ -91,11 +104,11 @@ END
91
104
  end
92
105
  end
93
106
 
94
- def make_logs(t, *messages, stream: nil)
107
+ def make_logs(timestamp, *messages, stream: nil)
95
108
  count = 0
96
109
  logs = []
97
110
  messages.each do |m|
98
- logs << [t + count, log_entry(m, count, stream)]
111
+ logs << [timestamp + count, log_entry(m, count, stream)]
99
112
  count += m.lines.count
100
113
  end
101
114
  logs
@@ -125,7 +138,9 @@ END
125
138
  }
126
139
 
127
140
  test_cases.each do |language, exception|
128
- cfg = "languages #{language}"
141
+ cfg = %(
142
+ #{CONFIG}
143
+ languages #{language})
129
144
  d = create_driver(cfg)
130
145
  t = Time.now.to_i
131
146
 
@@ -133,7 +148,7 @@ END
133
148
  single_line_exception = exception.gsub("\n", '\\n')
134
149
 
135
150
  # There is a nested exception within the body, we should ignore those!
136
- json_line_with_exception = {
151
+ json_with_exception = {
137
152
  'timestamp' => {
138
153
  'nanos' => 998_152_494,
139
154
  'seconds' => 1_496_420_064
@@ -141,8 +156,9 @@ END
141
156
  'message' => single_line_exception,
142
157
  'thread' => 139_658_267_147_048,
143
158
  'severity' => 'ERROR'
144
- }.to_json + "\n"
145
- json_line_without_exception = {
159
+ }
160
+ json_line_with_exception = "#{json_with_exception.to_json}\n"
161
+ json_without_exception = {
146
162
  'timestamp' => {
147
163
  'nanos' => 5_990_266,
148
164
  'seconds' => 1_496_420_065
@@ -150,18 +166,19 @@ END
150
166
  'message' => 'next line',
151
167
  'thread' => 139_658_267_147_048,
152
168
  'severity' => 'INFO'
153
- }.to_json + "\n"
169
+ }
170
+ json_line_without_exception = "#{json_without_exception.to_json}\n"
154
171
 
155
172
  router_mock = flexmock('router')
156
173
 
157
174
  # Validate that each line received is emitted separately as expected.
158
175
  router_mock.should_receive(:emit)
159
- .once.with(DEFAULT_TAG, Integer,
176
+ .once.with(DEFAULT_TAG_STRIPPED, Integer,
160
177
  'message' => json_line_with_exception,
161
178
  'count' => 0)
162
179
 
163
180
  router_mock.should_receive(:emit)
164
- .once.with(DEFAULT_TAG, Integer,
181
+ .once.with(DEFAULT_TAG_STRIPPED, Integer,
165
182
  'message' => json_line_without_exception,
166
183
  'count' => 1)
167
184
 
@@ -174,7 +191,9 @@ END
174
191
  end
175
192
 
176
193
  def test_single_language_config
177
- cfg = 'languages java'
194
+ cfg = %(
195
+ #{CONFIG}
196
+ languages java)
178
197
  d = create_driver(cfg)
179
198
  t = Time.now.to_i
180
199
  d.run do
@@ -185,7 +204,9 @@ END
185
204
  end
186
205
 
187
206
  def test_multi_language_config
188
- cfg = 'languages python, java'
207
+ cfg = %(
208
+ #{CONFIG}
209
+ languages python, java)
189
210
  d = create_driver(cfg)
190
211
  t = Time.now.to_i
191
212
  d.run do
@@ -196,7 +217,9 @@ END
196
217
  end
197
218
 
198
219
  def test_split_exception_after_timeout
199
- cfg = 'multiline_flush_interval 1'
220
+ cfg = %(
221
+ #{CONFIG}
222
+ multiline_flush_interval 1)
200
223
  d = create_driver(cfg)
201
224
  t1 = 0
202
225
  t2 = 0
@@ -224,7 +247,13 @@ END
224
247
  feed_lines(d, t2, " at x\n at y\n")
225
248
  d.instance.before_shutdown
226
249
  end
227
- assert_equal(make_logs(t1, JAVA_EXC + " at x\n at y\n"), d.events)
250
+ assert_equal(make_logs(t1, "#{JAVA_EXC} at x\n at y\n"), d.events)
251
+ end
252
+
253
+ def test_remove_tag_prefix_is_required
254
+ cfg = ''
255
+ e = assert_raises(Fluent::ConfigError) { create_driver(cfg) }
256
+ assert_match(/remove_tag_prefix/, e.message)
228
257
  end
229
258
 
230
259
  def get_out_tags(remove_tag_prefix, original_tag)
@@ -243,8 +272,42 @@ END
243
272
  assert_equal(['prefix.plus.rest.of.the.tag'], tags)
244
273
  end
245
274
 
275
+ def test_force_line_breaks_false
276
+ cfg = %(
277
+ #{CONFIG}
278
+ force_line_breaks true)
279
+ d = create_driver(cfg)
280
+ t = Time.now.to_i
281
+ d.run do
282
+ feed_lines(d, t, JAVA_EXC)
283
+ end
284
+ expected = JAVA_EXC
285
+ assert_equal(make_logs(t, *expected), d.events)
286
+ end
287
+
288
+ def test_force_line_breaks_true
289
+ cfg = %(
290
+ #{CONFIG}
291
+ force_line_breaks true)
292
+ d = create_driver(cfg)
293
+ t = Time.now.to_i
294
+ d.run do
295
+ feed_lines_without_line_breaks(d, t, JAVA_EXC)
296
+ end
297
+ # Expected: the first two lines of the exception are buffered and combined.
298
+ # Then the max_lines setting kicks in and the rest of the Python exception
299
+ # is logged line-by-line (since it's not an exception stack in itself).
300
+ # For the following Java stack trace, the two lines of the first exception
301
+ # are buffered and combined. So are the first two lines of the second
302
+ # exception. Then the rest is logged line-by-line.
303
+ expected = JAVA_EXC.chomp
304
+ assert_equal(make_logs(t, *expected), d.events)
305
+ end
306
+
246
307
  def test_flush_after_max_lines
247
- cfg = 'max_lines 2'
308
+ cfg = %(
309
+ #{CONFIG}
310
+ max_lines 2)
248
311
  d = create_driver(cfg)
249
312
  t = Time.now.to_i
250
313
  d.run do
@@ -256,22 +319,24 @@ END
256
319
  # For the following Java stack trace, the two lines of the first exception
257
320
  # are buffered and combined. So are the first two lines of the second
258
321
  # exception. Then the rest is logged line-by-line.
259
- expected = [PYTHON_EXC.lines[0..1].join] + PYTHON_EXC.lines[2..-1] + \
322
+ expected = [PYTHON_EXC.lines[0..1].join] + PYTHON_EXC.lines[2..] + \
260
323
  [JAVA_EXC.lines[0..1].join] + [JAVA_EXC.lines[2..3].join] + \
261
- JAVA_EXC.lines[4..-1]
324
+ JAVA_EXC.lines[4..]
262
325
  assert_equal(make_logs(t, *expected), d.events)
263
326
  end
264
327
 
265
328
  def test_separate_streams
266
- cfg = 'stream stream'
329
+ cfg = %(
330
+ #{CONFIG}
331
+ stream stream)
267
332
  d = create_driver(cfg)
268
333
  t = Time.now.to_i
269
334
  d.run do
270
335
  feed_lines(d, t, JAVA_EXC.lines[0], stream: 'java')
271
336
  feed_lines(d, t, PYTHON_EXC.lines[0..1].join, stream: 'python')
272
- feed_lines(d, t, JAVA_EXC.lines[1..-1].join, stream: 'java')
337
+ feed_lines(d, t, JAVA_EXC.lines[1..].join, stream: 'java')
273
338
  feed_lines(d, t, JAVA_EXC, stream: 'java')
274
- feed_lines(d, t, PYTHON_EXC.lines[2..-1].join, stream: 'python')
339
+ feed_lines(d, t, PYTHON_EXC.lines[2..].join, stream: 'python')
275
340
  feed_lines(d, t, 'something else', stream: 'java')
276
341
  end
277
342
  # Expected: the Python and the Java exceptions are handled separately
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-detect-exceptions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.13
4
+ version: 0.0.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stackdriver Agents
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-04 00:00:00.000000000 Z
11
+ date: 2023-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd
@@ -25,61 +25,61 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0.10'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rake
28
+ name: flexmock
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.3'
33
+ version: '2.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.3'
40
+ version: '2.0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rubocop
42
+ name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '='
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.42.0
47
+ version: '10.3'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '='
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.42.0
54
+ version: '10.3'
55
55
  - !ruby/object:Gem::Dependency
56
- name: test-unit
56
+ name: rubocop
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - '='
60
60
  - !ruby/object:Gem::Version
61
- version: '3.0'
61
+ version: 1.48.1
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - '='
67
67
  - !ruby/object:Gem::Version
68
- version: '3.0'
68
+ version: 1.48.1
69
69
  - !ruby/object:Gem::Dependency
70
- name: flexmock
70
+ name: test-unit
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '2.0'
75
+ version: '3.0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '2.0'
82
+ version: '3.0'
83
83
  description: |2
84
84
  Fluentd output plugin which detects exception stack traces in a stream of
85
85
  JSON log messages and combines all single-line messages that belong to the
@@ -116,14 +116,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
116
116
  requirements:
117
117
  - - ">="
118
118
  - !ruby/object:Gem::Version
119
- version: '2.0'
119
+ version: '2.6'
120
120
  required_rubygems_version: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
125
  requirements: []
126
- rubygems_version: 3.0.4
126
+ rubygems_version: 3.1.6
127
127
  signing_key:
128
128
  specification_version: 4
129
129
  summary: fluentd output plugin for combining stack traces as multi-line JSON logs