logstash-codec-multiline 2.0.2 → 2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -1
- data/README.md +3 -0
- data/lib/logstash/codecs/identity_map_codec.rb +251 -0
- data/lib/logstash/codecs/multiline.rb +3 -3
- data/logstash-codec-multiline.gemspec +1 -1
- data/spec/codecs/identity_map_codec_spec.rb +208 -0
- metadata +30 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b89e4a5a454c8bc979aca1a959c06ad2d65e29bc
|
4
|
+
data.tar.gz: 3eff2f29480107e6212eec95c096c18b3f82b55e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d7eb64acd24053b8ce18bfe111a5ab2917f5a41a3e979879ee1313bc64ffcf744ed85d11ade9843167bfe86579a34b8015d62b5fa0ee85d1356a1ac3360d246e
|
7
|
+
data.tar.gz: 36580542f95f5b66d042f8a2e6ed69064b49a1e2c1e2400f0aa49bfeb8f54ec510b99646fc1758d3a9887fb41862d1fd7ad44c30cbf3be721bf73323221953af
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
## 2.0.3
|
2
|
+
- Add pseudo codec IdentityMapCodec. Support class for identity based multiline processing.
|
3
|
+
|
1
4
|
## 2.0.0
|
2
|
-
- Plugins were updated to follow the new shutdown semantic, this mainly allows Logstash to instruct input plugins to terminate gracefully,
|
5
|
+
- Plugins were updated to follow the new shutdown semantic, this mainly allows Logstash to instruct input plugins to terminate gracefully,
|
3
6
|
instead of using Thread.raise on the plugins' threads. Ref: https://github.com/elastic/logstash/pull/3895
|
4
7
|
- Dependency on logstash-core update to 2.0
|
5
8
|
|
data/README.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# Logstash Plugin
|
2
2
|
|
3
|
+
[](http://build-eu-00.elastic.co/view/LS%20Plugins/view/LS%20Codecs/job/logstash-plugin-codec-multiline-unit/)
|
5
|
+
|
3
6
|
This is a plugin for [Logstash](https://github.com/elastic/logstash).
|
4
7
|
|
5
8
|
It is fully free and fully open source. The license is Apache 2.0, meaning you are pretty much free to use it however you want in whatever way.
|
@@ -0,0 +1,251 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/namespace"
|
3
|
+
require "thread_safe"
|
4
|
+
|
5
|
+
# This class is a Codec duck type
|
6
|
+
# Using Composition, it maps from a stream identity to
|
7
|
+
# a cloned codec instance via the same API as a Codec
|
8
|
+
# it implements the codec public API
|
9
|
+
|
10
|
+
module LogStash module Codecs class IdentityMapCodec
|
11
|
+
# subclass of Exception, LS has more than limit (20000) active streams
|
12
|
+
class IdentityMapUpperLimitException < Exception; end
|
13
|
+
|
14
|
+
module EightyPercentWarning
|
15
|
+
extend self
|
16
|
+
def visit(imc)
|
17
|
+
current_size, limit = imc.current_size_and_limit
|
18
|
+
return if current_size < (limit * 0.8)
|
19
|
+
imc.logger.warn("IdentityMapCodec has reached 80% capacity",
|
20
|
+
:current_size => current_size, :upper_limit => limit)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module UpperLimitReached
|
25
|
+
extend self
|
26
|
+
def visit(imc)
|
27
|
+
current_size, limit = imc.current_size_and_limit
|
28
|
+
return if current_size < limit
|
29
|
+
# we hit the limit
|
30
|
+
# try to clean out stale streams
|
31
|
+
current_size, limit = imc.map_cleanup
|
32
|
+
return if current_size < limit
|
33
|
+
# we are still at the limit and all streams are in use
|
34
|
+
imc.logger.error("IdentityMapCodec has reached 100% capacity",
|
35
|
+
:current_size => current_size, :upper_limit => limit)
|
36
|
+
raise IdentityMapUpperLimitException.new
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class MapCleaner
|
41
|
+
def initialize(imc, interval)
|
42
|
+
@imc, @interval = imc, interval
|
43
|
+
@running = false
|
44
|
+
end
|
45
|
+
|
46
|
+
def start
|
47
|
+
return self if running?
|
48
|
+
@running = true
|
49
|
+
@thread = Thread.new(@imc) do |imc|
|
50
|
+
loop do
|
51
|
+
sleep @interval
|
52
|
+
break if !@running
|
53
|
+
imc.map_cleanup
|
54
|
+
end
|
55
|
+
end
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
def running?
|
60
|
+
@running
|
61
|
+
end
|
62
|
+
|
63
|
+
def stop
|
64
|
+
return if !running?
|
65
|
+
@running = false
|
66
|
+
@thread.wakeup
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# A composite class to hold both the codec and the eviction_timeout
|
71
|
+
# instances of this Value Object are stored in the mapping hash
|
72
|
+
class CodecValue
|
73
|
+
attr_reader :codec
|
74
|
+
attr_accessor :timeout
|
75
|
+
|
76
|
+
def initialize(codec)
|
77
|
+
@codec = codec
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
#maximum size of the mapping hash
|
82
|
+
MAX_IDENTITIES = 20_000
|
83
|
+
|
84
|
+
# time after which a stream is
|
85
|
+
# considered stale
|
86
|
+
# each time a stream is accessed
|
87
|
+
# it is given a new timeout
|
88
|
+
EVICT_TIMEOUT = 60 * 60 * 1 # 1 hour
|
89
|
+
|
90
|
+
# time that the cleaner thread sleeps for
|
91
|
+
# before it tries to clean out stale mappings
|
92
|
+
CLEANER_INTERVAL = 60 * 5 # 5 minutes
|
93
|
+
|
94
|
+
attr_reader :identity_map
|
95
|
+
attr_accessor :base_codec, :cleaner
|
96
|
+
|
97
|
+
def initialize(codec)
|
98
|
+
@base_codec = codec
|
99
|
+
@base_codecs = [codec]
|
100
|
+
@identity_map = ThreadSafe::Hash.new &method(:codec_builder)
|
101
|
+
@max_identities = MAX_IDENTITIES
|
102
|
+
@evict_timeout = EVICT_TIMEOUT
|
103
|
+
@cleaner = MapCleaner.new(self, CLEANER_INTERVAL)
|
104
|
+
@decode_block = lambda {|*| }
|
105
|
+
end
|
106
|
+
|
107
|
+
# ==============================================
|
108
|
+
# Constructional/builder methods
|
109
|
+
# chain this method off of new
|
110
|
+
#
|
111
|
+
# used to add a non-default maximum identities
|
112
|
+
def max_identities(max)
|
113
|
+
@max_identities = max.to_i
|
114
|
+
self
|
115
|
+
end
|
116
|
+
|
117
|
+
# used to add a non-default evict timeout
|
118
|
+
def evict_timeout(timeout)
|
119
|
+
@evict_timeout = timeout.to_i
|
120
|
+
self
|
121
|
+
end
|
122
|
+
|
123
|
+
# used to add a non-default cleaner interval
|
124
|
+
def cleaner_interval(interval)
|
125
|
+
@cleaner.stop
|
126
|
+
@cleaner = MapCleaner.new(self, interval.to_i)
|
127
|
+
self
|
128
|
+
end
|
129
|
+
# end Constructional/builder methods
|
130
|
+
# ==============================================
|
131
|
+
|
132
|
+
# ==============================================
|
133
|
+
# Codec API
|
134
|
+
def decode(data, identity = nil, &block)
|
135
|
+
@decode_block = block if @decode_block != block
|
136
|
+
stream_codec(identity).decode(data, &block)
|
137
|
+
end
|
138
|
+
|
139
|
+
alias_method :<<, :decode
|
140
|
+
|
141
|
+
def encode(event, identity = nil)
|
142
|
+
stream_codec(identity).encode(event)
|
143
|
+
end
|
144
|
+
|
145
|
+
# this method will not be called from
|
146
|
+
# the input or the pipeline unless
|
147
|
+
# we implement codec flush on shutdown
|
148
|
+
# problematic, because we may not have
|
149
|
+
# received all the multiline parts yet.
|
150
|
+
# but if we don't flush we will lose data
|
151
|
+
def flush(&block)
|
152
|
+
all_codecs.each do |codec|
|
153
|
+
#let ruby do its default args thing
|
154
|
+
block.nil? ? codec.flush : codec.flush(&block)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def close()
|
159
|
+
cleaner.stop
|
160
|
+
all_codecs.each(&:close)
|
161
|
+
end
|
162
|
+
# end Codec API
|
163
|
+
# ==============================================
|
164
|
+
|
165
|
+
def all_codecs
|
166
|
+
no_streams? ? @base_codecs : identity_map.values.map(&:codec)
|
167
|
+
end
|
168
|
+
|
169
|
+
def max_limit
|
170
|
+
@max_identities
|
171
|
+
end
|
172
|
+
|
173
|
+
def identity_count
|
174
|
+
identity_map.size
|
175
|
+
end
|
176
|
+
|
177
|
+
# support cleaning of stale stream/codecs
|
178
|
+
# a stream is considered stale if it has not
|
179
|
+
# been accessed in the last @evict_timeout
|
180
|
+
# period (default 1 hour)
|
181
|
+
def map_cleanup
|
182
|
+
cut_off = Time.now.to_i
|
183
|
+
# delete_if is atomic
|
184
|
+
# contents should not mutate during this call
|
185
|
+
identity_map.delete_if do |identity, compo|
|
186
|
+
if (flag = compo.timeout <= cut_off)
|
187
|
+
compo.codec.flush(&@decode_block)
|
188
|
+
end
|
189
|
+
flag
|
190
|
+
end
|
191
|
+
current_size_and_limit
|
192
|
+
end
|
193
|
+
|
194
|
+
def current_size_and_limit
|
195
|
+
[identity_count, max_limit]
|
196
|
+
end
|
197
|
+
|
198
|
+
def logger
|
199
|
+
# we 'borrow' the codec's logger as we don't have our own
|
200
|
+
@base_codec.logger
|
201
|
+
end
|
202
|
+
|
203
|
+
def codec_without_usage_update(identity)
|
204
|
+
find_codec_value(identity).codec
|
205
|
+
end
|
206
|
+
|
207
|
+
def eviction_timestamp_for(identity)
|
208
|
+
find_codec_value(identity).timeout
|
209
|
+
end
|
210
|
+
|
211
|
+
private
|
212
|
+
|
213
|
+
def stream_codec(identity)
|
214
|
+
return base_codec if identity.nil?
|
215
|
+
record_codec_usage(identity) # returns codec
|
216
|
+
end
|
217
|
+
|
218
|
+
def find_codec_value(identity)
|
219
|
+
identity_map[identity]
|
220
|
+
end
|
221
|
+
|
222
|
+
# for nil stream this method is not called
|
223
|
+
def record_codec_usage(identity)
|
224
|
+
check_map_limits
|
225
|
+
# only start the cleaner if streams are in use
|
226
|
+
# continuous calls to start are OK
|
227
|
+
cleaner.start
|
228
|
+
compo = find_codec_value(identity)
|
229
|
+
compo.timeout = eviction_timestamp
|
230
|
+
compo.codec
|
231
|
+
end
|
232
|
+
|
233
|
+
def eviction_timestamp
|
234
|
+
Time.now.to_i + @evict_timeout
|
235
|
+
end
|
236
|
+
|
237
|
+
def check_map_limits
|
238
|
+
UpperLimitReached.visit(self)
|
239
|
+
EightyPercentWarning.visit(self)
|
240
|
+
end
|
241
|
+
|
242
|
+
def codec_builder(hash, k)
|
243
|
+
codec = hash.empty? ? @base_codec : @base_codec.clone
|
244
|
+
compo = CodecValue.new(codec)
|
245
|
+
hash.store(k, compo)
|
246
|
+
end
|
247
|
+
|
248
|
+
def no_streams?
|
249
|
+
identity_map.empty?
|
250
|
+
end
|
251
|
+
end end end
|
@@ -181,7 +181,7 @@ class LogStash::Codecs::Multiline < LogStash::Codecs::Base
|
|
181
181
|
end
|
182
182
|
|
183
183
|
def flush(&block)
|
184
|
-
if @buffer.any?
|
184
|
+
if @buffer.any?
|
185
185
|
yield merge_events
|
186
186
|
reset_buffer
|
187
187
|
end
|
@@ -211,7 +211,7 @@ class LogStash::Codecs::Multiline < LogStash::Codecs::Base
|
|
211
211
|
end
|
212
212
|
|
213
213
|
def over_maximun_lines?
|
214
|
-
@buffer.size > @max_lines
|
214
|
+
@buffer.size > @max_lines
|
215
215
|
end
|
216
216
|
|
217
217
|
def over_maximun_bytes?
|
@@ -227,4 +227,4 @@ class LogStash::Codecs::Multiline < LogStash::Codecs::Base
|
|
227
227
|
@on_event.call(event, event)
|
228
228
|
end # def encode
|
229
229
|
|
230
|
-
end # class LogStash::Codecs::
|
230
|
+
end # class LogStash::Codecs::Multiline
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
|
3
3
|
s.name = 'logstash-codec-multiline'
|
4
|
-
s.version = '2.0.
|
4
|
+
s.version = '2.0.3'
|
5
5
|
s.licenses = ['Apache License (2.0)']
|
6
6
|
s.summary = "The multiline codec will collapse multiline messages and merge them 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/plugin install gemname. This gem is not a stand-alone program"
|
@@ -0,0 +1,208 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/devutils/rspec/spec_helper"
|
3
|
+
require "logstash/codecs/identity_map_codec"
|
4
|
+
|
5
|
+
class LogTracer
|
6
|
+
def initialize() @tracer = []; end
|
7
|
+
def warn(*args) @tracer.push [:warn, args]; end
|
8
|
+
def error(*args) @tracer.push [:error, args]; end
|
9
|
+
|
10
|
+
def trace_for(symbol)
|
11
|
+
params = @tracer.assoc(symbol)
|
12
|
+
params.nil? ? false : params.last
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class IdentityMapCodecTracer
|
17
|
+
def initialize() @tracer = []; end
|
18
|
+
def clone() self.class.new; end
|
19
|
+
def decode(data) @tracer.push [:decode, data]; end
|
20
|
+
def encode(event) @tracer.push [:encode, event]; end
|
21
|
+
def flush(&block) @tracer.push [:flush, true]; end
|
22
|
+
def close() @tracer.push [:close, true]; end
|
23
|
+
def logger() @logger ||= LogTracer.new; end
|
24
|
+
|
25
|
+
def trace_for(symbol)
|
26
|
+
params = @tracer.assoc(symbol)
|
27
|
+
params.nil? ? false : params.last
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe LogStash::Codecs::IdentityMapCodec do
|
32
|
+
let(:codec) { IdentityMapCodecTracer.new }
|
33
|
+
let(:logger) { codec.logger }
|
34
|
+
let(:demuxer) { described_class.new(codec) }
|
35
|
+
let(:stream1) { "stream-a" }
|
36
|
+
let(:codec1) { demuxer.codec_without_usage_update(stream1) }
|
37
|
+
let(:arg1) { "data-a" }
|
38
|
+
|
39
|
+
after do
|
40
|
+
codec.close
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "operating without stream identity" do
|
44
|
+
let(:stream1) { nil }
|
45
|
+
|
46
|
+
it "transparently refers to the original codec" do
|
47
|
+
expect(codec).to eql(codec1)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "operating with stream identity" do
|
52
|
+
|
53
|
+
before { demuxer.decode(arg1, stream1) }
|
54
|
+
|
55
|
+
it "the first identity refers to the original codec" do
|
56
|
+
expect(codec).to eql(codec1)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "#decode" do
|
61
|
+
context "when no identity is used" do
|
62
|
+
let(:stream1) { nil }
|
63
|
+
|
64
|
+
it "calls the method on the original codec" do
|
65
|
+
demuxer.decode(arg1, stream1)
|
66
|
+
|
67
|
+
expect(codec.trace_for(:decode)).to eq(arg1)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "when multiple identities are used" do
|
72
|
+
let(:stream2) { "stream-b" }
|
73
|
+
let(:codec2) { demuxer.codec_without_usage_update(stream2) }
|
74
|
+
let(:arg2) { "data-b" }
|
75
|
+
|
76
|
+
it "calls the method on the appropriate codec" do
|
77
|
+
demuxer.decode(arg1, stream1)
|
78
|
+
demuxer.decode(arg2, stream2)
|
79
|
+
|
80
|
+
expect(codec1.trace_for(:decode)).to eq(arg1)
|
81
|
+
expect(codec2.trace_for(:decode)).to eq(arg2)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#encode" do
|
87
|
+
context "when no identity is used" do
|
88
|
+
let(:stream1) { nil }
|
89
|
+
let(:arg1) { LogStash::Event.new({"type" => "file"}) }
|
90
|
+
|
91
|
+
it "calls the method on the original codec" do
|
92
|
+
demuxer.encode(arg1, stream1)
|
93
|
+
|
94
|
+
expect(codec.trace_for(:encode)).to eq(arg1)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context "when multiple identities are used" do
|
99
|
+
let(:stream2) { "stream-b" }
|
100
|
+
let(:codec2) { demuxer.codec_without_usage_update(stream2) }
|
101
|
+
let(:arg2) { LogStash::Event.new({"type" => "file"}) }
|
102
|
+
|
103
|
+
it "calls the method on the appropriate codec" do
|
104
|
+
demuxer.encode(arg1, stream1)
|
105
|
+
demuxer.encode(arg2, stream2)
|
106
|
+
|
107
|
+
expect(codec1.trace_for(:encode)).to eq(arg1)
|
108
|
+
expect(codec2.trace_for(:encode)).to eq(arg2)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "#close" do
|
114
|
+
context "when no identity is used" do
|
115
|
+
before do
|
116
|
+
demuxer.decode(arg1)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "calls the method on the original codec" do
|
120
|
+
demuxer.close
|
121
|
+
expect(codec.trace_for(:close)).to be_truthy
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context "when multiple identities are used" do
|
126
|
+
let(:stream2) { "stream-b" }
|
127
|
+
let(:codec2) { demuxer.codec_without_usage_update(stream2) }
|
128
|
+
let(:arg2) { LogStash::Event.new({"type" => "file"}) }
|
129
|
+
|
130
|
+
before do
|
131
|
+
demuxer.decode(arg1, stream1)
|
132
|
+
demuxer.decode(arg2, stream2)
|
133
|
+
end
|
134
|
+
|
135
|
+
it "calls the method on all codecs" do
|
136
|
+
demuxer.close
|
137
|
+
|
138
|
+
expect(codec1.trace_for(:close)).to be_truthy
|
139
|
+
expect(codec2.trace_for(:close)).to be_truthy
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe "over capacity protection" do
|
145
|
+
let(:demuxer) { described_class.new(codec).max_identities(limit) }
|
146
|
+
|
147
|
+
context "when capacity at 80% or higher" do
|
148
|
+
let(:limit) { 10 }
|
149
|
+
|
150
|
+
it "a warning is logged" do
|
151
|
+
limit.pred.times do |i|
|
152
|
+
demuxer.decode(Object.new, "stream#{i}")
|
153
|
+
end
|
154
|
+
|
155
|
+
expect(logger.trace_for(:warn).first).to match %r|has reached 80% capacity|
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context "when capacity is exceeded" do
|
160
|
+
let(:limit) { 2 }
|
161
|
+
let(:error_class) { LogStash::Codecs::IdentityMapCodec::IdentityMapUpperLimitException }
|
162
|
+
|
163
|
+
it "an exception is raised" do
|
164
|
+
limit.times do |i|
|
165
|
+
demuxer.decode(Object.new, "stream#{i}")
|
166
|
+
end
|
167
|
+
expect { demuxer.decode(Object.new, "stream4") }.to raise_error(error_class)
|
168
|
+
end
|
169
|
+
|
170
|
+
context "initially but some streams are idle and can be evicted" do
|
171
|
+
let(:demuxer) { described_class.new(codec).max_identities(limit).evict_timeout(1) }
|
172
|
+
|
173
|
+
it "an exception is NOT raised" do
|
174
|
+
demuxer.decode(Object.new, "stream1")
|
175
|
+
sleep(1.2)
|
176
|
+
demuxer.decode(Object.new, "stream2")
|
177
|
+
expect(demuxer.identity_count).to eq(limit)
|
178
|
+
expect { demuxer.decode(Object.new, "stream4") }.not_to raise_error
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "usage tracking" do
|
185
|
+
let(:demuxer) { described_class.new(codec).evict_timeout(10) }
|
186
|
+
context "when an operation is performed by identity" do
|
187
|
+
it "the new eviction time for that identity is recorded" do
|
188
|
+
demuxer.decode(Object.new, "stream1")
|
189
|
+
current_eviction = demuxer.eviction_timestamp_for("stream1")
|
190
|
+
sleep(2)
|
191
|
+
demuxer.decode(Object.new, "stream1")
|
192
|
+
expect(demuxer.eviction_timestamp_for("stream1")).to be >= current_eviction + 2
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
describe "codec eviction" do
|
198
|
+
let(:demuxer) { described_class.new(codec).evict_timeout(1).cleaner_interval(1) }
|
199
|
+
context "when an identity has become stale" do
|
200
|
+
it "the cleaner evicts the codec and flushes it first" do
|
201
|
+
demuxer.decode(Object.new, "stream1")
|
202
|
+
sleep(2.1)
|
203
|
+
expect(codec.trace_for(:flush)).to be_truthy
|
204
|
+
expect(demuxer.identity_map.keys).not_to include("stream1")
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
metadata
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-codec-multiline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Elastic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-11-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
|
14
|
+
name: logstash-core
|
15
|
+
version_requirements: !ruby/object:Gem::Requirement
|
15
16
|
requirements:
|
16
17
|
- - '>='
|
17
18
|
- !ruby/object:Gem::Version
|
@@ -19,10 +20,7 @@ dependencies:
|
|
19
20
|
- - <
|
20
21
|
- !ruby/object:Gem::Version
|
21
22
|
version: 3.0.0
|
22
|
-
|
23
|
-
prerelease: false
|
24
|
-
type: :runtime
|
25
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirement: !ruby/object:Gem::Requirement
|
26
24
|
requirements:
|
27
25
|
- - '>='
|
28
26
|
- !ruby/object:Gem::Version
|
@@ -30,64 +28,68 @@ dependencies:
|
|
30
28
|
- - <
|
31
29
|
- !ruby/object:Gem::Version
|
32
30
|
version: 3.0.0
|
31
|
+
prerelease: false
|
32
|
+
type: :runtime
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
|
+
name: logstash-patterns-core
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
34
40
|
requirement: !ruby/object:Gem::Requirement
|
35
41
|
requirements:
|
36
42
|
- - '>='
|
37
43
|
- !ruby/object:Gem::Version
|
38
44
|
version: '0'
|
39
|
-
name: logstash-patterns-core
|
40
45
|
prerelease: false
|
41
46
|
type: :runtime
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: jls-grok
|
42
49
|
version_requirements: !ruby/object:Gem::Requirement
|
43
50
|
requirements:
|
44
|
-
- -
|
51
|
+
- - ~>
|
45
52
|
- !ruby/object:Gem::Version
|
46
|
-
version:
|
47
|
-
- !ruby/object:Gem::Dependency
|
53
|
+
version: 0.11.1
|
48
54
|
requirement: !ruby/object:Gem::Requirement
|
49
55
|
requirements:
|
50
56
|
- - ~>
|
51
57
|
- !ruby/object:Gem::Version
|
52
58
|
version: 0.11.1
|
53
|
-
name: jls-grok
|
54
59
|
prerelease: false
|
55
60
|
type: :runtime
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: logstash-devutils
|
56
63
|
version_requirements: !ruby/object:Gem::Requirement
|
57
64
|
requirements:
|
58
|
-
- -
|
65
|
+
- - '>='
|
59
66
|
- !ruby/object:Gem::Version
|
60
|
-
version: 0
|
61
|
-
- !ruby/object:Gem::Dependency
|
67
|
+
version: '0'
|
62
68
|
requirement: !ruby/object:Gem::Requirement
|
63
69
|
requirements:
|
64
70
|
- - '>='
|
65
71
|
- !ruby/object:Gem::Version
|
66
72
|
version: '0'
|
67
|
-
name: logstash-devutils
|
68
73
|
prerelease: false
|
69
74
|
type: :development
|
70
|
-
version_requirements: !ruby/object:Gem::Requirement
|
71
|
-
requirements:
|
72
|
-
- - '>='
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
version: '0'
|
75
75
|
description: This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program
|
76
76
|
email: info@elastic.co
|
77
77
|
executables: []
|
78
78
|
extensions: []
|
79
79
|
extra_rdoc_files: []
|
80
80
|
files:
|
81
|
+
- lib/logstash/codecs/identity_map_codec.rb
|
82
|
+
- lib/logstash/codecs/multiline.rb
|
83
|
+
- spec/codecs/multiline_spec.rb
|
84
|
+
- spec/codecs/identity_map_codec_spec.rb
|
85
|
+
- spec/supports/helpers.rb
|
86
|
+
- logstash-codec-multiline.gemspec
|
87
|
+
- README.md
|
81
88
|
- CHANGELOG.md
|
82
89
|
- CONTRIBUTORS
|
83
90
|
- Gemfile
|
84
91
|
- LICENSE
|
85
92
|
- NOTICE.TXT
|
86
|
-
- README.md
|
87
|
-
- lib/logstash/codecs/multiline.rb
|
88
|
-
- logstash-codec-multiline.gemspec
|
89
|
-
- spec/codecs/multiline_spec.rb
|
90
|
-
- spec/supports/helpers.rb
|
91
93
|
homepage: http://www.elastic.co/guide/en/logstash/current/index.html
|
92
94
|
licenses:
|
93
95
|
- Apache License (2.0)
|
@@ -110,10 +112,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
110
112
|
version: '0'
|
111
113
|
requirements: []
|
112
114
|
rubyforge_project:
|
113
|
-
rubygems_version: 2.
|
115
|
+
rubygems_version: 2.1.9
|
114
116
|
signing_key:
|
115
117
|
specification_version: 4
|
116
118
|
summary: The multiline codec will collapse multiline messages and merge them into a single event.
|
117
119
|
test_files:
|
118
120
|
- spec/codecs/multiline_spec.rb
|
121
|
+
- spec/codecs/identity_map_codec_spec.rb
|
119
122
|
- spec/supports/helpers.rb
|