logstash-output-file_closeable 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/Gemfile +2 -0
- data/LICENSE +13 -0
- data/Rakefile +7 -0
- data/lib/logstash/outputs/file_closeable.rb +195 -0
- data/logstash-output-file_closeable.gemspec +27 -0
- data/spec/outputs/file_closeable_spec.rb +5 -0
- metadata +87 -0
checksums.yaml
ADDED
@@ -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
|
data/.gitignore
ADDED
data/Gemfile
ADDED
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,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
|
+
|
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
|