logstash-codec-multiline 3.1.0 → 3.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a4ecbf8730e688adbacb1af57c98f7c5105b5677337b140a22b6ccb41e1468ea
4
- data.tar.gz: 299167720ec0457af53b7f118b6e55bd6c078f6ac1b8e4978ca68872a04cbc7c
3
+ metadata.gz: 3e46243c32a2f87ede3a266ee117dd89086a5a48454813d8979fe04a25454692
4
+ data.tar.gz: fedc22e883fd7e842a4de3f8cf599268c57f7b1d7de06a40a5d5fb27cd86febb
5
5
  SHA512:
6
- metadata.gz: 798b7fe3f963ade7578c655a00ba2ba7ea602dced4e463b170d8d7bf8b9e0585bedda761f9ee5bbbcb8026d99e0cbc3dc22bdfc19abe063c5d3716c2b8e0fd03
7
- data.tar.gz: b4758f3f75e0ad1e470800aff9ccf353f8f4493cbcd6b30f687ef3fa74973e5baf0aba65a25450b83b3269879065ab5878141914dd3c35998e0bad4ca631b8bd
6
+ metadata.gz: faa8892c245b03438c1cd63f5812b8e5c80c145b55fd437e8eb3ab82baf4bb94f23754d720c40016fc8bfecf23a6eae7cbb1c1ab4e0a34f5a5a4e37efe1d8fec
7
+ data.tar.gz: 415515b5dc715d12df012febfc9a91cf986d8c05fd73f975bc284807bbd034e436168a6d624299bc53aea5417bae4d391f10b97b32a07b0b43be7ac197de8a7a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 3.1.2
2
+ - Fix: periodic runner fails to stop and prevent pipeline shutdown [#72](https://github.com/logstash-plugins/logstash-codec-multiline/pull/72)
3
+
4
+ ## 3.1.1
5
+ - Fix: avoid reusing per-identity codec instances for differing identities. Removes a very minor optimization so that stateful codecs like CSV can work reliably [#70](https://github.com/logstash-plugins/logstash-codec-multiline/pull/70)
6
+
1
7
  ## 3.1.0
2
8
  - Feat: ECS compatibility [#69](https://github.com/logstash-plugins/logstash-codec-multiline/pull/69)
3
9
 
@@ -42,15 +42,20 @@ module LogStash module Codecs class IdentityMapCodec
42
42
  def initialize(listener, interval, method_symbol)
43
43
  @listener, @interval = listener, interval
44
44
  @method_symbol = method_symbol
45
- @running = Concurrent::AtomicBoolean.new(false)
45
+ @running = Concurrent::AtomicBoolean.new(true)
46
46
  end
47
47
 
48
+ # The goal of periodic runner is to have a single thread to do clean up / auto flush
49
+ # This method is expected to access by a single thread,
50
+ # otherwise, multiple Thread.start could create more than one periodic runner
48
51
  def start
49
- return self if running?
50
- @running.make_true
52
+ return self unless running?
53
+ return self if running? && !@thread.nil?
54
+
51
55
  @thread = Thread.start do
52
56
  class_name = @listener.class.name.split('::').last # IdentityMapCodec
53
57
  LogStash::Util.set_thread_name("#{class_name}##{@method_symbol}")
58
+ @listener.logger.debug("Start periodic runner")
54
59
 
55
60
  while running? do
56
61
  sleep @interval
@@ -67,9 +72,11 @@ module LogStash module Codecs class IdentityMapCodec
67
72
  end
68
73
 
69
74
  def stop
70
- return if !running?
75
+ return unless running?
76
+
77
+ @listener.logger.debug("Stop periodic runner")
71
78
  @running.make_false
72
- while @thread.alive?
79
+ while @thread&.alive?
73
80
  begin
74
81
  @thread.wakeup
75
82
  rescue ThreadError
@@ -290,6 +297,7 @@ module LogStash module Codecs class IdentityMapCodec
290
297
  end
291
298
 
292
299
  def codec_without_usage_update(identity)
300
+ return base_codec if identity.nil? # mirror optimization in `stream_codec`
293
301
  find_codec_value(identity).codec
294
302
  end
295
303
 
@@ -312,7 +320,7 @@ module LogStash module Codecs class IdentityMapCodec
312
320
  def record_codec_usage(identity)
313
321
  check_map_limits
314
322
  # only start the cleaner if streams are in use
315
- # continuous calls to start are OK
323
+ # continuous calls to start are OK if this codec method is accessed by a single thread
316
324
  cleaner.start
317
325
  auto_flusher.start
318
326
  compo = find_codec_value(identity)
@@ -336,7 +344,7 @@ module LogStash module Codecs class IdentityMapCodec
336
344
  end
337
345
 
338
346
  def codec_builder(hash, k)
339
- codec = hash.empty? ? @base_codec : @base_codec.clone
347
+ codec = @base_codec.clone
340
348
  codec.use_mapper_auto_flush if using_mapped_auto_flush?
341
349
  compo = CodecValue.new(codec).tap do |o|
342
350
  now = Time.now
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-codec-multiline'
4
- s.version = '3.1.0'
4
+ s.version = '3.1.2'
5
5
  s.licenses = ['Apache License (2.0)']
6
6
  s.summary = "Merges multiline messages into a single event"
7
7
  s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
@@ -29,7 +29,8 @@ describe LogStash::Codecs::IdentityMapCodec do
29
29
  let(:stream1) { nil }
30
30
 
31
31
  it "transparently refers to the original codec" do
32
- expect(codec).to eql(codec1)
32
+ resolved_codec = demuxer.codec_without_usage_update(stream1)
33
+ expect(resolved_codec).to eq(codec)
33
34
  end
34
35
  end
35
36
 
@@ -37,8 +38,8 @@ describe LogStash::Codecs::IdentityMapCodec do
37
38
 
38
39
  before { demuxer.decode(arg1, stream1) }
39
40
 
40
- it "the first identity refers to the original codec" do
41
- expect(codec).to eql(codec1)
41
+ it "the first identity refers to a copy of original codec" do
42
+ expect(codec1).to_not eql(codec)
42
43
  end
43
44
  end
44
45
 
@@ -212,8 +213,11 @@ describe LogStash::Codecs::IdentityMapCodec do
212
213
  let(:demuxer) { described_class.new(codec).evict_timeout(1).cleaner_interval(1) }
213
214
  it "the cleaner evicts the codec and flushes it first" do
214
215
  demuxer.decode(Object.new, "stream1"){|*| 42}
216
+ mapped_codec = demuxer.codec_without_usage_update("stream1") # get before eviction
217
+
215
218
  sleep(2.1)
216
- expect(codec.trace_for(:flush)).to eq(42)
219
+
220
+ expect(mapped_codec.trace_for(:flush)).to eq(42)
217
221
  expect(demuxer.identity_map.keys).not_to include("stream1")
218
222
  end
219
223
  end
@@ -227,9 +231,12 @@ describe LogStash::Codecs::IdentityMapCodec do
227
231
  end
228
232
  it "the cleaner evicts the codec and flushes it first using the eviction_block" do
229
233
  demuxer.decode(Object.new, "stream1"){|*| 42}
234
+ mapped_codec = demuxer.codec_without_usage_update("stream1") # get before eviction
235
+
230
236
  sleep(2.1)
231
- expect(codec.trace_for(:flush)).to eq(24)
232
- expect(demuxer.identity_map.keys).not_to include("stream1")
237
+
238
+ expect(mapped_codec.trace_for(:flush)).to eq(24)
239
+ expect(demuxer.identity_map.keys).to_not include("stream1")
233
240
  end
234
241
  end
235
242
  end
@@ -251,7 +258,9 @@ describe LogStash::Codecs::IdentityMapCodec do
251
258
  it "no events are generated (the line is buffered)" do
252
259
  expect(imc.identity_count).to eq(1)
253
260
  expect(queue.size).to eq(0)
254
- expect(mlc.internal_buffer[0]).to eq("foo")
261
+
262
+ mapped_codec = imc.codec_without_usage_update(identity)
263
+ expect(mapped_codec.internal_buffer[0]).to eq("foo")
255
264
  end
256
265
  end
257
266
 
@@ -290,3 +299,79 @@ describe LogStash::Codecs::IdentityMapCodec do
290
299
  end
291
300
  end
292
301
  end
302
+
303
+ describe LogStash::Codecs::IdentityMapCodec::PeriodicRunner do
304
+ let(:listener) do
305
+ double('Listener', logger: double('Logger').as_null_object,
306
+ some_method: double('method_symbol').as_null_object)
307
+ end
308
+ let(:interval) { 1 }
309
+ let(:method_symbol) { :some_method }
310
+ subject(:runner) { described_class.new(listener, interval, method_symbol) }
311
+
312
+ before(:all) do
313
+ Thread.abort_on_exception = true
314
+ end
315
+
316
+ describe "normal shutdown" do
317
+ it "starts first and stops successfully" do
318
+ start_thread = Thread.start do
319
+ runner.start
320
+ end
321
+
322
+ stop_thread = Thread.start do
323
+ sleep(1)
324
+ runner.stop
325
+ end
326
+
327
+ start_thread.join
328
+ stop_thread.join
329
+
330
+ expect(runner.instance_variable_get('@listener')).to be_nil
331
+ end
332
+ end
333
+
334
+ describe "race condition" do
335
+ let(:atomic_bool) { Concurrent::AtomicBoolean.new(true) }
336
+ let(:running) { double('AtomicBooleanStub') }
337
+
338
+ before do
339
+ allow(running).to receive(:make_true) do
340
+ atomic_bool.make_true
341
+ end
342
+
343
+ allow(running).to receive(:make_false) do
344
+ atomic_bool.make_false
345
+ sleep(2)
346
+ end
347
+
348
+ allow(running).to receive(:true?) do
349
+ atomic_bool.true?
350
+ end
351
+ end
352
+
353
+ before :each do
354
+ runner.instance_variable_set('@running', running)
355
+ end
356
+
357
+ it "starts several times and stops successfully" do
358
+ start_thread = Thread.start do
359
+ 5.times do
360
+ runner.start
361
+ sleep(1)
362
+ end
363
+ end
364
+
365
+ stop_thread = Thread.start do
366
+ sleep(1) # give time to runner start
367
+ runner.stop
368
+ end
369
+
370
+ start_thread.join
371
+ stop_thread.join
372
+
373
+ expect(runner.instance_variable_get('@listener')).to be_nil
374
+ expect(runner.instance_variable_get('@thread').alive?).to be_falsey
375
+ end
376
+ end
377
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-codec-multiline
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 3.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-27 00:00:00.000000000 Z
11
+ date: 2024-04-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -20,8 +20,8 @@ dependencies:
20
20
  - !ruby/object:Gem::Version
21
21
  version: '2.99'
22
22
  name: logstash-core-plugin-api
23
- type: :runtime
24
23
  prerelease: false
24
+ type: :runtime
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
@@ -37,8 +37,8 @@ dependencies:
37
37
  - !ruby/object:Gem::Version
38
38
  version: '1.3'
39
39
  name: logstash-mixin-ecs_compatibility_support
40
- type: :runtime
41
40
  prerelease: false
41
+ type: :runtime
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
@@ -51,8 +51,8 @@ dependencies:
51
51
  - !ruby/object:Gem::Version
52
52
  version: '1.0'
53
53
  name: logstash-mixin-event_support
54
- type: :runtime
55
54
  prerelease: false
55
+ type: :runtime
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - "~>"
@@ -65,8 +65,8 @@ dependencies:
65
65
  - !ruby/object:Gem::Version
66
66
  version: '0'
67
67
  name: logstash-patterns-core
68
- type: :runtime
69
68
  prerelease: false
69
+ type: :runtime
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - ">="
@@ -79,8 +79,8 @@ dependencies:
79
79
  - !ruby/object:Gem::Version
80
80
  version: 0.11.1
81
81
  name: jls-grok
82
- type: :runtime
83
82
  prerelease: false
83
+ type: :runtime
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - "~>"
@@ -93,8 +93,8 @@ dependencies:
93
93
  - !ruby/object:Gem::Version
94
94
  version: '0'
95
95
  name: concurrent-ruby
96
- type: :runtime
97
96
  prerelease: false
97
+ type: :runtime
98
98
  version_requirements: !ruby/object:Gem::Requirement
99
99
  requirements:
100
100
  - - ">="
@@ -107,8 +107,8 @@ dependencies:
107
107
  - !ruby/object:Gem::Version
108
108
  version: '0'
109
109
  name: logstash-devutils
110
- type: :development
111
110
  prerelease: false
111
+ type: :development
112
112
  version_requirements: !ruby/object:Gem::Requirement
113
113
  requirements:
114
114
  - - ">="
@@ -121,8 +121,8 @@ dependencies:
121
121
  - !ruby/object:Gem::Version
122
122
  version: '0'
123
123
  name: insist
124
- type: :development
125
124
  prerelease: false
125
+ type: :development
126
126
  version_requirements: !ruby/object:Gem::Requirement
127
127
  requirements:
128
128
  - - ">="
@@ -173,7 +173,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
173
173
  - !ruby/object:Gem::Version
174
174
  version: '0'
175
175
  requirements: []
176
- rubygems_version: 3.0.6
176
+ rubygems_version: 3.2.33
177
177
  signing_key:
178
178
  specification_version: 4
179
179
  summary: Merges multiline messages into a single event