logstash-input-file_progress 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8ce74ef18daca1f4dee56f79adf5c680423dac47
4
+ data.tar.gz: 639c3ae4c64b2d7224668ffbf2a6bb219f9499ed
5
+ SHA512:
6
+ metadata.gz: 1f2a51b2364f190771284c31baaa9723f613957ce70fd5918707533ed3b6ce815c930fa3fc41a30d87a5b00612ccb14c074f2f1014718f6dc66f18bb5c076613
7
+ data.tar.gz: 8e02ebb1782de1c4c5151f7d5f0c4471e4e03394e0cc7566044f4414ae81332030205045e613ad428ec478953bbd9d4713c199455608e08b6c7853ec6418a6b7
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ Gemfile.lock
2
+ .ruby-version
3
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2012-2014 Elasticsearch <http://www.elasticsearch.org>
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ @files=[]
2
+
3
+ task :default do
4
+ system("rake -T")
5
+ end
6
+
7
+ require "logstash/devutils/rake"
@@ -0,0 +1,149 @@
1
+ require "logstash/inputs/base"
2
+ require "logstash/namespace"
3
+
4
+ require "pathname"
5
+ require "socket" # for Socket.gethostname
6
+
7
+ # Stream events from files.
8
+ #
9
+ # By default, each event is assumed to be one line. If you
10
+ # want to join lines, you'll want to use the multiline filter.
11
+ #
12
+ # Files are followed in a manner similar to "tail -0F". File rotation
13
+ # is detected and handled by this input.
14
+ #
15
+ # In addition to 'normal' file input we add events with sincedb-data to the pipe.
16
+ # This can be later used to serve progress date with e.g. faye-output
17
+ class LogStash::Inputs::FileProgress < LogStash::Inputs::Base
18
+ config_name "file_progress"
19
+
20
+ # TODO(sissel): This should switch to use the 'line' codec by default
21
+ # once file following
22
+ default :codec, "line"
23
+
24
+ # The path to the file to use as an input.
25
+ # You can use globs here, such as `/var/log/*.log`
26
+ # Paths must be absolute and cannot be relative.
27
+ config :path, :validate => :array, :required => true
28
+
29
+ # Exclusions (matched against the filename, not full path). Globs
30
+ # are valid here, too. For example, if you have
31
+ #
32
+ # path => "/var/log/*"
33
+ #
34
+ # you might want to exclude gzipped files:
35
+ #
36
+ # exclude => "*.gz"
37
+ config :exclude, :validate => :array
38
+
39
+ # How often we stat files to see if they have been modified. Increasing
40
+ # this interval will decrease the number of system calls we make, but
41
+ # increase the time to detect new log lines.
42
+ config :stat_interval, :validate => :number, :default => 1
43
+
44
+ # How often we expand globs to discover new files to watch.
45
+ config :discover_interval, :validate => :number, :default => 15
46
+
47
+ # Where to write the since database (keeps track of the current
48
+ # position of monitored log files). The default will write
49
+ # sincedb files to some path matching "$HOME/.sincedb*"
50
+ config :sincedb_path, :validate => :string, :required => true
51
+
52
+ # How often to write a since database with the current position of
53
+ # monitored log files.
54
+ config :sincedb_write_interval, :validate => :number, :default => 15
55
+
56
+ # Choose where logstash starts initially reading files - at the beginning or
57
+ # at the end. The default behavior treats files like live streams and thus
58
+ # starts at the end. If you have old data you want to import, set this
59
+ # to 'beginning'
60
+ #
61
+ # This option only modifieds "first contact" situations where a file is new
62
+ # and not seen before. If a file has already been seen before, this option
63
+ # has no effect.
64
+ config :start_position, :validate => [ "beginning", "end"], :default => "beginning"
65
+
66
+ # Should the progressdb events be send to the pipeline
67
+ config :progressdb, :validate => :boolean, :default => false
68
+
69
+ # Should the processdb entry be deleted after file-deletion
70
+ config :progressdb_del, :validate => :boolean, :default => false
71
+
72
+ # Close the file when end is reached
73
+ # This make sense when reading a file once from the beginning and want to e.g.
74
+ # proceed renaming or deleting the parent folder
75
+ config :eof_close, :validate => :boolean, :default => false
76
+
77
+ public
78
+ def register
79
+ require "addressable/uri"
80
+ require "filewatch/ext/filetail"
81
+ require "digest/md5"
82
+ @logger.info("Registering file input", :path => @path)
83
+
84
+ @tail_config = {
85
+ :exclude => @exclude,
86
+ :stat_interval => @stat_interval,
87
+ :discover_interval => @discover_interval,
88
+ :sincedb_write_interval => @sincedb_write_interval,
89
+ :logger => @logger,
90
+ :progressdb => @progressdb,
91
+ :progressdb_del => @progressdb_del,
92
+ :eof_close => @eof_close,
93
+ }
94
+
95
+ @path.each do |path|
96
+ if Pathname.new(path).relative?
97
+ raise ArgumentError.new("File paths must be absolute, relative path specified: #{path}")
98
+ end
99
+ end
100
+
101
+ @tail_config[:sincedb_path] = @sincedb_path
102
+
103
+ if @start_position == "beginning"
104
+ @tail_config[:start_new_files_at] = :beginning
105
+ end
106
+
107
+ @codec_plain = LogStash::Codecs::Plain.new
108
+ end # def register
109
+
110
+ public
111
+ def run(queue)
112
+ @tail = FileWatch::Ext::FileTail.new(@tail_config)
113
+ @tail.logger = @logger
114
+ @path.each { |path| @tail.tail(path) }
115
+ hostname = Socket.gethostname
116
+
117
+ @tail.subscribe do |path, data, type|
118
+ @logger.debug("Received line", :path => path, :data => data) if logger.debug?
119
+
120
+ if type == :log
121
+ @codec.decode(data) do |event|
122
+
123
+ decorate(event)
124
+ event["host"] = hostname
125
+ event["path"] = path
126
+
127
+ queue << event
128
+ end
129
+ elsif type == :progressdb
130
+ @codec_plain.decode(data) do |event|
131
+
132
+ decorate(event)
133
+ event["host"] = hostname
134
+ event["path"] = path
135
+ event["type"] = "progressdb";
136
+
137
+ queue << event
138
+ end
139
+ end # if
140
+ end # subscribe
141
+ finished
142
+ end # def run
143
+
144
+ public
145
+ def teardown
146
+ @tail.sincedb_write
147
+ @tail.quit
148
+ end # def teardown
149
+ end # class LogStash::Inputs::TriggeredPackage
@@ -0,0 +1,32 @@
1
+ Gem::Specification.new do |s|
2
+
3
+ s.name = 'logstash-input-file_progress'
4
+ s.version = '0.1.0'
5
+ s.licenses = ['Apache License (2.0)']
6
+ s.summary = "Stream events from files with progress-events."
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"
8
+ s.authors = ["Signify"]
9
+ s.email = 'dietmar@signifydata.com'
10
+ s.homepage = "http://www.signifydata.com"
11
+ s.require_paths = ["lib"]
12
+
13
+ # Files
14
+ s.files = `git ls-files`.split($\)
15
+
16
+ # Tests
17
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
18
+
19
+ # Special flag to let us know this is actually a logstash plugin
20
+ s.metadata = { "logstash_plugin" => "true", "logstash_group" => "input" }
21
+
22
+ # Gem dependencies
23
+ s.add_runtime_dependency 'logstash-core', '>= 1.4.0', '< 2.0.0'
24
+
25
+ s.add_runtime_dependency 'logstash-codec-line'
26
+ s.add_runtime_dependency 'addressable'
27
+ s.add_runtime_dependency "filewatch-ext", ["~> 0.3.0"]
28
+
29
+
30
+ s.add_development_dependency 'logstash-devutils'
31
+ end
32
+
@@ -0,0 +1,141 @@
1
+ # encoding: utf-8
2
+
3
+ require "logstash/devutils/rspec/spec_helper"
4
+ require "logstash/inputs/file_progress"
5
+ require "tempfile"
6
+
7
+ describe "inputs/file_progress" do
8
+
9
+
10
+ describe "starts at the end of an existing file" do
11
+ tmp_file = Tempfile.new('logstash-spec-input-file')
12
+
13
+ config = %q[
14
+ input {
15
+ file_progress {
16
+ type => "blah"
17
+ path => "#{tmp_file.path}"
18
+ sincedb_path => "/dev/null"
19
+ }
20
+ }
21
+ ]
22
+
23
+ #input do |pipeline, queue|
24
+ File.open(tmp_file, "w") do |fd|
25
+ fd.puts("ignore me 1")
26
+ fd.puts("ignore me 2")
27
+ end
28
+
29
+ pipeline = LogStash::Pipeline.new(config)
30
+ queue = Queue.new
31
+ pipeline.instance_eval do
32
+ @output_func = lambda { |event| queue << event }
33
+ end
34
+ pipeline_thread = Thread.new { pipeline.run }
35
+ event = queue.pop
36
+
37
+ # at this point even if pipeline.ready? == true the plugins
38
+ # threads might still be initializing so we cannot know when the
39
+ # file plugin will have seen the original file, it could see it
40
+ # after the first(s) hello world appends below, hence the
41
+ # retry logic.
42
+
43
+ retries = 0
44
+ loop do
45
+ insist { retries } < 20 # 2 secs should be plenty?
46
+
47
+ File.open(tmp_file, "a") do |fd|
48
+ fd.puts("hello")
49
+ fd.puts("world")
50
+ end
51
+
52
+ if queue.size >= 2
53
+ events = 2.times.collect { queue.pop }
54
+ insist { events[0]["message"] } == "hello"
55
+ insist { events[1]["message"] } == "world"
56
+ break
57
+ end
58
+
59
+ sleep(0.1)
60
+ retries += 1
61
+ end
62
+
63
+ pipeline_thread.join
64
+
65
+ #end
66
+ end
67
+
68
+ #describe "can start at the beginning of an existing file" do
69
+ # tmp_file = Tempfile.new('logstash-spec-input-file')#
70
+
71
+ # config <<-CONFIG
72
+ # input {
73
+ # file_progress {
74
+ # type => "blah"
75
+ # path => "#{tmp_file.path}"
76
+ # start_position => "beginning"
77
+ # sincedb_path => "/dev/null"
78
+ # }
79
+ # }
80
+ # CONFIG#
81
+
82
+ # input do |pipeline, queue|
83
+ # File.open(tmp_file, "a") do |fd|
84
+ # fd.puts("hello")
85
+ # fd.puts("world")
86
+ # end#
87
+
88
+ # Thread.new { pipeline.run }
89
+ # sleep 0.1 while !pipeline.ready?#
90
+
91
+ # events = 2.times.collect { queue.pop }
92
+ # insist { events[0]["message"] } == "hello"
93
+ # insist { events[1]["message"] } == "world"
94
+ # end
95
+ # end#
96
+
97
+ # describe "restarts at the sincedb value" do
98
+ # tmp_file = Tempfile.new('logstash-spec-input-file')
99
+ # tmp_sincedb = Tempfile.new('logstash-spec-input-file-sincedb')#
100
+
101
+ # config <<-CONFIG
102
+ # input {
103
+ # file_progress {
104
+ # type => "blah"
105
+ # path => "#{tmp_file.path}"
106
+ # start_position => "beginning"
107
+ # sincedb_path => "#{tmp_sincedb.path}"
108
+ # }
109
+ # }
110
+ # CONFIG#
111
+
112
+ # input do |pipeline, queue|
113
+ # File.open(tmp_file, "w") do |fd|
114
+ # fd.puts("hello")
115
+ # fd.puts("world")
116
+ # end#
117
+
118
+ # t = Thread.new { pipeline.run }
119
+ # sleep 0.1 while !pipeline.ready?#
120
+
121
+ # events = 2.times.collect { queue.pop }
122
+ # pipeline.shutdown
123
+ # t.join#
124
+
125
+ # File.open(tmp_file, "a") do |fd|
126
+ # fd.puts("foo")
127
+ # fd.puts("bar")
128
+ # fd.puts("baz")
129
+ # end#
130
+
131
+ # Thread.new { pipeline.run }
132
+ # sleep 0.1 while !pipeline.ready?#
133
+
134
+ # events = 3.times.collect { queue.pop }#
135
+
136
+ # insist { events[0]["message"] } == "foo"
137
+ # insist { events[1]["message"] } == "bar"
138
+ # insist { events[2]["message"] } == "baz"
139
+ # end
140
+ # end
141
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: logstash-input-file_progress
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Signify
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - '>='
17
+ - !ruby/object:Gem::Version
18
+ version: 1.4.0
19
+ - - <
20
+ - !ruby/object:Gem::Version
21
+ version: 2.0.0
22
+ name: logstash-core
23
+ prerelease: false
24
+ type: :runtime
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.4.0
30
+ - - <
31
+ - !ruby/object:Gem::Version
32
+ version: 2.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ name: logstash-codec-line
40
+ prerelease: false
41
+ type: :runtime
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ requirement: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ name: addressable
54
+ prerelease: false
55
+ type: :runtime
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ~>
65
+ - !ruby/object:Gem::Version
66
+ version: 0.3.0
67
+ name: filewatch-ext
68
+ prerelease: false
69
+ type: :runtime
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ~>
73
+ - !ruby/object:Gem::Version
74
+ version: 0.3.0
75
+ - !ruby/object:Gem::Dependency
76
+ requirement: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ name: logstash-devutils
82
+ prerelease: false
83
+ type: :development
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ 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
90
+ email: dietmar@signifydata.com
91
+ executables: []
92
+ extensions: []
93
+ extra_rdoc_files: []
94
+ files:
95
+ - .gitignore
96
+ - Gemfile
97
+ - LICENSE
98
+ - Rakefile
99
+ - lib/logstash/inputs/file_progress.rb
100
+ - logstash-input-file_progress.gemspec
101
+ - spec/inputs/file_progress_spec.rb
102
+ homepage: http://www.signifydata.com
103
+ licenses:
104
+ - Apache License (2.0)
105
+ metadata:
106
+ logstash_plugin: 'true'
107
+ logstash_group: input
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - '>='
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - '>='
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubyforge_project:
124
+ rubygems_version: 2.1.9
125
+ signing_key:
126
+ specification_version: 4
127
+ summary: Stream events from files with progress-events.
128
+ test_files:
129
+ - spec/inputs/file_progress_spec.rb