fluent-plugin-http-record-modifier 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +54 -0
- data/Rakefile +10 -0
- data/fluent-plugin-http-record-modifier.gemspec +24 -0
- data/lib/fluent/plugin/.filter_http_record_modifier.rb.swp +0 -0
- data/lib/fluent/plugin/filter_http_record_modifier.rb +288 -0
- metadata +94 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2ea15085273d646c9d75d934aa5b2e90eeef89af
|
4
|
+
data.tar.gz: 693781df064fceb076c7d99a8718a89724898aa8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d938f24e8a733b6a9161f94e09d066d2eed540d29a5487684c14e226867a92f8fb6f7fa229ab49a09d25a89d178c2379245c65d77ad4e2ecd251d651e4a40122
|
7
|
+
data.tar.gz: 859c43d550ef56cc379bf899c6fbf7e43964103d4369fe85d9eb70e2c87b4e245eb50f8edb9ce0bec993b31600968a06fb13cfcbd66e04f6910ecdeba79cebac
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Augusto Nishi
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# Fluent::Plugin::Simple Value to Hash
|
2
|
+
|
3
|
+
Fluent plugin for converting simple value variables to hash to be usable to others plugins
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'fluent-plugin-http-record-modifier'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install fluent-plugin-http-record-modifier
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
```
|
22
|
+
|
23
|
+
<filter tag>
|
24
|
+
type http_record_modifier
|
25
|
+
method (defaults to GET)
|
26
|
+
renew_record (defaults to false)
|
27
|
+
endpoint_url yourapi.com/api/something/
|
28
|
+
serializer (form or json, just used on POST)
|
29
|
+
authentication (none or basic, defaults to none)
|
30
|
+
username (default to '')
|
31
|
+
password (default to '')
|
32
|
+
<params>
|
33
|
+
var ${tag_parts[1]}
|
34
|
+
var2 ${record_attr}
|
35
|
+
</params>
|
36
|
+
<record>
|
37
|
+
name ${body.name}
|
38
|
+
body ${body}
|
39
|
+
array ${body.array}
|
40
|
+
second ${body.array[1]}
|
41
|
+
last ${body.array[-1]}
|
42
|
+
deep ${body.array[0].attr}
|
43
|
+
</record>
|
44
|
+
</filter>
|
45
|
+
|
46
|
+
```
|
47
|
+
|
48
|
+
## Contributing
|
49
|
+
|
50
|
+
1. Fork it ( http://github.com/DEVTecnologia/fluent-plugin-http-record-modifier/fork )
|
51
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
52
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
53
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
54
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "fluent-plugin-http-record-modifier"
|
7
|
+
spec.version = "0.0.0"
|
8
|
+
spec.authors = ["Augusto Nishi"]
|
9
|
+
spec.email = ["augusto.nishi@gmail.com"]
|
10
|
+
spec.summary = %q{fluentd filter plugin for modifing record based on a HTTP request}
|
11
|
+
spec.description = %q{fluentd filter plugin for modifing record based on a HTTP request}
|
12
|
+
spec.homepage = "http://github.com/DEVTecnologia/fluent-plugin-http-record-modifier"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
21
|
+
spec.add_development_dependency "rake"
|
22
|
+
spec.add_development_dependency "fluentd"
|
23
|
+
|
24
|
+
end
|
Binary file
|
@@ -0,0 +1,288 @@
|
|
1
|
+
module Fluent
|
2
|
+
class HttpRecordModifier < Filter
|
3
|
+
Plugin.register_filter('http_record_modifier', self)
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
require 'socket'
|
7
|
+
require 'yajl'
|
8
|
+
require 'net/http'
|
9
|
+
require 'uri'
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
#Based on Filter Record Tranformer that is built-in on Fluent
|
14
|
+
config_param :remove_keys, :string, :default => nil
|
15
|
+
config_param :keep_keys, :string, :default => nil
|
16
|
+
config_param :method, :string, :default => :get
|
17
|
+
config_param :rene_record, :bool, :default => false
|
18
|
+
config_param :auto_typecast, :bool, :default => false # false for lower version compatibility
|
19
|
+
config_param :endpoint_url, :string
|
20
|
+
config_param :serializer, :string, :default => :form
|
21
|
+
config_param :authentication, :string, :default => nil
|
22
|
+
config_param :username, :string, :default => ''
|
23
|
+
config_param :password, :string, :default => ''
|
24
|
+
config_param :raise_on_error, :bool, :default => true
|
25
|
+
|
26
|
+
def configure(conf)
|
27
|
+
super
|
28
|
+
@method ||= conf['method']
|
29
|
+
@map = {}
|
30
|
+
# <record></record> directive
|
31
|
+
conf.elements.select { |element| element.name == 'record' }.each do |element|
|
32
|
+
element.each_pair do |k, v|
|
33
|
+
element.has_key?(k) # to suppress unread configuration warning
|
34
|
+
@map[k] = parse_value(v)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
@maped_params = {}
|
39
|
+
# <params></params> directive
|
40
|
+
conf.elements.select { |element| element.name == 'params' }.each do |element|
|
41
|
+
element.each_pair do |k, v|
|
42
|
+
element.has_key?(k) # to suppress unread configuration warning
|
43
|
+
@maped_params[k] = parse_value(v)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
if @remove_keys
|
48
|
+
@remove_keys = @remove_keys.split(',')
|
49
|
+
end
|
50
|
+
|
51
|
+
if @keep_keys
|
52
|
+
raise Fluent::ConfigError, "`renew_record` must be true to use `keep_keys`" unless @renew_record
|
53
|
+
@keep_keys = @keep_keys.split(',')
|
54
|
+
end
|
55
|
+
|
56
|
+
@placeholder_expander = PlaceholderExpander.new({
|
57
|
+
:log => log,
|
58
|
+
:auto_typecast => @auto_typecast,
|
59
|
+
})
|
60
|
+
|
61
|
+
@hostname = Socket.gethostname
|
62
|
+
end
|
63
|
+
|
64
|
+
def filter_stream(tag, es)
|
65
|
+
new_es = MultiEventStream.new
|
66
|
+
tag_parts = tag.split('.')
|
67
|
+
tag_prefix = tag_prefix(tag_parts)
|
68
|
+
tag_suffix = tag_suffix(tag_parts)
|
69
|
+
placeholders = {
|
70
|
+
'tag' => tag,
|
71
|
+
'tag_parts' => tag_parts,
|
72
|
+
'tag_prefix' => tag_prefix,
|
73
|
+
'tag_suffix' => tag_suffix,
|
74
|
+
'hostname' => @hostname,
|
75
|
+
}
|
76
|
+
last_record = nil
|
77
|
+
es.each do |time, record|
|
78
|
+
last_record = record # for debug log
|
79
|
+
req, uri = create_request(tag, time, record)
|
80
|
+
res = send_request(req, uri)
|
81
|
+
body = deserialize_body(res)
|
82
|
+
new_record = reform(time, record, placeholders, body)
|
83
|
+
if @renew_time_key && new_record.has_key?(@renew_time_key)
|
84
|
+
time = new_record[@renew_time_key].to_i
|
85
|
+
end
|
86
|
+
new_es.add(time, new_record)
|
87
|
+
end
|
88
|
+
new_es
|
89
|
+
rescue => e
|
90
|
+
log.warn "failed to reform records", :error_class => e.class, :error => e.message
|
91
|
+
log.warn_backtrace
|
92
|
+
log.debug "map:#{@map} record:#{last_record} placeholders:#{placeholders}"
|
93
|
+
end
|
94
|
+
|
95
|
+
def deserialize_body(res)
|
96
|
+
clean = {}
|
97
|
+
body = res.body
|
98
|
+
if res.content_type == 'application/json'
|
99
|
+
body = Yajl.load(body)
|
100
|
+
if body.is_a? Hash
|
101
|
+
clean = Yajl.load(res.body)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
clean['body'] = body
|
105
|
+
clean
|
106
|
+
end
|
107
|
+
|
108
|
+
def format_params(tag, time, record)
|
109
|
+
tag_parts = tag.split('.')
|
110
|
+
tag_prefix = tag_prefix(tag_parts)
|
111
|
+
tag_suffix = tag_suffix(tag_parts)
|
112
|
+
placeholders = {
|
113
|
+
'tag' => tag,
|
114
|
+
'tag_parts' => tag_parts,
|
115
|
+
'tag_prefix' => tag_prefix,
|
116
|
+
'tag_suffix' => tag_suffix,
|
117
|
+
'hostname' => @hostname,
|
118
|
+
}
|
119
|
+
@placeholder_expander.prepare_placeholders(time, record, placeholders)
|
120
|
+
|
121
|
+
expand_placeholders(@maped_params)
|
122
|
+
end
|
123
|
+
|
124
|
+
def set_body(req, tag, time, record)
|
125
|
+
if @serializer == :json
|
126
|
+
req['Content-Type'] = 'application/json'
|
127
|
+
else
|
128
|
+
req.set_form_data(record)
|
129
|
+
end
|
130
|
+
req
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
def create_request(tag, time, record)
|
135
|
+
url = URI.encode(@endpoint_url.to_s)
|
136
|
+
uri = URI.parse(url)
|
137
|
+
params = format_params(tag, time, record)
|
138
|
+
uri.query = URI.encode_www_form(params)
|
139
|
+
req = Net::HTTP.const_get(@method.to_s.capitalize).new(uri)
|
140
|
+
unless @method.to_s.capitalize == 'Get'
|
141
|
+
set_body(req, tag, time, record)
|
142
|
+
end
|
143
|
+
return req, uri
|
144
|
+
end
|
145
|
+
|
146
|
+
def send_request(req, uri)
|
147
|
+
res = nil
|
148
|
+
|
149
|
+
begin
|
150
|
+
if @auth and @auth == :basic
|
151
|
+
req.basic_auth(@username, @password)
|
152
|
+
end
|
153
|
+
res = Net::HTTP.new(uri.host, uri.port).start {|http| http.request(req) }
|
154
|
+
rescue => e # rescue all StandardErrors
|
155
|
+
# server didn't respond
|
156
|
+
$log.warn "Net::HTTP.#{req.method.capitalize} raises exception: #{e.class}, '#{e.message}'"
|
157
|
+
raise e if @raise_on_error
|
158
|
+
end # end begin
|
159
|
+
end # end send_request
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
def parse_value(value_str)
|
164
|
+
if value_str.start_with?('{', '[')
|
165
|
+
JSON.parse(value_str)
|
166
|
+
else
|
167
|
+
value_str
|
168
|
+
end
|
169
|
+
rescue => e
|
170
|
+
log.warn "failed to parse #{value_str} as json. Assuming #{value_str} is a string", :error_class => e.class, :error => e.message
|
171
|
+
value_str # emit as string
|
172
|
+
end
|
173
|
+
|
174
|
+
def reform(time, record, opts, res)
|
175
|
+
@placeholder_expander.prepare_placeholders(time, res, opts)
|
176
|
+
|
177
|
+
new_record = @renew_record ? {} : record.dup
|
178
|
+
@keep_keys.each {|k| new_record[k] = record[k]} if @keep_keys and @renew_record
|
179
|
+
new_record.merge!(expand_placeholders(@map))
|
180
|
+
@remove_keys.each {|k| new_record.delete(k) } if @remove_keys
|
181
|
+
|
182
|
+
new_record
|
183
|
+
end
|
184
|
+
|
185
|
+
def expand_placeholders(value)
|
186
|
+
if value.is_a?(String)
|
187
|
+
new_value = @placeholder_expander.expand(value)
|
188
|
+
elsif value.is_a?(Hash)
|
189
|
+
new_value = {}
|
190
|
+
value.each_pair do |k, v|
|
191
|
+
new_value[@placeholder_expander.expand(k, true)] = expand_placeholders(v)
|
192
|
+
end
|
193
|
+
elsif value.is_a?(Array)
|
194
|
+
new_value = []
|
195
|
+
value.each_with_index do |v, i|
|
196
|
+
new_value[i] = expand_placeholders(v)
|
197
|
+
end
|
198
|
+
else
|
199
|
+
new_value = value
|
200
|
+
end
|
201
|
+
new_value
|
202
|
+
end
|
203
|
+
|
204
|
+
def tag_prefix(tag_parts)
|
205
|
+
return [] if tag_parts.empty?
|
206
|
+
tag_prefix = [tag_parts.first]
|
207
|
+
1.upto(tag_parts.size-1).each do |i|
|
208
|
+
tag_prefix[i] = "#{tag_prefix[i-1]}.#{tag_parts[i]}"
|
209
|
+
end
|
210
|
+
tag_prefix
|
211
|
+
end
|
212
|
+
|
213
|
+
def tag_suffix(tag_parts)
|
214
|
+
return [] if tag_parts.empty?
|
215
|
+
rev_tag_parts = tag_parts.reverse
|
216
|
+
rev_tag_suffix = [rev_tag_parts.first]
|
217
|
+
1.upto(tag_parts.size-1).each do |i|
|
218
|
+
rev_tag_suffix[i] = "#{rev_tag_parts[i]}.#{rev_tag_suffix[i-1]}"
|
219
|
+
end
|
220
|
+
rev_tag_suffix.reverse!
|
221
|
+
end
|
222
|
+
|
223
|
+
class PlaceholderExpander
|
224
|
+
attr_reader :placeholders, :log
|
225
|
+
|
226
|
+
def initialize(params)
|
227
|
+
@log = params[:log]
|
228
|
+
@auto_typecast = params[:auto_typecast]
|
229
|
+
end
|
230
|
+
|
231
|
+
def prepare_placeholders(time, record, opts)
|
232
|
+
placeholders = { '${time}' => Time.at(time).to_s }
|
233
|
+
record.each {|key, value| crawl_placeholder(value, placeholders, "#{key}")
|
234
|
+
}
|
235
|
+
opts.each do |key, value|
|
236
|
+
if value.kind_of?(Array) # tag_parts, etc
|
237
|
+
size = value.size
|
238
|
+
value.each_with_index { |v, idx|
|
239
|
+
placeholders.store("${#{key}[#{idx}]}", v)
|
240
|
+
placeholders.store("${#{key}[#{idx-size}]}", v) # support [-1]
|
241
|
+
}
|
242
|
+
else # string, interger, float, and others?
|
243
|
+
placeholders.store("${#{key}}", value)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
@placeholders = placeholders
|
248
|
+
end
|
249
|
+
|
250
|
+
def crawl_placeholder (value, placeholder, before, limit = 50)
|
251
|
+
if limit >= 0
|
252
|
+
if value.kind_of?(Hash)
|
253
|
+
value.each {|key, v| crawl_placeholder(v, placeholder, "#{before}.#{key}", limit - 1)}
|
254
|
+
elsif value.kind_of?(Array) # tag_parts, etc
|
255
|
+
size = value.size
|
256
|
+
value.each_with_index { |v, idx|
|
257
|
+
crawl_placeholder(v, placeholder, "#{before}[#{idx}]", limit - 1)
|
258
|
+
crawl_placeholder(v, placeholder, "#{before}[#{idx-size}]", limit - 1) #suport [-1]
|
259
|
+
}
|
260
|
+
end
|
261
|
+
end
|
262
|
+
# string, interger, float, and others?
|
263
|
+
placeholder.store("${#{before}}", value)
|
264
|
+
end
|
265
|
+
|
266
|
+
def expand(str, force_stringify=false)
|
267
|
+
if @auto_typecast and !force_stringify
|
268
|
+
single_placeholder_matched = str.match(/\A(\${[^}]+}|__[A-Z_]+__)\z/)
|
269
|
+
if single_placeholder_matched
|
270
|
+
log_unknown_placeholder($1)
|
271
|
+
return @placeholders[single_placeholder_matched[1]]
|
272
|
+
end
|
273
|
+
end
|
274
|
+
str.gsub(/(\${[^}]+}|__[A-Z_]+__)/) {
|
275
|
+
log_unknown_placeholder($1)
|
276
|
+
@placeholders[$1]
|
277
|
+
}
|
278
|
+
end
|
279
|
+
|
280
|
+
private
|
281
|
+
def log_unknown_placeholder(placeholder)
|
282
|
+
unless @placeholders.include?(placeholder)
|
283
|
+
log.warn "unknown placeholder `#{placeholder}` found"
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
metadata
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fluent-plugin-http-record-modifier
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Augusto Nishi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-07-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
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
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: fluentd
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: fluentd filter plugin for modifing record based on a HTTP request
|
56
|
+
email:
|
57
|
+
- augusto.nishi@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- Gemfile
|
64
|
+
- LICENSE.txt
|
65
|
+
- README.md
|
66
|
+
- Rakefile
|
67
|
+
- fluent-plugin-http-record-modifier.gemspec
|
68
|
+
- lib/fluent/plugin/.filter_http_record_modifier.rb.swp
|
69
|
+
- lib/fluent/plugin/filter_http_record_modifier.rb
|
70
|
+
homepage: http://github.com/DEVTecnologia/fluent-plugin-http-record-modifier
|
71
|
+
licenses:
|
72
|
+
- MIT
|
73
|
+
metadata: {}
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options: []
|
76
|
+
require_paths:
|
77
|
+
- lib
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
requirements: []
|
89
|
+
rubyforge_project:
|
90
|
+
rubygems_version: 2.2.1
|
91
|
+
signing_key:
|
92
|
+
specification_version: 4
|
93
|
+
summary: fluentd filter plugin for modifing record based on a HTTP request
|
94
|
+
test_files: []
|