fluentd 0.14.0 → 0.14.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of fluentd might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/example/copy_roundrobin.conf +39 -0
- data/example/filter_stdout.conf +5 -5
- data/example/in_forward.conf +2 -2
- data/example/in_http.conf +2 -2
- data/example/in_syslog.conf +2 -2
- data/example/in_tail.conf +2 -2
- data/example/in_tcp.conf +2 -2
- data/example/in_udp.conf +2 -2
- data/example/out_buffered_null.conf +32 -0
- data/example/out_copy.conf +4 -4
- data/example/out_file.conf +2 -2
- data/example/out_forward.conf +2 -2
- data/example/v0_12_filter.conf +8 -8
- data/fluentd.gemspec +1 -1
- data/lib/fluent/command/fluentd.rb +6 -1
- data/lib/fluent/compat/handle_tag_name_mixin.rb +53 -0
- data/lib/fluent/compat/input.rb +1 -0
- data/lib/fluent/compat/output.rb +1 -0
- data/lib/fluent/compat/record_filter_mixin.rb +34 -0
- data/lib/fluent/compat/set_tag_key_mixin.rb +50 -0
- data/lib/fluent/compat/set_time_key_mixin.rb +69 -0
- data/lib/fluent/compat/type_converter.rb +90 -0
- data/lib/fluent/config/configure_proxy.rb +24 -4
- data/lib/fluent/config/dsl.rb +18 -1
- data/lib/fluent/config/v1_parser.rb +3 -2
- data/lib/fluent/configurable.rb +1 -1
- data/lib/fluent/event.rb +37 -9
- data/lib/fluent/mixin.rb +12 -286
- data/lib/fluent/plugin/buffer.rb +2 -2
- data/lib/fluent/plugin/in_dummy.rb +5 -1
- data/lib/fluent/plugin/in_gc_stat.rb +7 -37
- data/lib/fluent/plugin/in_http.rb +2 -0
- data/lib/fluent/plugin/{in_stream.rb → in_unix.rb} +0 -0
- data/lib/fluent/plugin/out_buffered_stdout.rb +60 -0
- data/lib/fluent/plugin/out_copy.rb +8 -51
- data/lib/fluent/plugin/out_null.rb +5 -5
- data/lib/fluent/plugin/out_relabel.rb +5 -5
- data/lib/fluent/plugin/out_roundrobin.rb +13 -40
- data/lib/fluent/plugin/output.rb +9 -0
- data/lib/fluent/plugin_helper.rb +2 -0
- data/lib/fluent/plugin_helper/formatter.rb +138 -0
- data/lib/fluent/plugin_helper/inject.rb +112 -0
- data/lib/fluent/plugin_helper/parser.rb +138 -0
- data/lib/fluent/plugin_helper/storage.rb +64 -50
- data/lib/fluent/process.rb +6 -1
- data/lib/fluent/registry.rb +1 -1
- data/lib/fluent/supervisor.rb +20 -2
- data/lib/fluent/test.rb +30 -5
- data/lib/fluent/test/base.rb +2 -66
- data/lib/fluent/test/driver/base.rb +3 -0
- data/lib/fluent/test/driver/base_owned.rb +106 -0
- data/lib/fluent/test/driver/formatter.rb +30 -0
- data/lib/fluent/test/driver/multi_output.rb +52 -0
- data/lib/fluent/test/driver/owner.rb +32 -0
- data/lib/fluent/test/driver/parser.rb +30 -0
- data/lib/fluent/test/helpers.rb +54 -0
- data/lib/fluent/test/log.rb +73 -0
- data/lib/fluent/time.rb +71 -0
- data/lib/fluent/version.rb +1 -1
- data/test/compat/test_parser.rb +82 -0
- data/test/config/test_configure_proxy.rb +15 -0
- data/test/config/test_dsl.rb +180 -2
- data/test/helper.rb +2 -24
- data/test/plugin/test_in_gc_stat.rb +6 -6
- data/test/plugin/test_in_http.rb +49 -32
- data/test/plugin/{test_in_stream.rb → test_in_unix.rb} +1 -1
- data/test/plugin/test_out_buffered_stdout.rb +108 -0
- data/test/plugin/test_out_copy.rb +88 -127
- data/test/plugin/test_out_null.rb +29 -0
- data/test/plugin/test_out_relabel.rb +28 -0
- data/test/plugin/test_out_roundrobin.rb +35 -29
- data/test/plugin/test_out_stdout.rb +4 -4
- data/test/plugin/test_output_as_buffered.rb +51 -0
- data/test/plugin/test_output_as_buffered_secondary.rb +13 -0
- data/test/plugin/test_parser_apache.rb +38 -0
- data/test/plugin/test_parser_apache2.rb +38 -0
- data/test/plugin/test_parser_apache_error.rb +40 -0
- data/test/plugin/test_parser_base.rb +32 -0
- data/test/plugin/test_parser_csv.rb +94 -0
- data/test/plugin/test_parser_json.rb +107 -0
- data/test/plugin/test_parser_labeled_tsv.rb +129 -0
- data/test/plugin/test_parser_multiline.rb +100 -0
- data/test/plugin/test_parser_nginx.rb +42 -0
- data/test/plugin/test_parser_none.rb +53 -0
- data/test/plugin/test_parser_regexp.rb +110 -0
- data/test/plugin/test_parser_syslog.rb +66 -0
- data/test/plugin/test_parser_time.rb +46 -0
- data/test/plugin/test_parser_tsv.rb +125 -0
- data/test/plugin_helper/test_child_process.rb +11 -2
- data/test/plugin_helper/test_formatter.rb +212 -0
- data/test/plugin_helper/test_inject.rb +388 -0
- data/test/plugin_helper/test_parser.rb +223 -0
- data/test/plugin_helper/test_retry_state.rb +40 -40
- data/test/plugin_helper/test_storage.rb +77 -10
- data/test/scripts/fluent/plugin/out_test.rb +22 -17
- data/test/scripts/fluent/plugin/out_test2.rb +80 -0
- data/test/test_event.rb +57 -0
- data/test/test_formatter.rb +0 -178
- data/test/test_output.rb +2 -152
- data/test/test_root_agent.rb +3 -2
- data/test/test_supervisor.rb +93 -26
- data/test/test_time_formatter.rb +186 -0
- metadata +69 -7
- data/test/test_parser.rb +0 -1087
@@ -0,0 +1,69 @@
|
|
1
|
+
#
|
2
|
+
# Fluentd
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
require 'fluent/config/error'
|
18
|
+
require 'fluent/compat/record_filter_mixin'
|
19
|
+
require 'fluent/time'
|
20
|
+
require 'fluent/timezone'
|
21
|
+
|
22
|
+
module Fluent
|
23
|
+
module Compat
|
24
|
+
module SetTimeKeyMixin
|
25
|
+
include RecordFilterMixin
|
26
|
+
|
27
|
+
attr_accessor :include_time_key, :time_key, :localtime, :timezone
|
28
|
+
|
29
|
+
def configure(conf)
|
30
|
+
@include_time_key = false
|
31
|
+
@localtime = false
|
32
|
+
@timezone = nil
|
33
|
+
|
34
|
+
super
|
35
|
+
|
36
|
+
if s = conf['include_time_key']
|
37
|
+
include_time_key = Fluent::Config.bool_value(s)
|
38
|
+
raise Fluent::ConfigError, "Invalid boolean expression '#{s}' for include_time_key parameter" if include_time_key.nil?
|
39
|
+
|
40
|
+
@include_time_key = include_time_key
|
41
|
+
end
|
42
|
+
|
43
|
+
if @include_time_key
|
44
|
+
@time_key = conf['time_key'] || 'time'
|
45
|
+
@time_format = conf['time_format']
|
46
|
+
|
47
|
+
if conf['localtime']
|
48
|
+
@localtime = true
|
49
|
+
elsif conf['utc']
|
50
|
+
@localtime = false
|
51
|
+
end
|
52
|
+
|
53
|
+
if conf['timezone']
|
54
|
+
@timezone = conf['timezone']
|
55
|
+
Fluent::Timezone.validate!(@timezone)
|
56
|
+
end
|
57
|
+
|
58
|
+
@timef = Fluent::TimeFormatter.new(@time_format, @localtime, @timezone)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def filter_record(tag, time, record)
|
63
|
+
super
|
64
|
+
|
65
|
+
record[@time_key] = @timef.format(time) if @include_time_key
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
#
|
2
|
+
# Fluentd
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
module Fluent
|
18
|
+
module Compat
|
19
|
+
module TypeConverter
|
20
|
+
Converters = {
|
21
|
+
'string' => lambda { |v| v.to_s },
|
22
|
+
'integer' => lambda { |v| v.to_i },
|
23
|
+
'float' => lambda { |v| v.to_f },
|
24
|
+
'bool' => lambda { |v|
|
25
|
+
case v.downcase
|
26
|
+
when 'true', 'yes', '1'
|
27
|
+
true
|
28
|
+
else
|
29
|
+
false
|
30
|
+
end
|
31
|
+
},
|
32
|
+
'time' => lambda { |v, time_parser|
|
33
|
+
time_parser.parse(v)
|
34
|
+
},
|
35
|
+
'array' => lambda { |v, delimiter|
|
36
|
+
v.to_s.split(delimiter)
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
def self.included(klass)
|
41
|
+
klass.instance_eval {
|
42
|
+
config_param :types, :string, default: nil
|
43
|
+
config_param :types_delimiter, :string, default: ','
|
44
|
+
config_param :types_label_delimiter, :string, default: ':'
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def configure(conf)
|
49
|
+
super
|
50
|
+
|
51
|
+
@type_converters = nil
|
52
|
+
@type_converters = parse_types_parameter unless @types.nil?
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def convert_type(name, value)
|
58
|
+
converter = @type_converters[name]
|
59
|
+
converter.nil? ? value : converter.call(value)
|
60
|
+
end
|
61
|
+
|
62
|
+
def parse_types_parameter
|
63
|
+
converters = {}
|
64
|
+
|
65
|
+
@types.split(@types_delimiter).each { |pattern_name|
|
66
|
+
name, type, format = pattern_name.split(@types_label_delimiter, 3)
|
67
|
+
raise ConfigError, "Type is needed" if type.nil?
|
68
|
+
|
69
|
+
case type
|
70
|
+
when 'time'
|
71
|
+
require 'fluent/parser'
|
72
|
+
t_parser = Fluent::TextParser::TimeParser.new(format)
|
73
|
+
converters[name] = lambda { |v|
|
74
|
+
Converters[type].call(v, t_parser)
|
75
|
+
}
|
76
|
+
when 'array'
|
77
|
+
delimiter = format || ','
|
78
|
+
converters[name] = lambda { |v|
|
79
|
+
Converters[type].call(v, delimiter)
|
80
|
+
}
|
81
|
+
else
|
82
|
+
converters[name] = Converters[type]
|
83
|
+
end
|
84
|
+
}
|
85
|
+
|
86
|
+
converters
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -19,7 +19,7 @@ module Fluent
|
|
19
19
|
class ConfigureProxy
|
20
20
|
attr_accessor :name, :final, :param_name, :init, :required, :multi, :alias, :configured_in_section
|
21
21
|
attr_accessor :argument, :params, :defaults, :descriptions, :sections
|
22
|
-
# config_param :desc, :string, :
|
22
|
+
# config_param :desc, :string, default: '....'
|
23
23
|
# config_set_default :buffer_type, :memory
|
24
24
|
#
|
25
25
|
# config_section :default, required: true, multi: false do
|
@@ -37,10 +37,16 @@ module Fluent
|
|
37
37
|
# end
|
38
38
|
# end
|
39
39
|
|
40
|
-
def initialize(name, param_name: nil, final: nil, init: nil, required: nil, multi: nil, alias: nil, type_lookup:)
|
40
|
+
def initialize(name, root: false, param_name: nil, final: nil, init: nil, required: nil, multi: nil, alias: nil, type_lookup:)
|
41
41
|
@name = name.to_sym
|
42
42
|
@final = final
|
43
43
|
|
44
|
+
# For ConfigureProxy of root section, "@name" should be a class name of plugins.
|
45
|
+
# Otherwise (like subsections), "@name" should be a name of section, like "buffer", "store".
|
46
|
+
# For subsections, name will be used as parameter names (unless param_name exists), so overriding proxy's name
|
47
|
+
# should override "@name".
|
48
|
+
@root_section = root
|
49
|
+
|
44
50
|
@param_name = param_name && param_name.to_sym
|
45
51
|
@init = init
|
46
52
|
@required = required
|
@@ -67,6 +73,10 @@ module Fluent
|
|
67
73
|
@param_name || @name
|
68
74
|
end
|
69
75
|
|
76
|
+
def root?
|
77
|
+
@root_section
|
78
|
+
end
|
79
|
+
|
70
80
|
def init?
|
71
81
|
@init.nil? ? false : @init
|
72
82
|
end
|
@@ -105,7 +115,12 @@ module Fluent
|
|
105
115
|
options[:final] = @final || other.final
|
106
116
|
options[:type_lookup] = @type_lookup
|
107
117
|
|
108
|
-
merged = self.
|
118
|
+
merged = if self.root?
|
119
|
+
options[:root] = true
|
120
|
+
self.class.new(other.name, options)
|
121
|
+
else
|
122
|
+
self.class.new(@name, options)
|
123
|
+
end
|
109
124
|
|
110
125
|
# configured_in MUST be kept
|
111
126
|
merged.configured_in_section = self.configured_in_section
|
@@ -155,7 +170,12 @@ module Fluent
|
|
155
170
|
options[:final] = true
|
156
171
|
options[:type_lookup] = @type_lookup
|
157
172
|
|
158
|
-
merged = self.
|
173
|
+
merged = if self.root?
|
174
|
+
options[:root] = true
|
175
|
+
self.class.new(other.name, options)
|
176
|
+
else
|
177
|
+
self.class.new(@name, options)
|
178
|
+
end
|
159
179
|
|
160
180
|
merged.configured_in_section = self.configured_in_section
|
161
181
|
|
data/lib/fluent/config/dsl.rb
CHANGED
@@ -35,14 +35,19 @@ module Fluent
|
|
35
35
|
end
|
36
36
|
|
37
37
|
class Proxy
|
38
|
-
def initialize(name, arg)
|
38
|
+
def initialize(name, arg, include_basepath = Dir.pwd)
|
39
39
|
@element = Element.new(name, arg, self)
|
40
|
+
@include_basepath = include_basepath
|
40
41
|
end
|
41
42
|
|
42
43
|
def element
|
43
44
|
@element
|
44
45
|
end
|
45
46
|
|
47
|
+
def include_basepath
|
48
|
+
@include_basepath
|
49
|
+
end
|
50
|
+
|
46
51
|
def eval(source, source_path)
|
47
52
|
@element.instance_eval(source, source_path)
|
48
53
|
self
|
@@ -100,6 +105,18 @@ module Fluent
|
|
100
105
|
self
|
101
106
|
end
|
102
107
|
|
108
|
+
def include(*args)
|
109
|
+
::Kernel.raise ::ArgumentError, "#{name} block requires arguments for include path" if args.nil? || args.size != 1
|
110
|
+
if args.first =~ /\.rb$/
|
111
|
+
path = File.expand_path(args.first)
|
112
|
+
data = File.read(path)
|
113
|
+
self.instance_eval(data, path)
|
114
|
+
else
|
115
|
+
ss = StringScanner.new('')
|
116
|
+
Config::V1Parser.new(ss, @proxy.include_basepath, '', nil).eval_include(@attrs, @elements, args.first)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
103
120
|
def source(&block)
|
104
121
|
@proxy.add_element('source', nil, block)
|
105
122
|
end
|
@@ -148,14 +148,15 @@ module Fluent
|
|
148
148
|
|
149
149
|
def eval_include(attrs, elems, uri)
|
150
150
|
u = URI.parse(uri)
|
151
|
-
if u.scheme == 'file' || u.path == uri
|
151
|
+
if u.scheme == 'file' || (!u.scheme.nil? && u.scheme.length == 1) || u.path == uri # file path
|
152
|
+
# When the Windows absolute path then u.scheme.length == 1
|
153
|
+
# e.g. C:
|
152
154
|
path = u.path
|
153
155
|
if path[0] != ?/
|
154
156
|
pattern = File.expand_path("#{@include_basepath}/#{path}")
|
155
157
|
else
|
156
158
|
pattern = path
|
157
159
|
end
|
158
|
-
|
159
160
|
Dir.glob(pattern).sort.each { |entry|
|
160
161
|
basepath = File.dirname(entry)
|
161
162
|
fname = File.basename(entry)
|
data/lib/fluent/configurable.rb
CHANGED
@@ -119,7 +119,7 @@ module Fluent
|
|
119
119
|
map = configure_proxy_map
|
120
120
|
unless map[mod_name]
|
121
121
|
type_lookup = ->(type) { Fluent::Configurable.lookup_type(type) }
|
122
|
-
proxy = Fluent::Config::ConfigureProxy.new(mod_name, required: true, multi: false, type_lookup: type_lookup)
|
122
|
+
proxy = Fluent::Config::ConfigureProxy.new(mod_name, root: true, required: true, multi: false, type_lookup: type_lookup)
|
123
123
|
map[mod_name] = proxy
|
124
124
|
end
|
125
125
|
map[mod_name]
|
data/lib/fluent/event.rb
CHANGED
@@ -21,11 +21,25 @@ module Fluent
|
|
21
21
|
include Enumerable
|
22
22
|
include MessagePackFactory::Mixin
|
23
23
|
|
24
|
+
# dup does deep copy for event stream
|
25
|
+
def dup
|
26
|
+
raise NotImplementedError, "DO NOT USE THIS CLASS directly."
|
27
|
+
end
|
28
|
+
|
24
29
|
def size
|
25
30
|
raise NotImplementedError, "DO NOT USE THIS CLASS directly."
|
26
31
|
end
|
27
32
|
alias :length :size
|
28
33
|
|
34
|
+
def empty?
|
35
|
+
size == 0
|
36
|
+
end
|
37
|
+
|
38
|
+
# for tests
|
39
|
+
def ==(other)
|
40
|
+
other.is_a?(EventStream) && self.to_msgpack_stream == other.to_msgpack_stream
|
41
|
+
end
|
42
|
+
|
29
43
|
def repeatable?
|
30
44
|
false
|
31
45
|
end
|
@@ -70,6 +84,14 @@ module Fluent
|
|
70
84
|
true
|
71
85
|
end
|
72
86
|
|
87
|
+
def slice(index, num)
|
88
|
+
if index > 0 || num == 0
|
89
|
+
ArrayEventStream.new([])
|
90
|
+
else
|
91
|
+
self.dup
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
73
95
|
def each(&block)
|
74
96
|
block.call(@time, @record)
|
75
97
|
nil
|
@@ -86,7 +108,7 @@ module Fluent
|
|
86
108
|
end
|
87
109
|
|
88
110
|
def dup
|
89
|
-
entries = @entries.map
|
111
|
+
entries = @entries.map{ |time, record| [time, record.dup] }
|
90
112
|
ArrayEventStream.new(entries)
|
91
113
|
end
|
92
114
|
|
@@ -119,17 +141,13 @@ module Fluent
|
|
119
141
|
# 2. add events
|
120
142
|
# stream[tag].add(time, record)
|
121
143
|
class MultiEventStream < EventStream
|
122
|
-
def initialize
|
123
|
-
@time_array =
|
124
|
-
@record_array =
|
144
|
+
def initialize(time_array = [], record_array = [])
|
145
|
+
@time_array = time_array
|
146
|
+
@record_array = record_array
|
125
147
|
end
|
126
148
|
|
127
149
|
def dup
|
128
|
-
|
129
|
-
@time_array.zip(@record_array).each { |time, record|
|
130
|
-
es.add(time, record.dup)
|
131
|
-
}
|
132
|
-
es
|
150
|
+
MultiEventStream.new(@time_array.dup, @record_array.map(&:dup))
|
133
151
|
end
|
134
152
|
|
135
153
|
def size
|
@@ -166,6 +184,16 @@ module Fluent
|
|
166
184
|
@size = size
|
167
185
|
end
|
168
186
|
|
187
|
+
def empty?
|
188
|
+
# This is not correct, but actual number of records will be shown after iteration, and
|
189
|
+
# "size" argument is always 0 currently (because forward protocol doesn't tell it to destination)
|
190
|
+
false
|
191
|
+
end
|
192
|
+
|
193
|
+
def dup
|
194
|
+
MessagePackEventStream.new(@data.dup, @size)
|
195
|
+
end
|
196
|
+
|
169
197
|
def size
|
170
198
|
@size
|
171
199
|
end
|
data/lib/fluent/mixin.rb
CHANGED
@@ -14,292 +14,18 @@
|
|
14
14
|
# limitations under the License.
|
15
15
|
#
|
16
16
|
|
17
|
-
require 'fluent/
|
18
|
-
require 'fluent/
|
19
|
-
require 'fluent/
|
17
|
+
require 'fluent/compat/record_filter_mixin'
|
18
|
+
require 'fluent/compat/handle_tag_name_mixin'
|
19
|
+
require 'fluent/compat/set_time_key_mixin'
|
20
|
+
require 'fluent/compat/set_tag_key_mixin'
|
21
|
+
require 'fluent/compat/type_converter'
|
20
22
|
|
21
|
-
|
22
|
-
class TimeFormatter
|
23
|
-
def initialize(format, localtime, timezone = nil)
|
24
|
-
@tc1 = 0
|
25
|
-
@tc1_str = nil
|
26
|
-
@tc2 = 0
|
27
|
-
@tc2_str = nil
|
28
|
-
|
29
|
-
if format && format =~ /(^|[^%])(%%)*%L|(^|[^%])(%%)*%\d*N/
|
30
|
-
define_singleton_method(:format) {|time|
|
31
|
-
format_with_subsec(time)
|
32
|
-
}
|
33
|
-
else
|
34
|
-
define_singleton_method(:format) {|time|
|
35
|
-
format_without_subsec(time)
|
36
|
-
}
|
37
|
-
end
|
38
|
-
|
39
|
-
if formatter = Fluent::Timezone.formatter(timezone, format)
|
40
|
-
define_singleton_method(:format_nocache) {|time|
|
41
|
-
formatter.call(time)
|
42
|
-
}
|
43
|
-
return
|
44
|
-
end
|
45
|
-
|
46
|
-
if format
|
47
|
-
if localtime
|
48
|
-
define_singleton_method(:format_nocache) {|time|
|
49
|
-
Time.at(time).strftime(format)
|
50
|
-
}
|
51
|
-
else
|
52
|
-
define_singleton_method(:format_nocache) {|time|
|
53
|
-
Time.at(time).utc.strftime(format)
|
54
|
-
}
|
55
|
-
end
|
56
|
-
else
|
57
|
-
if localtime
|
58
|
-
define_singleton_method(:format_nocache) {|time|
|
59
|
-
Time.at(time).iso8601
|
60
|
-
}
|
61
|
-
else
|
62
|
-
define_singleton_method(:format_nocache) {|time|
|
63
|
-
Time.at(time).utc.iso8601
|
64
|
-
}
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def format_without_subsec(time)
|
70
|
-
if @tc1 == time
|
71
|
-
return @tc1_str
|
72
|
-
elsif @tc2 == time
|
73
|
-
return @tc2_str
|
74
|
-
else
|
75
|
-
str = format_nocache(time)
|
76
|
-
if @tc1 < @tc2
|
77
|
-
@tc1 = time
|
78
|
-
@tc1_str = str
|
79
|
-
else
|
80
|
-
@tc2 = time
|
81
|
-
@tc2_str = str
|
82
|
-
end
|
83
|
-
return str
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def format_with_subsec(time)
|
88
|
-
if Fluent::EventTime.eq?(@tc1, time)
|
89
|
-
return @tc1_str
|
90
|
-
elsif Fluent::EventTime.eq?(@tc2, time)
|
91
|
-
return @tc2_str
|
92
|
-
else
|
93
|
-
str = format_nocache(time)
|
94
|
-
if @tc1 < @tc2
|
95
|
-
@tc1 = time
|
96
|
-
@tc1_str = str
|
97
|
-
else
|
98
|
-
@tc2 = time
|
99
|
-
@tc2_str = str
|
100
|
-
end
|
101
|
-
return str
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def format(time)
|
106
|
-
# will be overridden in initialize
|
107
|
-
end
|
108
|
-
|
109
|
-
def format_nocache(time)
|
110
|
-
# will be overridden in initialize
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
|
115
|
-
module RecordFilterMixin
|
116
|
-
def filter_record(tag, time, record)
|
117
|
-
end
|
118
|
-
|
119
|
-
def format_stream(tag, es)
|
120
|
-
out = ''
|
121
|
-
es.each {|time,record|
|
122
|
-
tag_temp = tag.dup
|
123
|
-
filter_record(tag_temp, time, record)
|
124
|
-
out << format(tag_temp, time, record)
|
125
|
-
}
|
126
|
-
out
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
module HandleTagNameMixin
|
131
|
-
include RecordFilterMixin
|
132
|
-
|
133
|
-
attr_accessor :remove_tag_prefix, :remove_tag_suffix, :add_tag_prefix, :add_tag_suffix
|
134
|
-
def configure(conf)
|
135
|
-
super
|
136
|
-
|
137
|
-
@remove_tag_prefix = if conf.has_key?('remove_tag_prefix')
|
138
|
-
Regexp.new('^' + Regexp.escape(conf['remove_tag_prefix']))
|
139
|
-
else
|
140
|
-
nil
|
141
|
-
end
|
142
|
-
|
143
|
-
@remove_tag_suffix = if conf.has_key?('remove_tag_suffix')
|
144
|
-
Regexp.new(Regexp.escape(conf['remove_tag_suffix']) + '$')
|
145
|
-
else
|
146
|
-
nil
|
147
|
-
end
|
148
|
-
|
149
|
-
@add_tag_prefix = conf['add_tag_prefix']
|
150
|
-
@add_tag_suffix = conf['add_tag_suffix']
|
151
|
-
end
|
152
|
-
|
153
|
-
def filter_record(tag, time, record)
|
154
|
-
tag.sub!(@remove_tag_prefix, '') if @remove_tag_prefix
|
155
|
-
tag.sub!(@remove_tag_suffix, '') if @remove_tag_suffix
|
156
|
-
tag.insert(0, @add_tag_prefix) if @add_tag_prefix
|
157
|
-
tag << @add_tag_suffix if @add_tag_suffix
|
158
|
-
super(tag, time, record)
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
module SetTimeKeyMixin
|
163
|
-
require 'fluent/timezone'
|
164
|
-
include RecordFilterMixin
|
165
|
-
|
166
|
-
attr_accessor :include_time_key, :time_key, :localtime, :timezone
|
167
|
-
|
168
|
-
def configure(conf)
|
169
|
-
@include_time_key = false
|
170
|
-
@localtime = false
|
171
|
-
@timezone = nil
|
172
|
-
|
173
|
-
super
|
174
|
-
|
175
|
-
if s = conf['include_time_key']
|
176
|
-
include_time_key = Config.bool_value(s)
|
177
|
-
raise ConfigError, "Invalid boolean expression '#{s}' for include_time_key parameter" if include_time_key.nil?
|
178
|
-
|
179
|
-
@include_time_key = include_time_key
|
180
|
-
end
|
181
|
-
|
182
|
-
if @include_time_key
|
183
|
-
@time_key = conf['time_key'] || 'time'
|
184
|
-
@time_format = conf['time_format']
|
23
|
+
require 'fluent/time' # Fluent::TimeFormatter
|
185
24
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
if conf['timezone']
|
193
|
-
@timezone = conf['timezone']
|
194
|
-
Fluent::Timezone.validate!(@timezone)
|
195
|
-
end
|
196
|
-
|
197
|
-
@timef = TimeFormatter.new(@time_format, @localtime, @timezone)
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
def filter_record(tag, time, record)
|
202
|
-
super
|
203
|
-
|
204
|
-
record[@time_key] = @timef.format(time) if @include_time_key
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
module SetTagKeyMixin
|
209
|
-
include RecordFilterMixin
|
210
|
-
|
211
|
-
attr_accessor :include_tag_key, :tag_key
|
212
|
-
|
213
|
-
def configure(conf)
|
214
|
-
@include_tag_key = false
|
215
|
-
|
216
|
-
super
|
217
|
-
|
218
|
-
if s = conf['include_tag_key']
|
219
|
-
include_tag_key = Config.bool_value(s)
|
220
|
-
raise ConfigError, "Invalid boolean expression '#{s}' for include_tag_key parameter" if include_tag_key.nil?
|
221
|
-
|
222
|
-
@include_tag_key = include_tag_key
|
223
|
-
end
|
224
|
-
|
225
|
-
@tag_key = conf['tag_key'] || 'tag' if @include_tag_key
|
226
|
-
end
|
227
|
-
|
228
|
-
def filter_record(tag, time, record)
|
229
|
-
super
|
230
|
-
|
231
|
-
record[@tag_key] = tag if @include_tag_key
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
module TypeConverter
|
236
|
-
Converters = {
|
237
|
-
'string' => lambda { |v| v.to_s },
|
238
|
-
'integer' => lambda { |v| v.to_i },
|
239
|
-
'float' => lambda { |v| v.to_f },
|
240
|
-
'bool' => lambda { |v|
|
241
|
-
case v.downcase
|
242
|
-
when 'true', 'yes', '1'
|
243
|
-
true
|
244
|
-
else
|
245
|
-
false
|
246
|
-
end
|
247
|
-
},
|
248
|
-
'time' => lambda { |v, time_parser|
|
249
|
-
time_parser.parse(v)
|
250
|
-
},
|
251
|
-
'array' => lambda { |v, delimiter|
|
252
|
-
v.to_s.split(delimiter)
|
253
|
-
}
|
254
|
-
}
|
255
|
-
|
256
|
-
def self.included(klass)
|
257
|
-
klass.instance_eval {
|
258
|
-
config_param :types, :string, default: nil
|
259
|
-
config_param :types_delimiter, :string, default: ','
|
260
|
-
config_param :types_label_delimiter, :string, default: ':'
|
261
|
-
}
|
262
|
-
end
|
263
|
-
|
264
|
-
def configure(conf)
|
265
|
-
super
|
266
|
-
|
267
|
-
@type_converters = nil
|
268
|
-
@type_converters = parse_types_parameter unless @types.nil?
|
269
|
-
end
|
270
|
-
|
271
|
-
private
|
272
|
-
|
273
|
-
def convert_type(name, value)
|
274
|
-
converter = @type_converters[name]
|
275
|
-
converter.nil? ? value : converter.call(value)
|
276
|
-
end
|
277
|
-
|
278
|
-
def parse_types_parameter
|
279
|
-
converters = {}
|
280
|
-
|
281
|
-
@types.split(@types_delimiter).each { |pattern_name|
|
282
|
-
name, type, format = pattern_name.split(@types_label_delimiter, 3)
|
283
|
-
raise ConfigError, "Type is needed" if type.nil?
|
284
|
-
|
285
|
-
case type
|
286
|
-
when 'time'
|
287
|
-
require 'fluent/parser'
|
288
|
-
t_parser = Fluent::TextParser::TimeParser.new(format)
|
289
|
-
converters[name] = lambda { |v|
|
290
|
-
Converters[type].call(v, t_parser)
|
291
|
-
}
|
292
|
-
when 'array'
|
293
|
-
delimiter = format || ','
|
294
|
-
converters[name] = lambda { |v|
|
295
|
-
Converters[type].call(v, delimiter)
|
296
|
-
}
|
297
|
-
else
|
298
|
-
converters[name] = Converters[type]
|
299
|
-
end
|
300
|
-
}
|
301
|
-
|
302
|
-
converters
|
303
|
-
end
|
304
|
-
end
|
25
|
+
module Fluent
|
26
|
+
RecordFilterMixin = Fluent::Compat::RecordFilterMixin
|
27
|
+
HandleTagNameMixin = Fluent::Compat::HandleTagNameMixin
|
28
|
+
SetTimeKeyMixin = Fluent::Compat::SetTimeKeyMixin
|
29
|
+
SetTagKeyMixin = Fluent::Compat::SetTagKeyMixin
|
30
|
+
TypeConverter = Fluent::Compat::TypeConverter
|
305
31
|
end
|