fluent-plugin-heroku-syslog 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/.gitignore +18 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +13 -0
- data/README.md +33 -0
- data/Rakefile +10 -0
- data/fluent-plugin-heroku-syslog.gemspec +19 -0
- data/lib/fluent/plugin/in_heroku_syslog.rb +221 -0
- data/test/helper.rb +47 -0
- data/test/plugin/test_in_heroku_syslog.rb +127 -0
- metadata +84 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c1ba40b8e6dea0a28ffed82b25787897c0ead301
|
4
|
+
data.tar.gz: e2e430813032e6445a4bf0344dca1f746580ca09
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cc75128973dfcb608908f1f930e9cf4e6eb436457a12d1cbfddc1308c902e8e56d77df21f34b153c9f32c3c9a2c3b3c47e6490eb31df67cb1c3c699d35dfbf53
|
7
|
+
data.tar.gz: 4743b87ccc0fec77eb82613a49308700995aa305a133ed68c55c39631339b4b356e14c6b1dbabe0475491ee69dddbfea839cd21cd2404aa8f4a44cae51f5f98e
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright (c) 2014- Kazuyuki Honda
|
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/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# fluent-plugin-heroku-syslog
|
2
|
+
|
3
|
+
fluent plugin to drain heroku syslog.
|
4
|
+
|
5
|
+
[](https://travis-ci.org/hakobera/fluent-plugin-heroku-syslog)
|
6
|
+
|
7
|
+
## Component
|
8
|
+
|
9
|
+
### HerokuSyslogInput
|
10
|
+
|
11
|
+
Plugin to accept syslog input from [heroku syslog drains](https://devcenter.heroku.com/articles/logging#syslog-drains).
|
12
|
+
|
13
|
+
## Configuration
|
14
|
+
|
15
|
+
```
|
16
|
+
<source>
|
17
|
+
type heroku_syslog
|
18
|
+
port 5140
|
19
|
+
bind 0.0.0.0
|
20
|
+
tag heroku
|
21
|
+
</source>
|
22
|
+
```
|
23
|
+
|
24
|
+
## TODO
|
25
|
+
|
26
|
+
- Implement authentication logic or filter like HTTP basic auth.
|
27
|
+
|
28
|
+
## Copyright
|
29
|
+
|
30
|
+
- Copyright
|
31
|
+
- Copyright(C) 2014- Kazuyuki Honda (hakobera)
|
32
|
+
- License
|
33
|
+
- Apache License, Version 2.0
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
Gem::Specification.new do |gem|
|
3
|
+
gem.name = "fluent-plugin-heroku-syslog"
|
4
|
+
gem.version = "0.0.1"
|
5
|
+
gem.authors = ["Kazuyuki Honda"]
|
6
|
+
gem.email = ["hakobera@gmail.com"]
|
7
|
+
gem.description = %q{fluent plugin to drain heroku syslog}
|
8
|
+
gem.summary = %q{fluent plugin to drain heroku syslog}
|
9
|
+
gem.homepage = "https://github.com/hakobera/fluent-plugin-heroku-syslog"
|
10
|
+
gem.license = "APLv2"
|
11
|
+
|
12
|
+
gem.files = `git ls-files`.split($\)
|
13
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
|
17
|
+
gem.add_runtime_dependency "fluentd"
|
18
|
+
gem.add_development_dependency "rake"
|
19
|
+
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
module Fluent
|
2
|
+
class HerokuSyslogInput < Input
|
3
|
+
Plugin.register_input('heroku_syslog', self)
|
4
|
+
|
5
|
+
OCTET_COUNTING_REGEXP = /^([0-9]+)\s+(.*)/
|
6
|
+
SYSLOG_REGEXP = /^\<([0-9]+)\>[0-9]*(.*)/
|
7
|
+
SYSLOG_ALL_REGEXP = /^\<(?<pri>[0-9]+)\>[0-9]* (?<time>[^ ]*) (?<drain_id>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*) (?<pid>[a-zA-Z0-9\.]+)? *(?<message>.*)$/
|
8
|
+
TIME_FORMAT = "%Y-%m-%dT%H:%M:%S%z"
|
9
|
+
|
10
|
+
FACILITY_MAP = {
|
11
|
+
0 => 'kern',
|
12
|
+
1 => 'user',
|
13
|
+
2 => 'mail',
|
14
|
+
3 => 'daemon',
|
15
|
+
4 => 'auth',
|
16
|
+
5 => 'syslog',
|
17
|
+
6 => 'lpr',
|
18
|
+
7 => 'news',
|
19
|
+
8 => 'uucp',
|
20
|
+
9 => 'cron',
|
21
|
+
10 => 'authpriv',
|
22
|
+
11 => 'ftp',
|
23
|
+
12 => 'ntp',
|
24
|
+
13 => 'audit',
|
25
|
+
14 => 'alert',
|
26
|
+
15 => 'at',
|
27
|
+
16 => 'local0',
|
28
|
+
17 => 'local1',
|
29
|
+
18 => 'local2',
|
30
|
+
19 => 'local3',
|
31
|
+
20 => 'local4',
|
32
|
+
21 => 'local5',
|
33
|
+
22 => 'local6',
|
34
|
+
23 => 'local7'
|
35
|
+
}
|
36
|
+
|
37
|
+
PRIORITY_MAP = {
|
38
|
+
0 => 'emerg',
|
39
|
+
1 => 'alert',
|
40
|
+
2 => 'crit',
|
41
|
+
3 => 'err',
|
42
|
+
4 => 'warn',
|
43
|
+
5 => 'notice',
|
44
|
+
6 => 'info',
|
45
|
+
7 => 'debug'
|
46
|
+
}
|
47
|
+
|
48
|
+
def initialize
|
49
|
+
super
|
50
|
+
require 'cool.io'
|
51
|
+
require 'fluent/plugin/socket_util'
|
52
|
+
end
|
53
|
+
|
54
|
+
config_param :port, :integer, :default => 5140
|
55
|
+
config_param :bind, :string, :default => '0.0.0.0'
|
56
|
+
config_param :tag, :string
|
57
|
+
|
58
|
+
def configure(conf)
|
59
|
+
super
|
60
|
+
|
61
|
+
parser = TextParser.new
|
62
|
+
if parser.configure(conf, false)
|
63
|
+
@parser = parser
|
64
|
+
else
|
65
|
+
@parser = nil
|
66
|
+
@time_parser = TextParser::TimeParser.new(TIME_FORMAT)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def start
|
71
|
+
if @parser
|
72
|
+
callback = method(:receive_data_parser)
|
73
|
+
else
|
74
|
+
callback = method(:receive_data)
|
75
|
+
end
|
76
|
+
|
77
|
+
@loop = Coolio::Loop.new
|
78
|
+
@handler = listen(callback)
|
79
|
+
@loop.attach(@handler)
|
80
|
+
|
81
|
+
@thread = Thread.new(&method(:run))
|
82
|
+
end
|
83
|
+
|
84
|
+
def shutdown
|
85
|
+
@loop.watchers.each {|w| w.detach }
|
86
|
+
@loop.stop
|
87
|
+
@handler.close
|
88
|
+
@thread.join
|
89
|
+
end
|
90
|
+
|
91
|
+
def run
|
92
|
+
@loop.run
|
93
|
+
rescue
|
94
|
+
$log.error "unexpected error", :error=>$!.to_s
|
95
|
+
$log.error_backtrace
|
96
|
+
end
|
97
|
+
|
98
|
+
protected
|
99
|
+
def receive_data_parser(data)
|
100
|
+
m = SYSLOG_REGEXP.match(data)
|
101
|
+
unless m
|
102
|
+
$log.debug "invalid syslog message: #{data.dump}"
|
103
|
+
return
|
104
|
+
end
|
105
|
+
pri = m[1].to_i
|
106
|
+
text = m[2]
|
107
|
+
|
108
|
+
time, record = @parser.parse(text)
|
109
|
+
unless time && record
|
110
|
+
return
|
111
|
+
end
|
112
|
+
|
113
|
+
emit(pri, time, record)
|
114
|
+
|
115
|
+
rescue
|
116
|
+
$log.warn data.dump, :error=>$!.to_s
|
117
|
+
$log.debug_backtrace
|
118
|
+
end
|
119
|
+
|
120
|
+
def receive_data(data)
|
121
|
+
m = SYSLOG_ALL_REGEXP.match(data)
|
122
|
+
unless m
|
123
|
+
$log.debug "invalid syslog message", :data=>data
|
124
|
+
return
|
125
|
+
end
|
126
|
+
|
127
|
+
pri = nil
|
128
|
+
time = nil
|
129
|
+
record = {}
|
130
|
+
|
131
|
+
m.names.each {|name|
|
132
|
+
if value = m[name]
|
133
|
+
case name
|
134
|
+
when "pri"
|
135
|
+
pri = value.to_i
|
136
|
+
when "time"
|
137
|
+
time = @time_parser.parse(value.gsub(/ +/, ' ').gsub(/\.[0-9]+/, ''))
|
138
|
+
else
|
139
|
+
record[name] = value
|
140
|
+
end
|
141
|
+
end
|
142
|
+
}
|
143
|
+
|
144
|
+
time ||= Engine.now
|
145
|
+
|
146
|
+
emit(pri, time, record)
|
147
|
+
|
148
|
+
rescue
|
149
|
+
$log.warn data.dump, :error=>$!.to_s
|
150
|
+
$log.debug_backtrace
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
def listen(callback)
|
156
|
+
$log.debug "listening heroku syslog socket on #{@bind}:#{@port}"
|
157
|
+
Coolio::TCPServer.new(@bind, @port, TcpHandler, callback)
|
158
|
+
end
|
159
|
+
|
160
|
+
def emit(pri, time, record)
|
161
|
+
facility = FACILITY_MAP[pri >> 3]
|
162
|
+
priority = PRIORITY_MAP[pri & 0b111]
|
163
|
+
|
164
|
+
tag = "#{@tag}.#{facility}.#{priority}"
|
165
|
+
|
166
|
+
Engine.emit(tag, time, record)
|
167
|
+
rescue => e
|
168
|
+
$log.error "syslog failed to emit", :error => e.to_s, :error_class => e.class.to_s, :tag => tag, :record => Yajl.dump(record)
|
169
|
+
end
|
170
|
+
|
171
|
+
class TcpHandler < Coolio::Socket
|
172
|
+
def initialize(io, on_message)
|
173
|
+
super(io)
|
174
|
+
if io.is_a?(TCPSocket)
|
175
|
+
opt = [1, @timeout.to_i].pack('I!I!') # { int l_onoff; int l_linger; }
|
176
|
+
io.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, opt)
|
177
|
+
end
|
178
|
+
$log.trace { "accepted fluent socket object_id=#{self.object_id}" }
|
179
|
+
@on_message = on_message
|
180
|
+
@buffer = "".force_encoding('ASCII-8BIT')
|
181
|
+
end
|
182
|
+
|
183
|
+
def on_connect
|
184
|
+
end
|
185
|
+
|
186
|
+
def on_read(data)
|
187
|
+
@buffer << data
|
188
|
+
pos = 0
|
189
|
+
|
190
|
+
# syslog family add "\n" to each message and this seems only way to split messages in tcp stream
|
191
|
+
while i = @buffer.index("\n", pos)
|
192
|
+
msg = @buffer[pos..i]
|
193
|
+
|
194
|
+
# Support Octet Counting
|
195
|
+
# https://tools.ietf.org/html/rfc6587#section-3.4.1
|
196
|
+
m = OCTET_COUNTING_REGEXP.match(msg)
|
197
|
+
valid = true
|
198
|
+
if m
|
199
|
+
msg_len = m[1].to_i - 1
|
200
|
+
msg = m[2]
|
201
|
+
|
202
|
+
if msg_len != msg.length
|
203
|
+
$log.debug "invalid syslog message length", :expected => msg_len, :actual => msg.length, :data => msg
|
204
|
+
valid = false
|
205
|
+
end
|
206
|
+
end
|
207
|
+
@on_message.call(msg) if valid
|
208
|
+
pos = i + 1
|
209
|
+
end
|
210
|
+
@buffer.slice!(0, pos) if pos > 0
|
211
|
+
rescue => e
|
212
|
+
$log.error "syslog error", :error => e, :error_class => e.class
|
213
|
+
close
|
214
|
+
end
|
215
|
+
|
216
|
+
def on_close
|
217
|
+
$log.trace { "closed fluent socket object_id=#{self.object_id}" }
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
|
12
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
13
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
14
|
+
|
15
|
+
require 'fileutils'
|
16
|
+
require 'fluent/log'
|
17
|
+
require 'fluent/test'
|
18
|
+
|
19
|
+
$log = Fluent::Log.new(STDOUT, Fluent::Log::LEVEL_DEBUG)
|
20
|
+
|
21
|
+
unless defined?(Test::Unit::AssertionFailedError)
|
22
|
+
class Test::Unit::AssertionFailedError < StandardError
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def unused_port
|
27
|
+
s = TCPServer.open(0)
|
28
|
+
port = s.addr[1]
|
29
|
+
s.close
|
30
|
+
port
|
31
|
+
end
|
32
|
+
|
33
|
+
def ipv6_enabled?
|
34
|
+
require 'socket'
|
35
|
+
|
36
|
+
begin
|
37
|
+
TCPServer.open("::1", 0)
|
38
|
+
true
|
39
|
+
rescue
|
40
|
+
false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
require 'fluent/plugin/in_heroku_syslog'
|
45
|
+
|
46
|
+
class Test::Unit::TestCase
|
47
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class HerokuSyslogInputTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
Fluent::Test.setup
|
6
|
+
end
|
7
|
+
|
8
|
+
PORT = unused_port
|
9
|
+
CONFIG = %[
|
10
|
+
port #{PORT}
|
11
|
+
bind 127.0.0.1
|
12
|
+
tag heroku.syslog
|
13
|
+
]
|
14
|
+
|
15
|
+
IPv6_CONFIG = %[
|
16
|
+
port #{PORT}
|
17
|
+
bind ::1
|
18
|
+
tag syslog
|
19
|
+
]
|
20
|
+
|
21
|
+
def create_driver(conf=CONFIG)
|
22
|
+
Fluent::Test::InputTestDriver.new(Fluent::HerokuSyslogInput).configure(conf)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_configure
|
26
|
+
configs = {'127.0.0.1' => CONFIG}
|
27
|
+
configs.merge!('::1' => IPv6_CONFIG) if ipv6_enabled?
|
28
|
+
|
29
|
+
configs.each_pair { |k, v|
|
30
|
+
d = create_driver(v)
|
31
|
+
assert_equal PORT, d.instance.port
|
32
|
+
assert_equal k, d.instance.bind
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_time_format
|
37
|
+
configs = {'127.0.0.1' => CONFIG}
|
38
|
+
configs.merge!('::1' => IPv6_CONFIG) if ipv6_enabled?
|
39
|
+
|
40
|
+
configs.each_pair { |k, v|
|
41
|
+
d = create_driver(v)
|
42
|
+
|
43
|
+
tests = [
|
44
|
+
{
|
45
|
+
'msg' => "92 <13>1 2014-01-29T06:25:52.589365+00:00 d.916a3e50-efa1-4754-aded-ffffffffffff app web.1 foo\n",
|
46
|
+
'expected' => Time.strptime('2014-01-29T06:25:52+00:00', '%Y-%m-%dT%H:%M:%S%z').to_i
|
47
|
+
},
|
48
|
+
{
|
49
|
+
'msg' => "92 <13>1 2014-01-30T07:35:00.123456+09:00 d.916a3e50-efa1-4754-aded-ffffffffffff app web.1 bar\n",
|
50
|
+
'expected' => Time.strptime('2014-01-30T07:35:00+09:00', '%Y-%m-%dT%H:%M:%S%z').to_i
|
51
|
+
}
|
52
|
+
]
|
53
|
+
|
54
|
+
d.run do
|
55
|
+
tests.each {|test|
|
56
|
+
TCPSocket.open(k, PORT) do |s|
|
57
|
+
s.send(test['msg'], 0)
|
58
|
+
end
|
59
|
+
}
|
60
|
+
sleep 1
|
61
|
+
end
|
62
|
+
|
63
|
+
emits = d.emits
|
64
|
+
$log.debug emits
|
65
|
+
emits.each_index {|i|
|
66
|
+
$log.debug emits[i][1]
|
67
|
+
assert_equal(tests[i]['expected'], emits[i][1])
|
68
|
+
}
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_msg_size
|
73
|
+
d = create_driver
|
74
|
+
tests = create_test_case
|
75
|
+
|
76
|
+
d.run do
|
77
|
+
tests.each {|test|
|
78
|
+
TCPSocket.open('127.0.0.1', PORT) do |s|
|
79
|
+
s.send(test['msg'], 0)
|
80
|
+
end
|
81
|
+
}
|
82
|
+
sleep 1
|
83
|
+
end
|
84
|
+
|
85
|
+
compare_test_result(d.emits, tests)
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_msg_size_with_same_tcp_connection
|
89
|
+
d = create_driver
|
90
|
+
tests = create_test_case
|
91
|
+
|
92
|
+
d.run do
|
93
|
+
TCPSocket.open('127.0.0.1', PORT) do |s|
|
94
|
+
tests.each {|test|
|
95
|
+
s.send(test['msg'], 0)
|
96
|
+
}
|
97
|
+
end
|
98
|
+
sleep 1
|
99
|
+
end
|
100
|
+
|
101
|
+
compare_test_result(d.emits, tests)
|
102
|
+
end
|
103
|
+
|
104
|
+
def create_test_case
|
105
|
+
# actual syslog message has "\n"
|
106
|
+
msgs = [
|
107
|
+
{'msg' => '<13>1 2014-01-01T01:23:45.123456+00:00 d.916a3e50-efa1-4754-aded-ffffffffffff app web.1 ' + 'x' * 100 + "\n", 'expected' => 'x' * 100},
|
108
|
+
{'msg' => '<13>1 2014-01-01T01:23:45.123456+00:00 d.916a3e50-efa1-4754-aded-ffffffffffff app web.1 ' + 'x' * 1024 + "\n", 'expected' => 'x' * 1024},
|
109
|
+
]
|
110
|
+
|
111
|
+
msgs.each do |msg|
|
112
|
+
msg['msg'] = "#{msg['msg'].length} #{msg['msg']}"
|
113
|
+
end
|
114
|
+
|
115
|
+
msgs
|
116
|
+
end
|
117
|
+
|
118
|
+
def compare_test_result(emits, tests)
|
119
|
+
emits.each_index {|i|
|
120
|
+
assert_equal(tests[i]['expected'], emits[i][2]['message'])
|
121
|
+
assert_equal('d.916a3e50-efa1-4754-aded-ffffffffffff', emits[i][2]['drain_id'])
|
122
|
+
assert_equal('app', emits[i][2]['ident'])
|
123
|
+
assert_equal('web.1', emits[i][2]['pid'])
|
124
|
+
}
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fluent-plugin-heroku-syslog
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kazuyuki Honda
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-01-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: fluentd
|
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: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: fluent plugin to drain heroku syslog
|
42
|
+
email:
|
43
|
+
- hakobera@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ".gitignore"
|
49
|
+
- ".travis.yml"
|
50
|
+
- Gemfile
|
51
|
+
- LICENSE.txt
|
52
|
+
- README.md
|
53
|
+
- Rakefile
|
54
|
+
- fluent-plugin-heroku-syslog.gemspec
|
55
|
+
- lib/fluent/plugin/in_heroku_syslog.rb
|
56
|
+
- test/helper.rb
|
57
|
+
- test/plugin/test_in_heroku_syslog.rb
|
58
|
+
homepage: https://github.com/hakobera/fluent-plugin-heroku-syslog
|
59
|
+
licenses:
|
60
|
+
- APLv2
|
61
|
+
metadata: {}
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
requirements: []
|
77
|
+
rubyforge_project:
|
78
|
+
rubygems_version: 2.2.0
|
79
|
+
signing_key:
|
80
|
+
specification_version: 4
|
81
|
+
summary: fluent plugin to drain heroku syslog
|
82
|
+
test_files:
|
83
|
+
- test/helper.rb
|
84
|
+
- test/plugin/test_in_heroku_syslog.rb
|