fluent-plugin-record-reformer 0.8.3 → 0.9.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.
- checksums.yaml +4 -4
- data/.travis.yml +3 -3
- data/CHANGELOG.md +6 -0
- data/README.md +8 -2
- data/fluent-plugin-record-reformer.gemspec +1 -1
- data/lib/fluent/plugin/out_record_reformer.rb +6 -355
- data/lib/fluent/plugin/out_record_reformer/core.rb +345 -0
- data/lib/fluent/plugin/out_record_reformer/v12.rb +32 -0
- data/lib/fluent/plugin/out_record_reformer/v14.rb +22 -0
- data/test/helper.rb +45 -0
- data/test/test_out_record_reformer.rb +20 -24
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 224873397bd762ffdf8b4256c727f0d274c0f39b
|
4
|
+
data.tar.gz: 3c2f1c849c49d690c1e583ac03ecd3817ba670ea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8dbc917cf34ea266ec33e4a39c59e87536856bf43af2ea1889714b71eb3d1145dc03f45789d7af99b6c89f9d36b581fd171ca94188c1afe25d19bcf3153464a
|
7
|
+
data.tar.gz: 9c47cd0a33f18d0b3f62ecc43077df7c1a2710aca5e110d39225a4c2a66e89823826ba3685f9f444f921098897fb67c1b71941575d3580d578e0817f9c4ee9ae
|
data/.travis.yml
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
rvm:
|
2
|
-
- 2.0.*
|
3
2
|
- 2.1.*
|
4
3
|
- 2.2.*
|
5
4
|
- 2.3.0
|
5
|
+
- 2.4.0
|
6
6
|
gemfile:
|
7
7
|
- Gemfile
|
8
8
|
- Gemfile.fluentd.0.12
|
9
9
|
- Gemfile.fluentd.0.10
|
10
10
|
matrix:
|
11
11
|
exclude:
|
12
|
-
- rvm: 2.0
|
13
|
-
gemfile: Gemfile
|
12
|
+
- rvm: 2.4.0
|
13
|
+
gemfile: Gemfile.fluentd.0.10
|
14
14
|
before_install: gem update bundler
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -4,6 +4,12 @@
|
|
4
4
|
|
5
5
|
Fluentd plugin to add or replace fields of a event record
|
6
6
|
|
7
|
+
## Requirements
|
8
|
+
|
9
|
+
See [.travis.yml](.travis.yml)
|
10
|
+
|
11
|
+
Note that `fluent-plugin-record-reformer` supports both v0.14 API and v0.12 API in one gem.
|
12
|
+
|
7
13
|
## Installation
|
8
14
|
|
9
15
|
Use RubyGems:
|
@@ -25,7 +31,7 @@ Example:
|
|
25
31
|
hostname ${hostname}
|
26
32
|
input_tag ${tag}
|
27
33
|
last_tag ${tag_parts[-1]}
|
28
|
-
message ${message}, yay!
|
34
|
+
message ${record['message']}, yay!
|
29
35
|
</record>
|
30
36
|
</match>
|
31
37
|
|
@@ -65,7 +71,7 @@ Example:
|
|
65
71
|
hostname ${hostname}
|
66
72
|
input_tag ${tag}
|
67
73
|
last_tag ${tag_parts[-1]}
|
68
|
-
message ${message}, yay!
|
74
|
+
message ${record['message']}, yay!
|
69
75
|
</match>
|
70
76
|
|
71
77
|
This results in same, but please note that following option parameters are reserved, so can not be used as a record key.
|
@@ -3,7 +3,7 @@ $:.push File.expand_path('../lib', __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.name = "fluent-plugin-record-reformer"
|
6
|
-
gem.version = "0.
|
6
|
+
gem.version = "0.9.0"
|
7
7
|
gem.authors = ["Naotoshi Seo"]
|
8
8
|
gem.email = "sonots@gmail.com"
|
9
9
|
gem.homepage = "https://github.com/sonots/fluent-plugin-record-reformer"
|
@@ -1,356 +1,7 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
require 'socket'
|
9
|
-
super
|
10
|
-
end
|
11
|
-
|
12
|
-
config_param :output_tag, :string, :default => nil, # obsolete
|
13
|
-
:desc => 'The output tag name. This option is deprecated. Use `tag` option instead.'
|
14
|
-
config_param :tag, :string, :default => nil,
|
15
|
-
:desc => 'The output tag name.'
|
16
|
-
config_param :remove_keys, :string, :default => nil,
|
17
|
-
:desc => 'Specify record keys to be removed by a string separated by , (comma).'
|
18
|
-
config_param :keep_keys, :string, :default => nil,
|
19
|
-
:desc => 'Specify record keys to be kept by a string separated by , (comma).'
|
20
|
-
config_param :renew_record, :bool, :default => false,
|
21
|
-
:desc => 'Creates an output record newly without extending (merging) the input record fields.'
|
22
|
-
config_param :renew_time_key, :string, :default => nil,
|
23
|
-
:desc => 'Overwrites the time of events with a value of the record field.'
|
24
|
-
config_param :enable_ruby, :bool, :default => true, # true for lower version compatibility
|
25
|
-
:desc => 'Enable to use ruby codes in placeholders.'
|
26
|
-
config_param :auto_typecast, :bool, :default => false, # false for lower version compatibility
|
27
|
-
:desc => 'Automatically cast the field types.'
|
28
|
-
|
29
|
-
BUILTIN_CONFIGURATIONS = %W(@id @type @label type tag output_tag remove_keys renew_record keep_keys enable_ruby renew_time_key auto_typecast)
|
30
|
-
|
31
|
-
# To support log_level option implemented by Fluentd v0.10.43
|
32
|
-
unless method_defined?(:log)
|
33
|
-
define_method("log") { $log }
|
34
|
-
end
|
35
|
-
|
36
|
-
# Define `router` method of v0.12 to support v0.10 or earlier
|
37
|
-
unless method_defined?(:router)
|
38
|
-
define_method("router") { Fluent::Engine }
|
39
|
-
end
|
40
|
-
|
41
|
-
def configure(conf)
|
42
|
-
super
|
43
|
-
|
44
|
-
map = {}
|
45
|
-
conf.each_pair { |k, v|
|
46
|
-
next if BUILTIN_CONFIGURATIONS.include?(k)
|
47
|
-
conf.has_key?(k) # to suppress unread configuration warning
|
48
|
-
map[k] = parse_value(v)
|
49
|
-
}
|
50
|
-
# <record></record> directive
|
51
|
-
conf.elements.select { |element| element.name == 'record' }.each { |element|
|
52
|
-
element.each_pair { |k, v|
|
53
|
-
element.has_key?(k) # to suppress unread configuration warning
|
54
|
-
map[k] = parse_value(v)
|
55
|
-
}
|
56
|
-
}
|
57
|
-
|
58
|
-
if @remove_keys
|
59
|
-
@remove_keys = @remove_keys.split(',')
|
60
|
-
end
|
61
|
-
|
62
|
-
if @keep_keys
|
63
|
-
raise Fluent::ConfigError, "out_record_reformer: `renew_record` must be true to use `keep_keys`" unless @renew_record
|
64
|
-
@keep_keys = @keep_keys.split(',')
|
65
|
-
end
|
66
|
-
|
67
|
-
if @output_tag and @tag.nil? # for lower version compatibility
|
68
|
-
log.warn "out_record_reformer: `output_tag` is deprecated. Use `tag` option instead."
|
69
|
-
@tag = @output_tag
|
70
|
-
end
|
71
|
-
if @tag.nil?
|
72
|
-
raise Fluent::ConfigError, "out_record_reformer: `tag` must be specified"
|
73
|
-
end
|
74
|
-
|
75
|
-
placeholder_expander_params = {
|
76
|
-
:log => log,
|
77
|
-
:auto_typecast => @auto_typecast,
|
78
|
-
}
|
79
|
-
@placeholder_expander =
|
80
|
-
if @enable_ruby
|
81
|
-
# require utilities which would be used in ruby placeholders
|
82
|
-
require 'pathname'
|
83
|
-
require 'uri'
|
84
|
-
require 'cgi'
|
85
|
-
RubyPlaceholderExpander.new(placeholder_expander_params)
|
86
|
-
else
|
87
|
-
PlaceholderExpander.new(placeholder_expander_params)
|
88
|
-
end
|
89
|
-
@map = @placeholder_expander.preprocess_map(map)
|
90
|
-
@tag = @placeholder_expander.preprocess_map(@tag)
|
91
|
-
|
92
|
-
@hostname = Socket.gethostname
|
93
|
-
end
|
94
|
-
|
95
|
-
def emit(tag, es, chain)
|
96
|
-
tag_parts = tag.split('.')
|
97
|
-
tag_prefix = tag_prefix(tag_parts)
|
98
|
-
tag_suffix = tag_suffix(tag_parts)
|
99
|
-
placeholder_values = {
|
100
|
-
'tag' => tag,
|
101
|
-
'tags' => tag_parts, # for old version compatibility
|
102
|
-
'tag_parts' => tag_parts,
|
103
|
-
'tag_prefix' => tag_prefix,
|
104
|
-
'tag_suffix' => tag_suffix,
|
105
|
-
'hostname' => @hostname,
|
106
|
-
}
|
107
|
-
last_record = nil
|
108
|
-
es.each {|time, record|
|
109
|
-
last_record = record # for debug log
|
110
|
-
placeholder_values.merge!({
|
111
|
-
'time' => @placeholder_expander.time_value(time),
|
112
|
-
'record' => record,
|
113
|
-
})
|
114
|
-
new_tag, new_record = reform(@tag, record, placeholder_values)
|
115
|
-
if new_tag
|
116
|
-
if @renew_time_key && new_record.has_key?(@renew_time_key)
|
117
|
-
time = new_record[@renew_time_key].to_i
|
118
|
-
end
|
119
|
-
@remove_keys.each {|k| new_record.delete(k) } if @remove_keys
|
120
|
-
router.emit(new_tag, time, new_record)
|
121
|
-
end
|
122
|
-
}
|
123
|
-
chain.next
|
124
|
-
rescue => e
|
125
|
-
log.warn "record_reformer: #{e.class} #{e.message} #{e.backtrace.first}"
|
126
|
-
log.debug "record_reformer: tag:#{@tag} map:#{@map} record:#{last_record} placeholder_values:#{placeholder_values}"
|
127
|
-
end
|
128
|
-
|
129
|
-
private
|
130
|
-
|
131
|
-
def parse_value(value_str)
|
132
|
-
if value_str.start_with?('{', '[')
|
133
|
-
JSON.parse(value_str)
|
134
|
-
else
|
135
|
-
value_str
|
136
|
-
end
|
137
|
-
rescue => e
|
138
|
-
log.warn "failed to parse #{value_str} as json. Assuming #{value_str} is a string", :error_class => e.class, :error => e.message
|
139
|
-
value_str # emit as string
|
140
|
-
end
|
141
|
-
|
142
|
-
def reform(tag, record, placeholder_values)
|
143
|
-
placeholders = @placeholder_expander.prepare_placeholders(placeholder_values)
|
144
|
-
|
145
|
-
new_tag = expand_placeholders(tag, placeholders)
|
146
|
-
|
147
|
-
new_record = @renew_record ? {} : record.dup
|
148
|
-
@keep_keys.each {|k| new_record[k] = record[k]} if @keep_keys and @renew_record
|
149
|
-
new_record.merge!(expand_placeholders(@map, placeholders))
|
150
|
-
|
151
|
-
[new_tag, new_record]
|
152
|
-
end
|
153
|
-
|
154
|
-
def expand_placeholders(value, placeholders)
|
155
|
-
if value.is_a?(String)
|
156
|
-
new_value = @placeholder_expander.expand(value, placeholders)
|
157
|
-
elsif value.is_a?(Hash)
|
158
|
-
new_value = {}
|
159
|
-
value.each_pair do |k, v|
|
160
|
-
new_key = @placeholder_expander.expand(k, placeholders, true)
|
161
|
-
new_value[new_key] = expand_placeholders(v, placeholders)
|
162
|
-
end
|
163
|
-
elsif value.is_a?(Array)
|
164
|
-
new_value = []
|
165
|
-
value.each_with_index do |v, i|
|
166
|
-
new_value[i] = expand_placeholders(v, placeholders)
|
167
|
-
end
|
168
|
-
else
|
169
|
-
new_value = value
|
170
|
-
end
|
171
|
-
new_value
|
172
|
-
end
|
173
|
-
|
174
|
-
def tag_prefix(tag_parts)
|
175
|
-
return [] if tag_parts.empty?
|
176
|
-
tag_prefix = [tag_parts.first]
|
177
|
-
1.upto(tag_parts.size-1).each do |i|
|
178
|
-
tag_prefix[i] = "#{tag_prefix[i-1]}.#{tag_parts[i]}"
|
179
|
-
end
|
180
|
-
tag_prefix
|
181
|
-
end
|
182
|
-
|
183
|
-
def tag_suffix(tag_parts)
|
184
|
-
return [] if tag_parts.empty?
|
185
|
-
rev_tag_parts = tag_parts.reverse
|
186
|
-
rev_tag_suffix = [rev_tag_parts.first]
|
187
|
-
1.upto(tag_parts.size-1).each do |i|
|
188
|
-
rev_tag_suffix[i] = "#{rev_tag_parts[i]}.#{rev_tag_suffix[i-1]}"
|
189
|
-
end
|
190
|
-
rev_tag_suffix.reverse!
|
191
|
-
end
|
192
|
-
|
193
|
-
# THIS CLASS MUST BE THREAD-SAFE
|
194
|
-
class PlaceholderExpander
|
195
|
-
attr_reader :placeholders, :log
|
196
|
-
|
197
|
-
def initialize(params)
|
198
|
-
@log = params[:log]
|
199
|
-
@auto_typecast = params[:auto_typecast]
|
200
|
-
end
|
201
|
-
|
202
|
-
def time_value(time)
|
203
|
-
Time.at(time).to_s
|
204
|
-
end
|
205
|
-
|
206
|
-
def preprocess_map(value, force_stringify = false)
|
207
|
-
value
|
208
|
-
end
|
209
|
-
|
210
|
-
def prepare_placeholders(placeholder_values)
|
211
|
-
placeholders = {}
|
212
|
-
|
213
|
-
placeholder_values.each do |key, value|
|
214
|
-
if value.kind_of?(Array) # tag_parts, etc
|
215
|
-
size = value.size
|
216
|
-
value.each_with_index do |v, idx|
|
217
|
-
placeholders.store("${#{key}[#{idx}]}", v)
|
218
|
-
placeholders.store("${#{key}[#{idx-size}]}", v) # support [-1]
|
219
|
-
end
|
220
|
-
elsif value.kind_of?(Hash) # record, etc
|
221
|
-
value.each do |k, v|
|
222
|
-
unless placeholder_values.has_key?(k) # prevent overwriting the reserved keys such as tag
|
223
|
-
placeholders.store("${#{k}}", v)
|
224
|
-
end
|
225
|
-
placeholders.store(%Q[${#{key}["#{k}"]}], v) # record["foo"]
|
226
|
-
end
|
227
|
-
else # string, interger, float, and others?
|
228
|
-
placeholders.store("${#{key}}", value)
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
placeholders
|
233
|
-
end
|
234
|
-
|
235
|
-
# Expand string with placeholders
|
236
|
-
#
|
237
|
-
# @param [String] str
|
238
|
-
# @param [Boolean] force_stringify the value must be string, used for hash key
|
239
|
-
def expand(str, placeholders, force_stringify = false)
|
240
|
-
if @auto_typecast and !force_stringify
|
241
|
-
single_placeholder_matched = str.match(/\A(\${[^}]+}|__[A-Z_]+__)\z/)
|
242
|
-
if single_placeholder_matched
|
243
|
-
log_if_unknown_placeholder($1, placeholders)
|
244
|
-
return placeholders[single_placeholder_matched[1]]
|
245
|
-
end
|
246
|
-
end
|
247
|
-
str.gsub(/(\${[^}]+}|__[A-Z_]+__)/) {
|
248
|
-
log_if_unknown_placeholder($1, placeholders)
|
249
|
-
placeholders[$1]
|
250
|
-
}
|
251
|
-
end
|
252
|
-
|
253
|
-
private
|
254
|
-
|
255
|
-
def log_if_unknown_placeholder(placeholder, placeholders)
|
256
|
-
unless placeholders.include?(placeholder)
|
257
|
-
log.warn "record_reformer: unknown placeholder `#{placeholder}` found"
|
258
|
-
end
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
|
-
# THIS CLASS MUST BE THREAD-SAFE
|
263
|
-
class RubyPlaceholderExpander
|
264
|
-
attr_reader :log
|
265
|
-
|
266
|
-
def initialize(params)
|
267
|
-
@log = params[:log]
|
268
|
-
@auto_typecast = params[:auto_typecast]
|
269
|
-
@cleanroom_expander = CleanroomExpander.new
|
270
|
-
end
|
271
|
-
|
272
|
-
def time_value(time)
|
273
|
-
Time.at(time)
|
274
|
-
end
|
275
|
-
|
276
|
-
# Preprocess record map to convert into ruby string expansion
|
277
|
-
#
|
278
|
-
# @param [Hash|String|Array] value record map config
|
279
|
-
# @param [Boolean] force_stringify the value must be string, used for hash key
|
280
|
-
def preprocess_map(value, force_stringify = false)
|
281
|
-
new_value = nil
|
282
|
-
if value.is_a?(String)
|
283
|
-
if @auto_typecast and !force_stringify
|
284
|
-
num_placeholders = value.scan('${').size
|
285
|
-
if num_placeholders == 1 and value.start_with?('${') && value.end_with?('}')
|
286
|
-
new_value = value[2..-2] # ${..} => ..
|
287
|
-
end
|
288
|
-
end
|
289
|
-
unless new_value
|
290
|
-
new_value = "%Q[#{value.gsub('${', '#{')}]" # xx${..}xx => %Q[xx#{..}xx]
|
291
|
-
end
|
292
|
-
elsif value.is_a?(Hash)
|
293
|
-
new_value = {}
|
294
|
-
value.each_pair do |k, v|
|
295
|
-
new_value[preprocess_map(k, true)] = preprocess_map(v)
|
296
|
-
end
|
297
|
-
elsif value.is_a?(Array)
|
298
|
-
new_value = []
|
299
|
-
value.each_with_index do |v, i|
|
300
|
-
new_value[i] = preprocess_map(v)
|
301
|
-
end
|
302
|
-
else
|
303
|
-
new_value = value
|
304
|
-
end
|
305
|
-
new_value
|
306
|
-
end
|
307
|
-
|
308
|
-
def prepare_placeholders(placeholder_values)
|
309
|
-
placeholder_values
|
310
|
-
end
|
311
|
-
|
312
|
-
# Expand string with placeholders
|
313
|
-
#
|
314
|
-
# @param [String] str
|
315
|
-
def expand(str, placeholders, force_stringify = false)
|
316
|
-
@cleanroom_expander.expand(
|
317
|
-
str,
|
318
|
-
placeholders['tag'],
|
319
|
-
placeholders['time'],
|
320
|
-
placeholders['record'],
|
321
|
-
placeholders['tag_parts'],
|
322
|
-
placeholders['tag_prefix'],
|
323
|
-
placeholders['tag_suffix'],
|
324
|
-
placeholders['hostname'],
|
325
|
-
)
|
326
|
-
rescue => e
|
327
|
-
log.warn "record_reformer: failed to expand `#{str}`", :error_class => e.class, :error => e.message
|
328
|
-
log.warn_backtrace
|
329
|
-
nil
|
330
|
-
end
|
331
|
-
|
332
|
-
class CleanroomExpander
|
333
|
-
def expand(__str_to_eval__, tag, time, record, tag_parts, tag_prefix, tag_suffix, hostname)
|
334
|
-
tags = tag_parts # for old version compatibility
|
335
|
-
Thread.current[:record_reformer_record] = record # for old version compatibility
|
336
|
-
instance_eval(__str_to_eval__)
|
337
|
-
end
|
338
|
-
|
339
|
-
# for old version compatibility
|
340
|
-
def method_missing(name)
|
341
|
-
key = name.to_s
|
342
|
-
record = Thread.current[:record_reformer_record]
|
343
|
-
if record.has_key?(key)
|
344
|
-
record[key]
|
345
|
-
else
|
346
|
-
raise NameError, "undefined local variable or method `#{key}'"
|
347
|
-
end
|
348
|
-
end
|
349
|
-
|
350
|
-
(Object.instance_methods).each do |m|
|
351
|
-
undef_method m unless m.to_s =~ /^__|respond_to_missing\?|object_id|public_methods|instance_eval|method_missing|define_singleton_method|respond_to\?|new_ostruct_member/
|
352
|
-
end
|
353
|
-
end
|
354
|
-
end
|
355
|
-
end
|
1
|
+
require 'fluent/version'
|
2
|
+
major, minor, patch = Fluent::VERSION.split('.').map(&:to_i)
|
3
|
+
if major > 0 || (major == 0 && minor >= 14)
|
4
|
+
require_relative 'out_record_reformer/v14'
|
5
|
+
else
|
6
|
+
require_relative 'out_record_reformer/v12'
|
356
7
|
end
|
@@ -0,0 +1,345 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
module Fluent
|
5
|
+
module RecordReformerOutputCore
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.included(klass)
|
11
|
+
klass.config_param :output_tag, :string, :default => nil, # obsolete
|
12
|
+
:desc => 'The output tag name. This option is deprecated. Use `tag` option instead.'
|
13
|
+
klass.config_param :tag, :string, :default => nil,
|
14
|
+
:desc => 'The output tag name.'
|
15
|
+
klass.config_param :remove_keys, :string, :default => nil,
|
16
|
+
:desc => 'Specify record keys to be removed by a string separated by , (comma).'
|
17
|
+
klass.config_param :keep_keys, :string, :default => nil,
|
18
|
+
:desc => 'Specify record keys to be kept by a string separated by , (comma).'
|
19
|
+
klass.config_param :renew_record, :bool, :default => false,
|
20
|
+
:desc => 'Creates an output record newly without extending (merging) the input record fields.'
|
21
|
+
klass.config_param :renew_time_key, :string, :default => nil,
|
22
|
+
:desc => 'Overwrites the time of events with a value of the record field.'
|
23
|
+
klass.config_param :enable_ruby, :bool, :default => true, # true for lower version compatibility
|
24
|
+
:desc => 'Enable to use ruby codes in placeholders.'
|
25
|
+
klass.config_param :auto_typecast, :bool, :default => false, # false for lower version compatibility
|
26
|
+
:desc => 'Automatically cast the field types.'
|
27
|
+
end
|
28
|
+
|
29
|
+
BUILTIN_CONFIGURATIONS = %W(@id @type @label type tag output_tag remove_keys renew_record keep_keys enable_ruby renew_time_key auto_typecast)
|
30
|
+
|
31
|
+
def configure(conf)
|
32
|
+
super
|
33
|
+
|
34
|
+
map = {}
|
35
|
+
conf.each_pair { |k, v|
|
36
|
+
next if BUILTIN_CONFIGURATIONS.include?(k)
|
37
|
+
conf.has_key?(k) # to suppress unread configuration warning
|
38
|
+
map[k] = parse_value(v)
|
39
|
+
}
|
40
|
+
# <record></record> directive
|
41
|
+
conf.elements.select { |element| element.name == 'record' }.each { |element|
|
42
|
+
element.each_pair { |k, v|
|
43
|
+
element.has_key?(k) # to suppress unread configuration warning
|
44
|
+
map[k] = parse_value(v)
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
if @remove_keys
|
49
|
+
@remove_keys = @remove_keys.split(',')
|
50
|
+
end
|
51
|
+
|
52
|
+
if @keep_keys
|
53
|
+
raise Fluent::ConfigError, "out_record_reformer: `renew_record` must be true to use `keep_keys`" unless @renew_record
|
54
|
+
@keep_keys = @keep_keys.split(',')
|
55
|
+
end
|
56
|
+
|
57
|
+
if @output_tag and @tag.nil? # for lower version compatibility
|
58
|
+
log.warn "out_record_reformer: `output_tag` is deprecated. Use `tag` option instead."
|
59
|
+
@tag = @output_tag
|
60
|
+
end
|
61
|
+
if @tag.nil?
|
62
|
+
raise Fluent::ConfigError, "out_record_reformer: `tag` must be specified"
|
63
|
+
end
|
64
|
+
|
65
|
+
placeholder_expander_params = {
|
66
|
+
:log => log,
|
67
|
+
:auto_typecast => @auto_typecast,
|
68
|
+
}
|
69
|
+
@placeholder_expander =
|
70
|
+
if @enable_ruby
|
71
|
+
# require utilities which would be used in ruby placeholders
|
72
|
+
require 'pathname'
|
73
|
+
require 'uri'
|
74
|
+
require 'cgi'
|
75
|
+
RubyPlaceholderExpander.new(placeholder_expander_params)
|
76
|
+
else
|
77
|
+
PlaceholderExpander.new(placeholder_expander_params)
|
78
|
+
end
|
79
|
+
@map = @placeholder_expander.preprocess_map(map)
|
80
|
+
@tag = @placeholder_expander.preprocess_map(@tag)
|
81
|
+
|
82
|
+
@hostname = Socket.gethostname
|
83
|
+
end
|
84
|
+
|
85
|
+
def process(tag, es)
|
86
|
+
tag_parts = tag.split('.')
|
87
|
+
tag_prefix = tag_prefix(tag_parts)
|
88
|
+
tag_suffix = tag_suffix(tag_parts)
|
89
|
+
placeholder_values = {
|
90
|
+
'tag' => tag,
|
91
|
+
'tags' => tag_parts, # for old version compatibility
|
92
|
+
'tag_parts' => tag_parts,
|
93
|
+
'tag_prefix' => tag_prefix,
|
94
|
+
'tag_suffix' => tag_suffix,
|
95
|
+
'hostname' => @hostname,
|
96
|
+
}
|
97
|
+
last_record = nil
|
98
|
+
es.each {|time, record|
|
99
|
+
last_record = record # for debug log
|
100
|
+
placeholder_values.merge!({
|
101
|
+
'time' => @placeholder_expander.time_value(time),
|
102
|
+
'record' => record,
|
103
|
+
})
|
104
|
+
new_tag, new_record = reform(@tag, record, placeholder_values)
|
105
|
+
if new_tag
|
106
|
+
if @renew_time_key && new_record.has_key?(@renew_time_key)
|
107
|
+
time = new_record[@renew_time_key].to_i
|
108
|
+
end
|
109
|
+
@remove_keys.each {|k| new_record.delete(k) } if @remove_keys
|
110
|
+
router.emit(new_tag, time, new_record)
|
111
|
+
end
|
112
|
+
}
|
113
|
+
rescue => e
|
114
|
+
log.warn "record_reformer: #{e.class} #{e.message} #{e.backtrace.first}"
|
115
|
+
log.debug "record_reformer: tag:#{@tag} map:#{@map} record:#{last_record} placeholder_values:#{placeholder_values}"
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def parse_value(value_str)
|
121
|
+
if value_str.start_with?('{', '[')
|
122
|
+
JSON.parse(value_str)
|
123
|
+
else
|
124
|
+
value_str
|
125
|
+
end
|
126
|
+
rescue => e
|
127
|
+
log.warn "failed to parse #{value_str} as json. Assuming #{value_str} is a string", :error_class => e.class, :error => e.message
|
128
|
+
value_str # emit as string
|
129
|
+
end
|
130
|
+
|
131
|
+
def reform(tag, record, placeholder_values)
|
132
|
+
placeholders = @placeholder_expander.prepare_placeholders(placeholder_values)
|
133
|
+
|
134
|
+
new_tag = expand_placeholders(tag, placeholders)
|
135
|
+
|
136
|
+
new_record = @renew_record ? {} : record.dup
|
137
|
+
@keep_keys.each {|k| new_record[k] = record[k]} if @keep_keys and @renew_record
|
138
|
+
new_record.merge!(expand_placeholders(@map, placeholders))
|
139
|
+
|
140
|
+
[new_tag, new_record]
|
141
|
+
end
|
142
|
+
|
143
|
+
def expand_placeholders(value, placeholders)
|
144
|
+
if value.is_a?(String)
|
145
|
+
new_value = @placeholder_expander.expand(value, placeholders)
|
146
|
+
elsif value.is_a?(Hash)
|
147
|
+
new_value = {}
|
148
|
+
value.each_pair do |k, v|
|
149
|
+
new_key = @placeholder_expander.expand(k, placeholders, true)
|
150
|
+
new_value[new_key] = expand_placeholders(v, placeholders)
|
151
|
+
end
|
152
|
+
elsif value.is_a?(Array)
|
153
|
+
new_value = []
|
154
|
+
value.each_with_index do |v, i|
|
155
|
+
new_value[i] = expand_placeholders(v, placeholders)
|
156
|
+
end
|
157
|
+
else
|
158
|
+
new_value = value
|
159
|
+
end
|
160
|
+
new_value
|
161
|
+
end
|
162
|
+
|
163
|
+
def tag_prefix(tag_parts)
|
164
|
+
return [] if tag_parts.empty?
|
165
|
+
tag_prefix = [tag_parts.first]
|
166
|
+
1.upto(tag_parts.size-1).each do |i|
|
167
|
+
tag_prefix[i] = "#{tag_prefix[i-1]}.#{tag_parts[i]}"
|
168
|
+
end
|
169
|
+
tag_prefix
|
170
|
+
end
|
171
|
+
|
172
|
+
def tag_suffix(tag_parts)
|
173
|
+
return [] if tag_parts.empty?
|
174
|
+
rev_tag_parts = tag_parts.reverse
|
175
|
+
rev_tag_suffix = [rev_tag_parts.first]
|
176
|
+
1.upto(tag_parts.size-1).each do |i|
|
177
|
+
rev_tag_suffix[i] = "#{rev_tag_parts[i]}.#{rev_tag_suffix[i-1]}"
|
178
|
+
end
|
179
|
+
rev_tag_suffix.reverse!
|
180
|
+
end
|
181
|
+
|
182
|
+
# THIS CLASS MUST BE THREAD-SAFE
|
183
|
+
class PlaceholderExpander
|
184
|
+
attr_reader :placeholders, :log
|
185
|
+
|
186
|
+
def initialize(params)
|
187
|
+
@log = params[:log]
|
188
|
+
@auto_typecast = params[:auto_typecast]
|
189
|
+
end
|
190
|
+
|
191
|
+
def time_value(time)
|
192
|
+
Time.at(time).to_s
|
193
|
+
end
|
194
|
+
|
195
|
+
def preprocess_map(value, force_stringify = false)
|
196
|
+
value
|
197
|
+
end
|
198
|
+
|
199
|
+
def prepare_placeholders(placeholder_values)
|
200
|
+
placeholders = {}
|
201
|
+
|
202
|
+
placeholder_values.each do |key, value|
|
203
|
+
if value.kind_of?(Array) # tag_parts, etc
|
204
|
+
size = value.size
|
205
|
+
value.each_with_index do |v, idx|
|
206
|
+
placeholders.store("${#{key}[#{idx}]}", v)
|
207
|
+
placeholders.store("${#{key}[#{idx-size}]}", v) # support [-1]
|
208
|
+
end
|
209
|
+
elsif value.kind_of?(Hash) # record, etc
|
210
|
+
value.each do |k, v|
|
211
|
+
unless placeholder_values.has_key?(k) # prevent overwriting the reserved keys such as tag
|
212
|
+
placeholders.store("${#{k}}", v)
|
213
|
+
end
|
214
|
+
placeholders.store(%Q[${#{key}["#{k}"]}], v) # record["foo"]
|
215
|
+
end
|
216
|
+
else # string, interger, float, and others?
|
217
|
+
placeholders.store("${#{key}}", value)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
placeholders
|
222
|
+
end
|
223
|
+
|
224
|
+
# Expand string with placeholders
|
225
|
+
#
|
226
|
+
# @param [String] str
|
227
|
+
# @param [Boolean] force_stringify the value must be string, used for hash key
|
228
|
+
def expand(str, placeholders, force_stringify = false)
|
229
|
+
if @auto_typecast and !force_stringify
|
230
|
+
single_placeholder_matched = str.match(/\A(\${[^}]+}|__[A-Z_]+__)\z/)
|
231
|
+
if single_placeholder_matched
|
232
|
+
log_if_unknown_placeholder($1, placeholders)
|
233
|
+
return placeholders[single_placeholder_matched[1]]
|
234
|
+
end
|
235
|
+
end
|
236
|
+
str.gsub(/(\${[^}]+}|__[A-Z_]+__)/) {
|
237
|
+
log_if_unknown_placeholder($1, placeholders)
|
238
|
+
placeholders[$1]
|
239
|
+
}
|
240
|
+
end
|
241
|
+
|
242
|
+
private
|
243
|
+
|
244
|
+
def log_if_unknown_placeholder(placeholder, placeholders)
|
245
|
+
unless placeholders.include?(placeholder)
|
246
|
+
log.warn "record_reformer: unknown placeholder `#{placeholder}` found"
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
# THIS CLASS MUST BE THREAD-SAFE
|
252
|
+
class RubyPlaceholderExpander
|
253
|
+
attr_reader :log
|
254
|
+
|
255
|
+
def initialize(params)
|
256
|
+
@log = params[:log]
|
257
|
+
@auto_typecast = params[:auto_typecast]
|
258
|
+
@cleanroom_expander = CleanroomExpander.new
|
259
|
+
end
|
260
|
+
|
261
|
+
def time_value(time)
|
262
|
+
Time.at(time)
|
263
|
+
end
|
264
|
+
|
265
|
+
# Preprocess record map to convert into ruby string expansion
|
266
|
+
#
|
267
|
+
# @param [Hash|String|Array] value record map config
|
268
|
+
# @param [Boolean] force_stringify the value must be string, used for hash key
|
269
|
+
def preprocess_map(value, force_stringify = false)
|
270
|
+
new_value = nil
|
271
|
+
if value.is_a?(String)
|
272
|
+
if @auto_typecast and !force_stringify
|
273
|
+
num_placeholders = value.scan('${').size
|
274
|
+
if num_placeholders == 1 and value.start_with?('${') && value.end_with?('}')
|
275
|
+
new_value = value[2..-2] # ${..} => ..
|
276
|
+
end
|
277
|
+
end
|
278
|
+
unless new_value
|
279
|
+
new_value = "%Q[#{value.gsub('${', '#{')}]" # xx${..}xx => %Q[xx#{..}xx]
|
280
|
+
end
|
281
|
+
elsif value.is_a?(Hash)
|
282
|
+
new_value = {}
|
283
|
+
value.each_pair do |k, v|
|
284
|
+
new_value[preprocess_map(k, true)] = preprocess_map(v)
|
285
|
+
end
|
286
|
+
elsif value.is_a?(Array)
|
287
|
+
new_value = []
|
288
|
+
value.each_with_index do |v, i|
|
289
|
+
new_value[i] = preprocess_map(v)
|
290
|
+
end
|
291
|
+
else
|
292
|
+
new_value = value
|
293
|
+
end
|
294
|
+
new_value
|
295
|
+
end
|
296
|
+
|
297
|
+
def prepare_placeholders(placeholder_values)
|
298
|
+
placeholder_values
|
299
|
+
end
|
300
|
+
|
301
|
+
# Expand string with placeholders
|
302
|
+
#
|
303
|
+
# @param [String] str
|
304
|
+
def expand(str, placeholders, force_stringify = false)
|
305
|
+
@cleanroom_expander.expand(
|
306
|
+
str,
|
307
|
+
placeholders['tag'],
|
308
|
+
placeholders['time'],
|
309
|
+
placeholders['record'],
|
310
|
+
placeholders['tag_parts'],
|
311
|
+
placeholders['tag_prefix'],
|
312
|
+
placeholders['tag_suffix'],
|
313
|
+
placeholders['hostname'],
|
314
|
+
)
|
315
|
+
rescue => e
|
316
|
+
log.warn "record_reformer: failed to expand `#{str}`", :error_class => e.class, :error => e.message
|
317
|
+
log.warn_backtrace
|
318
|
+
nil
|
319
|
+
end
|
320
|
+
|
321
|
+
class CleanroomExpander
|
322
|
+
def expand(__str_to_eval__, tag, time, record, tag_parts, tag_prefix, tag_suffix, hostname)
|
323
|
+
tags = tag_parts # for old version compatibility
|
324
|
+
Thread.current[:record_reformer_record] = record # for old version compatibility
|
325
|
+
instance_eval(__str_to_eval__)
|
326
|
+
end
|
327
|
+
|
328
|
+
# for old version compatibility
|
329
|
+
def method_missing(name)
|
330
|
+
key = name.to_s
|
331
|
+
record = Thread.current[:record_reformer_record]
|
332
|
+
if record.has_key?(key)
|
333
|
+
record[key]
|
334
|
+
else
|
335
|
+
raise NameError, "undefined local variable or method `#{key}'"
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
(Object.instance_methods).each do |m|
|
340
|
+
undef_method m unless m.to_s =~ /^__|respond_to_missing\?|object_id|public_methods|instance_eval|method_missing|define_singleton_method|respond_to\?|new_ostruct_member/
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative 'core'
|
2
|
+
|
3
|
+
module Fluent
|
4
|
+
class RecordReformerOutput < Output
|
5
|
+
Fluent::Plugin.register_output('record_reformer', self)
|
6
|
+
|
7
|
+
include ::Fluent::RecordReformerOutputCore
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
# To support log_level option implemented by Fluentd v0.10.43
|
14
|
+
unless method_defined?(:log)
|
15
|
+
define_method("log") { $log }
|
16
|
+
end
|
17
|
+
|
18
|
+
# Define `router` method of v0.12 to support v0.10 or earlier
|
19
|
+
unless method_defined?(:router)
|
20
|
+
define_method("router") { Fluent::Engine }
|
21
|
+
end
|
22
|
+
|
23
|
+
def configure(conf)
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
def emit(tag, es, chain)
|
28
|
+
process(tag, es)
|
29
|
+
chain.next
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'core'
|
2
|
+
|
3
|
+
module Fluent
|
4
|
+
class Plugin::RecordReformerOutput < Plugin::Output
|
5
|
+
Fluent::Plugin.register_output('record_reformer', self)
|
6
|
+
|
7
|
+
helpers :event_emitter
|
8
|
+
include ::Fluent::RecordReformerOutputCore
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def configure(conf)
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
def process(tag, es)
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/test/helper.rb
CHANGED
@@ -28,3 +28,48 @@ module Fluent
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
31
|
+
|
32
|
+
require 'fluent/version'
|
33
|
+
major, minor, patch = Fluent::VERSION.split('.').map(&:to_i)
|
34
|
+
if major > 0 || (major == 0 && minor >= 14)
|
35
|
+
require 'fluent/test/driver/output'
|
36
|
+
require 'fluent/test/helpers'
|
37
|
+
include Fluent::Test::Helpers
|
38
|
+
|
39
|
+
# I do not want to use Fluent::Test::OutputTestDriver, but
|
40
|
+
# want to have a test driver whose interface is compatible with of v0.12
|
41
|
+
class RecordReformerOutputTestDriver < Fluent::Test::Driver::Output
|
42
|
+
def initialize(klass, tag)
|
43
|
+
super(klass)
|
44
|
+
@tag = tag
|
45
|
+
end
|
46
|
+
|
47
|
+
def configure(conf, use_v1)
|
48
|
+
super(conf, syntax: use_v1 ? :v1 : :v0)
|
49
|
+
end
|
50
|
+
|
51
|
+
def run(&block)
|
52
|
+
super(default_tag: @tag, &block)
|
53
|
+
end
|
54
|
+
|
55
|
+
def emit(record, time)
|
56
|
+
feed(time, record)
|
57
|
+
end
|
58
|
+
|
59
|
+
def emits
|
60
|
+
events
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def create_driver(conf, use_v1)
|
65
|
+
RecordReformerOutputTestDriver.new(Fluent::Plugin::RecordReformerOutput, @tag).configure(conf, use_v1)
|
66
|
+
end
|
67
|
+
else
|
68
|
+
def event_time(str)
|
69
|
+
Time.parse(str)
|
70
|
+
end
|
71
|
+
|
72
|
+
def create_driver(conf, use_v1)
|
73
|
+
Fluent::Test::OutputTestDriver.new(Fluent::RecordReformerOutput, @tag).configure(conf, use_v1)
|
74
|
+
end
|
75
|
+
end
|
@@ -5,22 +5,6 @@ require 'fluent/plugin/out_record_reformer'
|
|
5
5
|
Fluent::Test.setup
|
6
6
|
|
7
7
|
class RecordReformerOutputTest < Test::Unit::TestCase
|
8
|
-
setup do
|
9
|
-
@hostname = Socket.gethostname.chomp
|
10
|
-
@tag = 'test.tag'
|
11
|
-
@tag_parts = @tag.split('.')
|
12
|
-
@time = Time.local(1,2,3,4,5,2010,nil,nil,nil,nil)
|
13
|
-
Timecop.freeze(@time)
|
14
|
-
end
|
15
|
-
|
16
|
-
teardown do
|
17
|
-
Timecop.return
|
18
|
-
end
|
19
|
-
|
20
|
-
def create_driver(conf, use_v1)
|
21
|
-
Fluent::Test::OutputTestDriver.new(Fluent::RecordReformerOutput, @tag).configure(conf, use_v1)
|
22
|
-
end
|
23
|
-
|
24
8
|
def emit(config, use_v1, msgs = [''])
|
25
9
|
d = create_driver(config, use_v1)
|
26
10
|
d.run do
|
@@ -37,6 +21,18 @@ class RecordReformerOutputTest < Test::Unit::TestCase
|
|
37
21
|
d.emits
|
38
22
|
end
|
39
23
|
|
24
|
+
setup do
|
25
|
+
@hostname = Socket.gethostname.chomp
|
26
|
+
@tag = 'test.tag'
|
27
|
+
@tag_parts = @tag.split('.')
|
28
|
+
@time = event_time("2010-05-04 03:02:01")
|
29
|
+
Timecop.freeze(@time)
|
30
|
+
end
|
31
|
+
|
32
|
+
teardown do
|
33
|
+
Timecop.return
|
34
|
+
end
|
35
|
+
|
40
36
|
CONFIG = %[
|
41
37
|
tag reformed.${tag}
|
42
38
|
|
@@ -77,7 +73,7 @@ class RecordReformerOutputTest < Test::Unit::TestCase
|
|
77
73
|
assert_equal('bar', record['eventType0'])
|
78
74
|
assert_equal(@hostname, record['hostname'])
|
79
75
|
assert_equal(@tag, record['input_tag'])
|
80
|
-
assert_equal(@time.to_s, record['time'])
|
76
|
+
assert_equal(Time.at(@time).localtime.to_s, record['time'])
|
81
77
|
assert_equal("#{@hostname} #{@tag_parts[-1]} #{msgs[i]}", record['message'])
|
82
78
|
end
|
83
79
|
end
|
@@ -109,7 +105,7 @@ class RecordReformerOutputTest < Test::Unit::TestCase
|
|
109
105
|
assert_equal('bar', record['eventType0'])
|
110
106
|
assert_equal(@hostname, record['hostname'])
|
111
107
|
assert_equal(@tag, record['tag'])
|
112
|
-
assert_equal(@time.to_s, record['time'])
|
108
|
+
assert_equal(Time.at(@time).localtime.to_s, record['time'])
|
113
109
|
assert_equal("#{@hostname} #{@tag_parts[-1]} #{msgs[i]}", record['message'])
|
114
110
|
end
|
115
111
|
end
|
@@ -122,7 +118,7 @@ class RecordReformerOutputTest < Test::Unit::TestCase
|
|
122
118
|
assert_not_include(record, 'eventType0')
|
123
119
|
assert_equal(@hostname, record['hostname'])
|
124
120
|
assert_equal(@tag, record['input_tag'])
|
125
|
-
assert_equal(@time.to_s, record['time'])
|
121
|
+
assert_equal(Time.at(@time).localtime.to_s, record['time'])
|
126
122
|
assert_not_include(record, 'message')
|
127
123
|
end
|
128
124
|
end
|
@@ -136,13 +132,13 @@ class RecordReformerOutputTest < Test::Unit::TestCase
|
|
136
132
|
assert_not_include(record, 'eventType0')
|
137
133
|
assert_equal(@hostname, record['hostname'])
|
138
134
|
assert_equal(@tag, record['input_tag'])
|
139
|
-
assert_equal(@time.to_s, record['time'])
|
135
|
+
assert_equal(Time.at(@time).localtime.to_s, record['time'])
|
140
136
|
assert_equal("#{@hostname} #{@tag_parts[-1]} #{msgs[i]}", record['message'])
|
141
137
|
end
|
142
138
|
end
|
143
139
|
|
144
140
|
test 'renew_time_key' do
|
145
|
-
times = [ Time.
|
141
|
+
times = [ Time.at(event_time("2010-05-04 03:02:02")), Time.at(event_time("2010-05-04 03:02:03")) ]
|
146
142
|
config = <<EOC
|
147
143
|
tag reformed.${tag}
|
148
144
|
enable_ruby true
|
@@ -170,7 +166,7 @@ EOC
|
|
170
166
|
event_time_key ${Time.parse(record["message"]).to_i}
|
171
167
|
</record>
|
172
168
|
EOC
|
173
|
-
times = [ Time.
|
169
|
+
times = [ Time.at(event_time("2010-05-04 03:02:02")), Time.at(event_time("2010-05-04 03:02:03")) ]
|
174
170
|
msgs = times.map{|t| t.to_s }
|
175
171
|
emits = emit(config, use_v1, msgs)
|
176
172
|
emits.each_with_index do |(tag, time, record), i|
|
@@ -295,7 +291,7 @@ EOC
|
|
295
291
|
]
|
296
292
|
emits = emit(config, use_v1)
|
297
293
|
emits.each do |(tag, time, record)|
|
298
|
-
assert_equal(
|
294
|
+
assert_equal(Time.at(time).localtime.to_s, record['message'])
|
299
295
|
end
|
300
296
|
end
|
301
297
|
|
@@ -335,7 +331,7 @@ EOC
|
|
335
331
|
assert_not_equal('tag', record['new_tag'])
|
336
332
|
assert_equal(@tag, record['new_tag'])
|
337
333
|
assert_not_equal('time', record['new_time'])
|
338
|
-
assert_equal(@time.to_s, record['new_time'])
|
334
|
+
assert_equal(Time.at(@time).localtime.to_s, record['new_time'])
|
339
335
|
assert_equal('tag', record['new_record_tag'])
|
340
336
|
assert_equal('time', record['new_record_time'])
|
341
337
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-record-reformer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Naotoshi Seo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-02-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fluentd
|
@@ -127,6 +127,9 @@ files:
|
|
127
127
|
- example.conf
|
128
128
|
- fluent-plugin-record-reformer.gemspec
|
129
129
|
- lib/fluent/plugin/out_record_reformer.rb
|
130
|
+
- lib/fluent/plugin/out_record_reformer/core.rb
|
131
|
+
- lib/fluent/plugin/out_record_reformer/v12.rb
|
132
|
+
- lib/fluent/plugin/out_record_reformer/v14.rb
|
130
133
|
- test/bench_out_record_reformer.rb
|
131
134
|
- test/helper.rb
|
132
135
|
- test/test_out_record_reformer.rb
|
@@ -150,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
150
153
|
version: '0'
|
151
154
|
requirements: []
|
152
155
|
rubyforge_project:
|
153
|
-
rubygems_version: 2.
|
156
|
+
rubygems_version: 2.6.8
|
154
157
|
signing_key:
|
155
158
|
specification_version: 4
|
156
159
|
summary: Fluentd plugin to add or replace fields of a event record
|