logstash-codec-multiline 3.1.0 → 3.1.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/lib/logstash/codecs/identity_map_codec.rb +15 -7
- data/logstash-codec-multiline.gemspec +1 -1
- data/spec/codecs/identity_map_codec_spec.rb +92 -7
- metadata +11 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e46243c32a2f87ede3a266ee117dd89086a5a48454813d8979fe04a25454692
|
4
|
+
data.tar.gz: fedc22e883fd7e842a4de3f8cf599268c57f7b1d7de06a40a5d5fb27cd86febb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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(
|
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
|
50
|
-
|
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
|
75
|
+
return unless running?
|
76
|
+
|
77
|
+
@listener.logger.debug("Stop periodic runner")
|
71
78
|
@running.make_false
|
72
|
-
while @thread
|
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 =
|
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.
|
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
|
-
|
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
|
41
|
-
expect(
|
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
|
-
|
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
|
-
|
232
|
-
expect(
|
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
|
-
|
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.
|
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:
|
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.
|
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
|