tailf2norikra 0.0.1
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 +7 -0
- data/LICENSE +20 -0
- data/README.md +84 -0
- data/bin/tailf2norikra +321 -0
- data/lib/tailf2norikra.rb +3 -0
- data/lib/tailf2norikra/version.rb +3 -0
- data/tailf2norikra.gemspec +31 -0
- metadata +151 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4379541d238cda27ebe548abe19ec81cd91ac986
|
4
|
+
data.tar.gz: 1ac994db1dcb5c200ee198692cfa2c2aa9624213
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 18eb2bdc2bcec3d8d33daf0d9ceb37b4d7dc375346e8aba993aabdf9986eae895f8fd00f12a4326797e875813e34264e1f83b77d84d7d5a09e03fa73dbd8aafc
|
7
|
+
data.tar.gz: 09880fad9565d47a913df0d19d1472ac4f8b43d592c575f0c090a647dc49f77e741690981d70b93b214017fe7a4559228bcbe9c10d32f5be3a1e17a820b2de49
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2015 Supersonic LTD
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# Tailf2Norikra
|
2
|
+
|
3
|
+
Watch and tail files in dirs with specified filename time based patterns and send them to norikra.
|
4
|
+
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'tailf2norikra'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle install
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install tailf2norikra
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
$ tailf2norikra -h
|
23
|
+
Usage: tailf2norikra [options]
|
24
|
+
--config PATH Path to settings config
|
25
|
+
-h, --help Display this screen
|
26
|
+
$
|
27
|
+
|
28
|
+
## Config
|
29
|
+
|
30
|
+
tailf:
|
31
|
+
files:
|
32
|
+
- target: delivery
|
33
|
+
prefix: /var/log/app/events
|
34
|
+
suffix: ''
|
35
|
+
time_pattern: ".%Y-%m-%d"
|
36
|
+
max_batch_lines: 48
|
37
|
+
timestamp_field: time
|
38
|
+
prune_events_older_than: 10
|
39
|
+
position_file: "/var/lib/app/tail2norikra.offsets"
|
40
|
+
flush_interval: 1
|
41
|
+
max_batch_lines: 1024
|
42
|
+
from_begining: false
|
43
|
+
delete_old_tailed_files: true
|
44
|
+
norikra:
|
45
|
+
host: localhost
|
46
|
+
port: 6666
|
47
|
+
send: true
|
48
|
+
|
49
|
+
* norikra.host - Norkra server
|
50
|
+
* norikra.port - Norikra port
|
51
|
+
* tailf.position_file - file where to save tailed files offsets which were sent to norikra
|
52
|
+
* tailf.flush_interval - how often in seconds to save the offsets to a file
|
53
|
+
* tailf.max_batch_lines - max number of lines to batch in each send request
|
54
|
+
* tailf.from_beggining - in case of a new file added to tailing , if to start tailing from beggining or end of the file
|
55
|
+
* tailf.delete_old_tailed_files - if to delete files once their time_pattern does not match the current time window and if they have been fully sent to norikra
|
56
|
+
* tailf.files - array of file configs for tail, each tailed file configs consists of:
|
57
|
+
* target - which target to send the events to
|
58
|
+
* prefix - the files prefix to watch for
|
59
|
+
* time_pattern - ruby time pattern of files to tail
|
60
|
+
* suffix - optional suffix of files to watch for
|
61
|
+
so the tool will watch for files that match - prefix + time_pattern + suffix
|
62
|
+
* max_batch_lines - max number of lines to batch in each send request just for this specific file pattern
|
63
|
+
* timestamp field: field which comatains timestamp/date
|
64
|
+
* prune_events_older_than: events with timestamp older than specified number of seconds will be ignored
|
65
|
+
|
66
|
+
|
67
|
+
## Features/Facts
|
68
|
+
|
69
|
+
* The config is validated by [schash](https://github.com/ryotarai/schash) gem
|
70
|
+
* Tailed files are watched for changes by [rb-notify](https://github.com/nex3/rb-inotify) gem
|
71
|
+
* Dirnames of all files prefixes are watched for new files creation or files moved to the dir and are automaticaly
|
72
|
+
added to tailing.
|
73
|
+
* As well dirnames are watched for deletion or files being moved out of directory, and they are removed from the list of files watched for changing.
|
74
|
+
* Based time_pattern, files are periodicaly autodeleted , thus avoiding need for log rotation tools.
|
75
|
+
* Files are matched by converting time_pattern to a regexp
|
76
|
+
|
77
|
+
## Contributing
|
78
|
+
|
79
|
+
1. Fork it
|
80
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
81
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
82
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
83
|
+
5. Create new Pull Request
|
84
|
+
6. Go to 1
|
data/bin/tailf2norikra
ADDED
@@ -0,0 +1,321 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'norikra-client'
|
4
|
+
require 'json'
|
5
|
+
require 'yaml'
|
6
|
+
require 'hash_symbolizer'
|
7
|
+
require 'schash'
|
8
|
+
require 'rb-inotify'
|
9
|
+
require 'timers'
|
10
|
+
require 'socket'
|
11
|
+
require 'fileutils'
|
12
|
+
require 'logger'
|
13
|
+
require 'mixlib/shellout'
|
14
|
+
require 'optparse'
|
15
|
+
|
16
|
+
$stdout.sync = true
|
17
|
+
|
18
|
+
Thread.abort_on_exception = true
|
19
|
+
|
20
|
+
@config = nil
|
21
|
+
|
22
|
+
loglevels = {
|
23
|
+
:debug => Logger::DEBUG,
|
24
|
+
:info => Logger::INFO,
|
25
|
+
:warn => Logger::WARN,
|
26
|
+
:error => Logger::Error,
|
27
|
+
:fatal => Logger::FATAL,
|
28
|
+
:unknown => Logger::UNKNOWN
|
29
|
+
}
|
30
|
+
|
31
|
+
@loglevel = Logger::INFO
|
32
|
+
|
33
|
+
opts = OptionParser.new
|
34
|
+
opts.banner = "Usage: #{$0} [options]"
|
35
|
+
opts.on( '--config PATH', String, 'Path to settings config' ) { |c| @config = c }
|
36
|
+
opts.on( '--log-level [LEVEL]', [:debug, :info, :warn, :error, :fatal, :unknown] ) { |l| @loglevel = loglevels[l] }
|
37
|
+
opts.on( '-h', '--help', 'Display this screen' ) { puts opts; exit 0 }
|
38
|
+
opts.parse!
|
39
|
+
|
40
|
+
unless @config
|
41
|
+
puts opts
|
42
|
+
exit 1
|
43
|
+
end
|
44
|
+
|
45
|
+
@logger = Logger.new(STDOUT)
|
46
|
+
|
47
|
+
@settings = YAML.load_file(@config).symbolize_keys(true)
|
48
|
+
|
49
|
+
validator = Schash::Validator.new do
|
50
|
+
{
|
51
|
+
tailf: {
|
52
|
+
files: array_of({
|
53
|
+
target: string,
|
54
|
+
prefix: string,
|
55
|
+
suffix: optional(string),
|
56
|
+
time_pattern: string,
|
57
|
+
timestamp_field: optional(string),
|
58
|
+
prune_events_older_than: optional(integer),
|
59
|
+
max_batch_lines: optional(integer)
|
60
|
+
}),
|
61
|
+
position_file: string,
|
62
|
+
flush_interval: integer,
|
63
|
+
max_batch_lines: optional(integer),
|
64
|
+
from_begining: boolean,
|
65
|
+
delete_old_tailed_files: optional(boolean),
|
66
|
+
post_delete_command: optional(string),
|
67
|
+
},
|
68
|
+
norikra: {
|
69
|
+
host: string,
|
70
|
+
port: integer
|
71
|
+
}
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
unless validator.validate(@settings).empty?
|
76
|
+
@logger.error("ERROR: bad settings")
|
77
|
+
@logger.error(validator.validate(@settings))
|
78
|
+
exit 1
|
79
|
+
end
|
80
|
+
|
81
|
+
@settings[:tailf][:files] = @settings[:tailf][:files].map{|h| h.symbolize_keys(true)}
|
82
|
+
|
83
|
+
@mutex = Mutex.new
|
84
|
+
|
85
|
+
@create_notifier = INotify::Notifier.new
|
86
|
+
@delete_notifier = INotify::Notifier.new
|
87
|
+
@tailf_notifier = INotify::Notifier.new
|
88
|
+
|
89
|
+
@dirs = {}
|
90
|
+
@files = {}
|
91
|
+
@threads = {}
|
92
|
+
@position_file = @settings[:tailf][:position_file]
|
93
|
+
@flush_interval = @settings[:tailf][:flush_interval]
|
94
|
+
@max_batch_lines = @settings[:tailf].has_key?(:max_batch_lines) ? @settings[:tailf][:max_batch_lines] : 1024
|
95
|
+
@from_begining = @settings[:tailf][:from_begining]
|
96
|
+
@delete_old_tailed_files = @settings[:tailf].has_key?(:delete_old_tailed_files) ? @settings[:tailf][:delete_old_tailed_files] : false
|
97
|
+
@norikra_host = @settings[:norikra][:host]
|
98
|
+
@norikra_port = @settings[:norikra][:port]
|
99
|
+
@send = @settings[:norikra].has_key?(:send) ? @settings[:norikra][:send] : true
|
100
|
+
|
101
|
+
def write_position_file
|
102
|
+
@mutex.synchronize do
|
103
|
+
File.open(@position_file, 'w') do |file|
|
104
|
+
@files.each do |path, attrs|
|
105
|
+
file.puts "#{path} #{attrs[:pattern]} #{attrs[:target]} #{attrs[:inode]} #{attrs[:offset]}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def load_position_file
|
112
|
+
if File.exist?(@position_file)
|
113
|
+
IO.readlines(@position_file).each do |line|
|
114
|
+
path, pattern, target, inode, offset = line.split(' ')
|
115
|
+
#Load state only for that exist with same inode and were not truncated/rewinded.
|
116
|
+
if File.exists?(path) and File.stat(path).ino == inode.to_i and File.stat(path).size >= offset.to_i
|
117
|
+
@files[path] = { :pattern => pattern, :target => target, :inode => inode.to_i, :offset => offset.to_i }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
write_position_file
|
122
|
+
end
|
123
|
+
|
124
|
+
load_position_file
|
125
|
+
|
126
|
+
@norikra = Norikra::Client.new(@norikra_host, @norikra_port)
|
127
|
+
|
128
|
+
@events_queue = SizedQueue.new(10)
|
129
|
+
|
130
|
+
@sender_thread = Thread.new do
|
131
|
+
loop do
|
132
|
+
batch = @events_queue.pop
|
133
|
+
begin
|
134
|
+
@norikra.send(batch[:target], batch[:events]) if @send
|
135
|
+
rescue Errno::ECONNREFUSED
|
136
|
+
@logger.warn("Connection refused to norikra server, retrying in 1 second ...")
|
137
|
+
sleep 1
|
138
|
+
retry
|
139
|
+
rescue Norikra::RPC::ServiceUnavailableError
|
140
|
+
@logger.warn("Got Norikra::RPC::ServiceUnavailableError while trying to senv events to norikra, retrying in 1 second ...")
|
141
|
+
sleep 1
|
142
|
+
retry
|
143
|
+
end
|
144
|
+
@files[batch[:path]][:offset] = batch[:offset]
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def norikra_send(path, buffer, offset)
|
149
|
+
prune_old_events = @files[path].has_key?(:timestamp_field) and @files[path].has_key?(:prune_events_older_than)
|
150
|
+
events = []
|
151
|
+
while event = buffer.shift
|
152
|
+
begin
|
153
|
+
event = JSON.parse(event)
|
154
|
+
if prune_old_events
|
155
|
+
unless event.has_key?(@files[path][:timestamp_field])
|
156
|
+
@logger.warn("Ignoring event without timestamp field #{@files[path][:timestamp_field]} #{event}")
|
157
|
+
else
|
158
|
+
if Time.now.to_i - event[@files[path][:timestamp_field]] > @files[path][:prune_events_older_than]
|
159
|
+
@logger.debug("Ignoring old event #{event}")
|
160
|
+
else
|
161
|
+
events << event
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
rescue => e
|
166
|
+
@logger.warn("Warning: Got bad json event #{event} #{e.message}")
|
167
|
+
end
|
168
|
+
end
|
169
|
+
@events_queue.push({ :path => path, :target => @files[path][:target], :events => events, :offset => offset})
|
170
|
+
end
|
171
|
+
|
172
|
+
def tailf(path)
|
173
|
+
file = File.open(path, 'r')
|
174
|
+
@files[path][:fd] = file
|
175
|
+
file.seek(@files[path][:offset], IO::SEEK_SET)
|
176
|
+
|
177
|
+
loop do #Fast read file in batches until we reach EOF upon which we start the tailf modify watcher
|
178
|
+
batch = file.each_line.take(@files[path][:max_batch_lines])
|
179
|
+
break if batch.empty?
|
180
|
+
norikra_send(path, batch, file.pos)
|
181
|
+
end
|
182
|
+
|
183
|
+
mutex = Mutex.new
|
184
|
+
@tailf_notifier.watch(path, :modify) do |event|
|
185
|
+
mutex.synchronize do
|
186
|
+
unless file.closed?
|
187
|
+
loop do
|
188
|
+
batch = file.each_line.take(@files[path][:max_batch_lines])
|
189
|
+
break if batch.empty?
|
190
|
+
norikra_send(path, batch, file.pos)
|
191
|
+
end
|
192
|
+
else
|
193
|
+
@logger.warn("watcher got modify event on closed file #{event.name}")
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
@time_regexp_hash = {
|
200
|
+
'Y' => '[0-9]{4}',
|
201
|
+
'm' => '[0-9]{2}',
|
202
|
+
'd' => '[0-9]{2}',
|
203
|
+
'H' => '[0-9]{2}',
|
204
|
+
'M' => '[0-9]{2}'
|
205
|
+
}
|
206
|
+
|
207
|
+
def time_pattern_to_regexp(pattern)
|
208
|
+
pattern.gsub(/%([^%])/) do
|
209
|
+
match = $1
|
210
|
+
@time_regexp_hash.has_key?(match) ? @time_regexp_hash[match] : match
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
#Scan existing files that match watched prefixes and start failing them
|
215
|
+
@settings[:tailf][:files].each do |tailf_file|
|
216
|
+
tailf_file[:prefix] = File.expand_path(tailf_file[:prefix])
|
217
|
+
dir = File.dirname(tailf_file[:prefix])
|
218
|
+
if File.exists?(dir) and File.directory?(dir)
|
219
|
+
dir_pattern_config = { :prefix => File.basename(tailf_file[:prefix]), :pattern => tailf_file[:time_pattern], :suffix => "#{tailf_file[:suffix]}", :targer => tailf_file[:target] }
|
220
|
+
dir_pattern_config[:timestamp_field] = tailf_file[:timestamp_field] if tailf_file.has_key?(:timestamp_field)
|
221
|
+
dir_pattern_config[:prune_events_older_than] = tailf_file[:prune_events_older_than] if tailf_file.has_key?(:prune_events_older_than)
|
222
|
+
dir_pattern_config[:max_batch_lines] = tailf_file.has_key?(:max_batch_lines) ? tailf_file[:max_batch_lines] : @max_batch_lines
|
223
|
+
@dirs[dir] ||= []
|
224
|
+
@dirs[dir] << dir_pattern_config
|
225
|
+
Dir.glob("#{tailf_file[:prefix]}*#{tailf_file[:suffix]}").each do |path|
|
226
|
+
if path.match(Regexp.new(time_pattern_to_regexp(tailf_file[:time_pattern])))
|
227
|
+
unless File.directory?(path)
|
228
|
+
#Populate state only if it was not loaded from position file
|
229
|
+
unless @files.has_key?(path)
|
230
|
+
@files[path] = { :pattern => tailf_file[:time_pattern], :target => tailf_file[:target], :inode => File.stat(path).ino, :offset => 0 }
|
231
|
+
@files[path][:offset] = File.stat(path).size unless @from_begining
|
232
|
+
end
|
233
|
+
@files[path][:max_batch_lines] = dir_pattern_config[:max_batch_lines]
|
234
|
+
if tailf_file.has_key?(:timestamp_field) and tailf_file.has_key?(:prune_events_older_than)
|
235
|
+
@files[path][:timestamp_field] = tailf_file[:timestamp_field]
|
236
|
+
@files[path][:prune_events_older_than] = tailf_file[:prune_events_older_than]
|
237
|
+
end
|
238
|
+
@threads[path] = Thread.new { tailf(path) } unless @threads.has_key?(path)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def delete_old_tailed_files
|
246
|
+
@mutex.synchronize do
|
247
|
+
@files.each_key do |path|
|
248
|
+
unless path.match(Regexp.new(Time.now.strftime(@files[path][:pattern])))
|
249
|
+
if File.exists?(path) and File.stat(path).ino == @files[path][:inode] and File.stat(path).size == @files[path][:offset] and (Time.now - File.stat(path).mtime) > 30
|
250
|
+
@logger.info("Deleteing old time pattern fully kafka produced file #{path}")
|
251
|
+
FileUtils.rm_r(path)
|
252
|
+
if @settings[:tailf].has_key?(:post_delete_command)
|
253
|
+
@logger.info("Running post delete command => #{@settings[:tailf][:post_delete_command]}")
|
254
|
+
command = Mixlib::ShellOut.new(@settings[:tailf][:post_delete_command])
|
255
|
+
begin
|
256
|
+
command.run_command
|
257
|
+
if command.error?
|
258
|
+
@logger.error("Failed post delete command => #{@settings[:tailf][:post_delete_command]}")
|
259
|
+
@logger.info("STDOUT: #{command.stdout}")
|
260
|
+
@logger.info("STDERR: #{command.stderr}")
|
261
|
+
end
|
262
|
+
rescue => e
|
263
|
+
@logger.error("Failed post delete command => #{@settings[:tailf][:post_delete_command]}")
|
264
|
+
@logger.info(e.message)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
@timers = Timers::Group.new
|
274
|
+
@uploads_timer = @timers.every(@flush_interval) { write_position_file }
|
275
|
+
@delete_old_tailed_files_timer = @timers.every(60) { delete_old_tailed_files } if @delete_old_tailed_files
|
276
|
+
Thread.new { loop { @timers.wait } }
|
277
|
+
|
278
|
+
@dirs.each_key do |dir|
|
279
|
+
|
280
|
+
@create_notifier.watch(dir, :create, :moved_to) do |event|
|
281
|
+
@mutex.synchronize do
|
282
|
+
path = "#{dir}/#{event.name}"
|
283
|
+
match = @dirs[dir].detect{|h| event.name.match(Regexp.new(h[:prefix] + time_pattern_to_regexp(h[:pattern]) + h[:suffix]))}
|
284
|
+
if match
|
285
|
+
unless File.directory?(path)
|
286
|
+
unless @threads.has_key?(path)
|
287
|
+
@logger.info("File #{event.name} was created in / moved into watched dir #{dir}")
|
288
|
+
@files[path] = { :pattern => match[:pattern], :target => match[:target], :inode => File.stat(path).ino, :offset => 0, :max_batch_lines => match[:max_batch_lines] }
|
289
|
+
if match.has_key?(:timestamp_field) and match.has_key?(:prune_events_older_than)
|
290
|
+
@files[path][:timestamp_field] = match[:timestamp_field]
|
291
|
+
@files[path][:prune_events_older_than] = match[:prune_events_older_than]
|
292
|
+
end
|
293
|
+
@threads[path] = Thread.new { tailf(path) }
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
@delete_notifier.watch(dir, :delete, :moved_from) do |event|
|
301
|
+
@mutex.synchronize do
|
302
|
+
path = "#{dir}/#{event.name}"
|
303
|
+
if @threads.has_key?(path)
|
304
|
+
@logger.info("File #{event.name} was deleted / moved from watched dir #{dir}")
|
305
|
+
if @threads[path].alive?
|
306
|
+
@threads[path].terminate
|
307
|
+
@threads[path].join
|
308
|
+
end
|
309
|
+
@threads.delete(path)
|
310
|
+
@files[path][:fd].close unless @files[path][:fd].closed?
|
311
|
+
@files.delete(path)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
end
|
317
|
+
|
318
|
+
Thread.new { @create_notifier.run }
|
319
|
+
Thread.new { @delete_notifier.run }
|
320
|
+
|
321
|
+
@tailf_notifier.run
|
@@ -0,0 +1,31 @@
|
|
1
|
+
lib = File.expand_path('../lib/', __FILE__)
|
2
|
+
$:.unshift lib unless $:.include?(lib)
|
3
|
+
|
4
|
+
require "tailf2norikra/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "tailf2norikra"
|
8
|
+
s.version = Tailf2Norikra::VERSION
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.authors = ["Alexander Piavlo"]
|
11
|
+
s.email = ["devops@supersonic.com"]
|
12
|
+
s.homepage = "http://github.com/SupersonicAds/tailf2norikra"
|
13
|
+
s.summary = "Watch and tail files with specified time based patterns and push them to norikra"
|
14
|
+
s.description = "Watch and tail files with specified time based patterns and push them to norikra"
|
15
|
+
s.license = 'MIT'
|
16
|
+
s.has_rdoc = false
|
17
|
+
|
18
|
+
s.add_dependency('norikra-client')
|
19
|
+
s.add_dependency('hash_symbolizer')
|
20
|
+
s.add_dependency('schash')
|
21
|
+
s.add_dependency('rb-inotify')
|
22
|
+
s.add_dependency('timers')
|
23
|
+
s.add_dependency('mixlib-shellout')
|
24
|
+
|
25
|
+
s.add_development_dependency('rake')
|
26
|
+
|
27
|
+
s.files = Dir.glob("{bin,lib}/**/*") + %w(tailf2norikra.gemspec LICENSE README.md)
|
28
|
+
s.executables = Dir.glob('bin/**/*').map { |file| File.basename(file) }
|
29
|
+
s.test_files = nil
|
30
|
+
s.require_paths = ['lib']
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tailf2norikra
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alexander Piavlo
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-01-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: norikra-client
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: hash_symbolizer
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: schash
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rb-inotify
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: timers
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: mixlib-shellout
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: Watch and tail files with specified time based patterns and push them
|
112
|
+
to norikra
|
113
|
+
email:
|
114
|
+
- devops@supersonic.com
|
115
|
+
executables:
|
116
|
+
- tailf2norikra
|
117
|
+
extensions: []
|
118
|
+
extra_rdoc_files: []
|
119
|
+
files:
|
120
|
+
- LICENSE
|
121
|
+
- README.md
|
122
|
+
- bin/tailf2norikra
|
123
|
+
- lib/tailf2norikra.rb
|
124
|
+
- lib/tailf2norikra/version.rb
|
125
|
+
- tailf2norikra.gemspec
|
126
|
+
homepage: http://github.com/SupersonicAds/tailf2norikra
|
127
|
+
licenses:
|
128
|
+
- MIT
|
129
|
+
metadata: {}
|
130
|
+
post_install_message:
|
131
|
+
rdoc_options: []
|
132
|
+
require_paths:
|
133
|
+
- lib
|
134
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
requirements: []
|
145
|
+
rubyforge_project:
|
146
|
+
rubygems_version: 2.2.2
|
147
|
+
signing_key:
|
148
|
+
specification_version: 4
|
149
|
+
summary: Watch and tail files with specified time based patterns and push them to
|
150
|
+
norikra
|
151
|
+
test_files: []
|