logstash-output-file_closeable 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: eb6ffd81954405585db0c421aca83f9ef69f5818
4
+ data.tar.gz: 8b6043f66938682c71f0430a9d49c7273b20ffb2
5
+ SHA512:
6
+ metadata.gz: 04227da02a03ca3c9df7c67d13f937a5b426ce3ead1182292d67798a1d410a2965a54f5bf6a6793ae8b740597f26a5ee81c660ed4654f941ab069c53008dcf00
7
+ data.tar.gz: 536851937ba38a919215d58fe687a5a180be615b38a40746743165b36d4bdd95879fa35cc3f0f3d52580faa750fca3617e85dd0e61276f1f3bdd657bfd6ba873
@@ -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.
@@ -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,195 @@
1
+ require "logstash/namespace"
2
+ require "logstash/outputs/base"
3
+ require "zlib"
4
+
5
+ # File output.
6
+ #
7
+ # Write events to files on disk. You can use fields from the
8
+ # event as parts of the filename.
9
+ class LogStash::Outputs::FileCloseable < LogStash::Outputs::Base
10
+
11
+ if RUBY_ENGINE == "jruby"
12
+ JavaException = java.lang.Exception
13
+ end
14
+
15
+ config_name "file2"
16
+
17
+ # The format to use when writing events to the file. This value
18
+ # supports any string and can include %{name} and other dynamic
19
+ # strings.
20
+ #
21
+ # If this setting is omitted, the full json representation of the
22
+ # event will be written as a single line.
23
+ config :message_format, :validate => :string
24
+
25
+ # Flush interval for flushing writes to log files. 0 will flush on every meesage
26
+ config :flush_interval, :validate => :number, :default => 2
27
+
28
+ # Gzip output stream
29
+ config :gzip, :validate => :boolean, :default => false
30
+
31
+ # The path to the file to write. Event fields can be used here,
32
+ # like "/var/log/logstash/%{host}/%{application}"
33
+ # One may also utilize the path option for date-based log
34
+ # rotation via the joda time format. This will use the event
35
+ # timestamp.
36
+ # E.g.: path => "./test-%{+YYYY-MM-dd}.txt" to create
37
+ # ./test-2013-05-29.txt
38
+ config :path, :validate => :string
39
+
40
+ public
41
+ def register
42
+ require "fileutils" # For mkdir_p
43
+
44
+ @files = {}
45
+ now = Time.now
46
+ @last_flush_cycle = now
47
+ @last_stale_cleanup_cycle = now
48
+ flush_interval = @flush_interval.to_i
49
+ @stale_cleanup_interval = 10
50
+
51
+ @codec.on_event do |event|
52
+ if @path
53
+ path = event.sprintf(@path)
54
+ else
55
+ path = event["path"]
56
+ end
57
+
58
+ fd = open(path)
59
+
60
+ if event.is_a? LogStash::Event and @message_format
61
+ output = event.sprintf(@message_format)
62
+ else
63
+ output = event["message"]
64
+ end
65
+
66
+ @logger.debug("Writing output to file", :output => output, :path => path) if @logger.debug?
67
+
68
+ fd.write(output)
69
+ fd.write("\n")
70
+
71
+ flush(fd)
72
+ close_stale_files(false)
73
+ end
74
+ end # def register
75
+
76
+ public
77
+ def receive(event)
78
+ return unless output?(event)
79
+
80
+ @codec.encode(event)
81
+
82
+ if event.include? "tags" and event["tags"].include?("eof")
83
+
84
+ @files.each do |path, fd|
85
+ if(File.basename(path) == File.basename(event['path']))
86
+ fd.active = false
87
+ end
88
+ end
89
+
90
+ close_stale_files(true) #means eof
91
+ return
92
+ end
93
+ end # def receive
94
+
95
+ def teardown
96
+ @logger.debug("Teardown: closing files") if @logger.debug?
97
+ @files.each do |path, fd|
98
+ begin
99
+ fd.close
100
+ @logger.debug("Closed file #{path}", :fd => fd) if @logger.debug?
101
+ rescue Exception => e
102
+ @logger.error("Excpetion while flushing and closing files.", :exception => e) if @logger.debug?
103
+ end
104
+ end
105
+ finished
106
+ end
107
+
108
+ private
109
+ def flush(fd)
110
+ if flush_interval > 0
111
+ flush_pending_files
112
+ else
113
+ fd.flush
114
+ end
115
+ end
116
+
117
+ # every flush_interval seconds or so (triggered by events, but if there are no events there's no point flushing files anyway)
118
+ def flush_pending_files
119
+ return unless Time.now - @last_flush_cycle >= flush_interval
120
+
121
+ @logger.debug("Starting flush cycle") if @logger.debug?
122
+ @files.each do |path, fd|
123
+ @logger.debug("Flushing file", :path => path, :fd => fd) if @logger.debug?
124
+ fd.flush
125
+ end
126
+ @last_flush_cycle = Time.now
127
+ end
128
+
129
+ # every 10 seconds or so (triggered by events, but if there are no events there's no point closing files anyway)
130
+ def close_stale_files(eof)
131
+ now = Time.now
132
+ return if now - @last_stale_cleanup_cycle < @stale_cleanup_interval and not eof
133
+
134
+ @logger.info("Starting stale files cleanup cycle", :files => @files)
135
+ inactive_files = @files.select { |path, fd| not fd.active }
136
+ @logger.debug("%d stale files found" % inactive_files.count, :inactive_files => inactive_files) if @logger.debug?
137
+ inactive_files.each do |path, fd|
138
+ @logger.info("Closing file %s" % path)
139
+ fd.close
140
+ @files.delete(path)
141
+ end
142
+ # mark all files as inactive, a call to write will mark them as active again
143
+ @files.each { |path, fd| fd.active = false }
144
+ @last_stale_cleanup_cycle = now
145
+ end
146
+
147
+ def open(path)
148
+ return @files[path] if @files.include?(path) and not @files[path].nil?
149
+
150
+ @logger.info("Opening file", :path => path)
151
+
152
+ dir = File.dirname(path)
153
+ if !Dir.exists?(dir)
154
+ @logger.info("Creating directory", :directory => dir)
155
+ FileUtils.mkdir_p(dir)
156
+ end
157
+
158
+ # work around a bug opening fifos (bug JRUBY-6280)
159
+ stat = File.stat(path) rescue nil
160
+ if stat and stat.ftype == "fifo" and RUBY_PLATFORM == "java"
161
+ fd = java.io.FileWriter.new(java.io.File.new(path))
162
+ else
163
+ fd = File.new(path, "a")
164
+ end
165
+ if gzip
166
+ fd = Zlib::GzipWriter.new(fd)
167
+ end
168
+ @files[path] = IOWriter.new(fd)
169
+ end
170
+ end # class LogStash::Outputs::TriggeredFolder
171
+
172
+ # wrapper class
173
+ class IOWriter
174
+ def initialize(io)
175
+ @io = io
176
+ end
177
+ def write(*args)
178
+ @io.write(*args)
179
+ @active = true
180
+ end
181
+ def flush
182
+ @io.flush
183
+ if @io.class == Zlib::GzipWriter
184
+ @io.to_io.flush
185
+ end
186
+ end
187
+ def method_missing(method_name, *args, &block)
188
+ if @io.respond_to?(method_name)
189
+ @io.send(method_name, *args, &block)
190
+ else
191
+ super
192
+ end
193
+ end
194
+ attr_accessor :active
195
+ end
@@ -0,0 +1,27 @@
1
+ Gem::Specification.new do |s|
2
+
3
+ s.name = 'logstash-output-file_closeable'
4
+ s.version = '0.1.0'
5
+ s.licenses = ['Apache License (2.0)']
6
+ s.summary = "This output will write events to files on disk with additional closing file of finished reading"
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" => "output" }
21
+
22
+ # Gem dependencies
23
+ s.add_runtime_dependency 'logstash-core', '>= 1.4.0', '< 2.0.0'
24
+
25
+ s.add_development_dependency 'logstash-devutils'
26
+ end
27
+
@@ -0,0 +1,5 @@
1
+ require "logstash/devutils/rspec/spec_helper"
2
+ require 'logstash/inputs/file_closeable'
3
+
4
+ describe LogStash::Inputs::FileCloseable do
5
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: logstash-output-file_closeable
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-devutils
40
+ prerelease: false
41
+ type: :development
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ 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
48
+ email: dietmar@signifydata.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - Gemfile
55
+ - LICENSE
56
+ - Rakefile
57
+ - lib/logstash/outputs/file_closeable.rb
58
+ - logstash-output-file_closeable.gemspec
59
+ - spec/outputs/file_closeable_spec.rb
60
+ homepage: http://www.signifydata.com
61
+ licenses:
62
+ - Apache License (2.0)
63
+ metadata:
64
+ logstash_plugin: 'true'
65
+ logstash_group: output
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 2.1.9
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: This output will write events to files on disk with additional closing file of finished reading
86
+ test_files:
87
+ - spec/outputs/file_closeable_spec.rb