logstash-input-file 2.1.3 → 2.2.0
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/inputs/file.rb +21 -3
- data/logstash-input-file.gemspec +3 -3
- data/spec/inputs/file_spec.rb +93 -4
- metadata +8 -9
- data/lib/logstash/inputs/identity_map_codec_component.rb +0 -56
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6412fcb09af0a0e32879a180c77e409c868caa43
|
4
|
+
data.tar.gz: 1d2fe6993ca73c122b2002a6c72c5d0f68a1fb9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2418a21eb0d3ea85185158c69ccbb971b332da29476fcdd7508249f3c28edda61c6a98e6886484a4a9bda6fd3e2b9ac0057eb6a8a84de17b2af075f4671cbae6
|
7
|
+
data.tar.gz: 189d29b3ccfbabdc6ad77d510cccb416dc0c738564676101a76beec9f37129c922f79ba613fb280d7486e70b4450693f9f08872a50372f93e467b09640cd9e73
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## 2.2.0
|
2
|
+
- Use ruby-filewatch 0.8.0, major rework of filewatch. See [Pull Request 74](https://github.com/jordansissel/ruby-filewatch/pull/74)
|
3
|
+
- add max_open_files config option, defaults to 4095, the input will process much more than this but have this number of files open at any time - files are closed based on the close_older setting, thereby making others openable.
|
4
|
+
- Changes the close_older logic to measure the time since the file was last read internlly rather than using the file stat modified time.
|
5
|
+
- Use logstash-codec-multiline 2.0.7, fixes a bug with auto_flush deadlocking when multiple file inputs are defined in the LS config.
|
6
|
+
|
1
7
|
## 2.1.3
|
2
8
|
- Use ruby-filewatch 0.7.1, re-enable close after file is modified again
|
3
9
|
|
data/lib/logstash/inputs/file.rb
CHANGED
@@ -35,6 +35,10 @@ require "socket" # for Socket.gethostname
|
|
35
35
|
# patterns with any frequency it might make sense to explicitly choose
|
36
36
|
# a sincedb path with the `sincedb_path` option.
|
37
37
|
#
|
38
|
+
# A different `sincedb_path` must be used for each input. Using the same
|
39
|
+
# path will cause issues. The read checkpoints for each input must be
|
40
|
+
# stored in a different path so the information does not override.
|
41
|
+
#
|
38
42
|
# Sincedb files are text files with four columns:
|
39
43
|
#
|
40
44
|
# . The inode number (or equivalent).
|
@@ -141,11 +145,24 @@ class LogStash::Inputs::File < LogStash::Inputs::Base
|
|
141
145
|
# longer ignored and any new data is read. The default is 24 hours.
|
142
146
|
config :ignore_older, :validate => :number, :default => 24 * 60 * 60
|
143
147
|
|
144
|
-
# If this option is specified, the file input closes any files that
|
145
|
-
#
|
148
|
+
# If this option is specified, the file input closes any files that were last
|
149
|
+
# read the specified timespan in seconds ago.
|
150
|
+
# This has different implications depending on if a file is being tailed or
|
151
|
+
# read. If tailing, and there is a large time gap in incoming data the file
|
152
|
+
# can be closed (allowing other files to be opened) but will be queued for
|
153
|
+
# reopening when new data is detected. If reading, the file will be closed
|
154
|
+
# after closed_older seconds from when the last bytes were read.
|
146
155
|
# The default is 1 hour
|
147
156
|
config :close_older, :validate => :number, :default => 1 * 60 * 60
|
148
157
|
|
158
|
+
# What is the maximum number of file_handles that this input consumes
|
159
|
+
# at any one time. Use close_older to close some files if you need to
|
160
|
+
# process more files than this number. This should not be set to the
|
161
|
+
# maximum the OS can do because file handles are needed for other
|
162
|
+
# LS plugins and OS processes.
|
163
|
+
# The default of 4095 is set in filewatch.
|
164
|
+
config :max_open_files, :validate => :number
|
165
|
+
|
149
166
|
public
|
150
167
|
def register
|
151
168
|
require "addressable/uri"
|
@@ -161,7 +178,8 @@ class LogStash::Inputs::File < LogStash::Inputs::Base
|
|
161
178
|
:sincedb_write_interval => @sincedb_write_interval,
|
162
179
|
:delimiter => @delimiter,
|
163
180
|
:ignore_older => @ignore_older,
|
164
|
-
:close_older => @close_older
|
181
|
+
:close_older => @close_older,
|
182
|
+
:max_open_files => @max_open_files
|
165
183
|
}
|
166
184
|
|
167
185
|
@path.each do |path|
|
data/logstash-input-file.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
|
3
3
|
s.name = 'logstash-input-file'
|
4
|
-
s.version = '2.
|
4
|
+
s.version = '2.2.0'
|
5
5
|
s.licenses = ['Apache License (2.0)']
|
6
6
|
s.summary = "Stream events from files."
|
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"
|
@@ -24,8 +24,8 @@ Gem::Specification.new do |s|
|
|
24
24
|
|
25
25
|
s.add_runtime_dependency 'logstash-codec-plain'
|
26
26
|
s.add_runtime_dependency 'addressable'
|
27
|
-
s.add_runtime_dependency 'filewatch', ['>= 0.
|
28
|
-
s.add_runtime_dependency 'logstash-codec-multiline', ['~> 2.0.
|
27
|
+
s.add_runtime_dependency 'filewatch', ['>= 0.8.0', '~> 0.8']
|
28
|
+
s.add_runtime_dependency 'logstash-codec-multiline', ['~> 2.0.7']
|
29
29
|
|
30
30
|
s.add_development_dependency 'stud', ['~> 0.0.19']
|
31
31
|
s.add_development_dependency 'logstash-devutils'
|
data/spec/inputs/file_spec.rb
CHANGED
@@ -152,6 +152,10 @@ describe LogStash::Inputs::File do
|
|
152
152
|
let(:sincedb_path) { Stud::Temporary.pathname }
|
153
153
|
let(:tmpdir_path) { Stud::Temporary.directory }
|
154
154
|
|
155
|
+
after :each do
|
156
|
+
FileUtils.rm_rf(sincedb_path)
|
157
|
+
end
|
158
|
+
|
155
159
|
context "when data exists and then more data is appended" do
|
156
160
|
subject { described_class.new(conf) }
|
157
161
|
|
@@ -369,6 +373,7 @@ describe LogStash::Inputs::File do
|
|
369
373
|
conf.update(
|
370
374
|
"path" => tmpdir_path + "/*.log",
|
371
375
|
"start_position" => "beginning",
|
376
|
+
"stat_interval" => 0.1,
|
372
377
|
"sincedb_path" => sincedb_path)
|
373
378
|
|
374
379
|
File.open(file_path, "w") do |fd|
|
@@ -382,14 +387,98 @@ describe LogStash::Inputs::File do
|
|
382
387
|
subject.register
|
383
388
|
expect(lsof_proc.call).to eq("")
|
384
389
|
run_thread_proc.call
|
385
|
-
sleep 0.
|
390
|
+
sleep 0.25
|
386
391
|
first_lsof = lsof_proc.call
|
387
|
-
expect(first_lsof).
|
392
|
+
expect(first_lsof.scan(file_path).size).to eq(1)
|
388
393
|
run_thread_proc.call
|
389
|
-
sleep 0.
|
394
|
+
sleep 0.25
|
390
395
|
second_lsof = lsof_proc.call
|
391
|
-
expect(second_lsof).to eq(
|
396
|
+
expect(second_lsof.scan(file_path).size).to eq(1)
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
describe "specifying max_open_files" do
|
401
|
+
subject { described_class.new(conf) }
|
402
|
+
before do
|
403
|
+
File.open("#{tmpdir_path}/a.log", "w") do |fd|
|
404
|
+
fd.puts("line1-of-a")
|
405
|
+
fd.puts("line2-of-a")
|
406
|
+
fd.fsync
|
407
|
+
end
|
408
|
+
File.open("#{tmpdir_path}/z.log", "w") do |fd|
|
409
|
+
fd.puts("line1-of-z")
|
410
|
+
fd.puts("line2-of-z")
|
411
|
+
fd.fsync
|
412
|
+
end
|
392
413
|
end
|
414
|
+
|
415
|
+
context "when close_older is NOT specified" do
|
416
|
+
before do
|
417
|
+
conf.clear
|
418
|
+
conf.update(
|
419
|
+
"type" => "blah",
|
420
|
+
"path" => "#{tmpdir_path}/*.log",
|
421
|
+
"sincedb_path" => sincedb_path,
|
422
|
+
"stat_interval" => 0.1,
|
423
|
+
"max_open_files" => 1,
|
424
|
+
"start_position" => "beginning",
|
425
|
+
"delimiter" => FILE_DELIMITER)
|
426
|
+
subject.register
|
427
|
+
Thread.new { subject.run(events) }
|
428
|
+
sleep 0.1
|
429
|
+
end
|
430
|
+
it "collects line events from only one file" do
|
431
|
+
# wait for one path to be mapped as identity
|
432
|
+
expect(pause_until{ subject.codec.identity_count == 1 }).to be_truthy
|
433
|
+
subject.stop
|
434
|
+
# stop flushes last event
|
435
|
+
expect(pause_until{ events.size == 2 }).to be_truthy
|
436
|
+
|
437
|
+
e1, e2 = events
|
438
|
+
if Dir.glob("#{tmpdir_path}/*.log").first =~ %r{a\.log}
|
439
|
+
#linux and OSX have different retrieval order
|
440
|
+
expect(e1["message"]).to eq("line1-of-a")
|
441
|
+
expect(e2["message"]).to eq("line2-of-a")
|
442
|
+
else
|
443
|
+
expect(e1["message"]).to eq("line1-of-z")
|
444
|
+
expect(e2["message"]).to eq("line2-of-z")
|
445
|
+
end
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
context "when close_older IS specified" do
|
450
|
+
before do
|
451
|
+
conf.update(
|
452
|
+
"type" => "blah",
|
453
|
+
"path" => "#{tmpdir_path}/*.log",
|
454
|
+
"sincedb_path" => sincedb_path,
|
455
|
+
"stat_interval" => 0.1,
|
456
|
+
"max_open_files" => 1,
|
457
|
+
"close_older" => 1,
|
458
|
+
"start_position" => "beginning",
|
459
|
+
"delimiter" => FILE_DELIMITER)
|
460
|
+
subject.register
|
461
|
+
Thread.new { subject.run(events) }
|
462
|
+
sleep 0.1
|
463
|
+
end
|
464
|
+
|
465
|
+
it "collects line events from both files" do
|
466
|
+
# close flushes last event of each identity
|
467
|
+
expect(pause_until{ events.size == 4 }).to be_truthy
|
468
|
+
subject.stop
|
469
|
+
if Dir.glob("#{tmpdir_path}/*.log").first =~ %r{a\.log}
|
470
|
+
#linux and OSX have different retrieval order
|
471
|
+
e1, e2, e3, e4 = events
|
472
|
+
else
|
473
|
+
e3, e4, e1, e2 = events
|
474
|
+
end
|
475
|
+
expect(e1["message"]).to eq("line1-of-a")
|
476
|
+
expect(e2["message"]).to eq("line2-of-a")
|
477
|
+
expect(e3["message"]).to eq("line1-of-z")
|
478
|
+
expect(e4["message"]).to eq("line2-of-z")
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
393
482
|
end
|
394
483
|
end
|
395
484
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-input-file
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Elastic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-01-
|
11
|
+
date: 2016-01-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: logstash-core
|
@@ -64,18 +64,18 @@ dependencies:
|
|
64
64
|
requirements:
|
65
65
|
- - '>='
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version: 0.
|
67
|
+
version: 0.8.0
|
68
68
|
- - ~>
|
69
69
|
- !ruby/object:Gem::Version
|
70
|
-
version: '0.
|
70
|
+
version: '0.8'
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - '>='
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 0.
|
75
|
+
version: 0.8.0
|
76
76
|
- - ~>
|
77
77
|
- !ruby/object:Gem::Version
|
78
|
-
version: '0.
|
78
|
+
version: '0.8'
|
79
79
|
prerelease: false
|
80
80
|
type: :runtime
|
81
81
|
- !ruby/object:Gem::Dependency
|
@@ -84,12 +84,12 @@ dependencies:
|
|
84
84
|
requirements:
|
85
85
|
- - ~>
|
86
86
|
- !ruby/object:Gem::Version
|
87
|
-
version: 2.0.
|
87
|
+
version: 2.0.7
|
88
88
|
requirement: !ruby/object:Gem::Requirement
|
89
89
|
requirements:
|
90
90
|
- - ~>
|
91
91
|
- !ruby/object:Gem::Version
|
92
|
-
version: 2.0.
|
92
|
+
version: 2.0.7
|
93
93
|
prerelease: false
|
94
94
|
type: :runtime
|
95
95
|
- !ruby/object:Gem::Dependency
|
@@ -147,7 +147,6 @@ files:
|
|
147
147
|
- NOTICE.TXT
|
148
148
|
- README.md
|
149
149
|
- lib/logstash/inputs/file.rb
|
150
|
-
- lib/logstash/inputs/identity_map_codec_component.rb
|
151
150
|
- logstash-input-file.gemspec
|
152
151
|
- spec/inputs/file_spec.rb
|
153
152
|
- spec/spec_helper.rb
|
@@ -1,56 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
require "logstash/inputs/component"
|
3
|
-
require "logstash/codecs/identity_map_codec"
|
4
|
-
|
5
|
-
module LogStash module Inputs class IdentityMapCodecComponent
|
6
|
-
include Component
|
7
|
-
|
8
|
-
attr_reader :codec
|
9
|
-
|
10
|
-
def add_codec(codec)
|
11
|
-
@codec = LogStash::Codecs::IdentityMapCodec.new(codec)
|
12
|
-
self
|
13
|
-
end
|
14
|
-
|
15
|
-
def stop
|
16
|
-
@codec.close
|
17
|
-
end
|
18
|
-
|
19
|
-
def do_work(context, data)
|
20
|
-
do_line(context, data) || do_eviction(context, data)
|
21
|
-
end
|
22
|
-
|
23
|
-
def process(context, data)
|
24
|
-
# data should be an event
|
25
|
-
deliver(context, data)
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def do_line(context, data)
|
31
|
-
return false unless line?(context)
|
32
|
-
@codec.decode_accept(context, data, self)
|
33
|
-
# above should call back on #process
|
34
|
-
true
|
35
|
-
end
|
36
|
-
|
37
|
-
def do_eviction(context, data)
|
38
|
-
return false unless evicting?(context)
|
39
|
-
path = context[:path]
|
40
|
-
@codec.evict(path) if path
|
41
|
-
true
|
42
|
-
end
|
43
|
-
|
44
|
-
def line?(ctx)
|
45
|
-
action(ctx) == "line"
|
46
|
-
end
|
47
|
-
|
48
|
-
def evicting?(ctx)
|
49
|
-
_action = action(ctx)
|
50
|
-
_action == "timed_out" || _action == "deleted"
|
51
|
-
end
|
52
|
-
|
53
|
-
def action(ctx)
|
54
|
-
ctx[:action]
|
55
|
-
end
|
56
|
-
end end end
|