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.

Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/example/copy_roundrobin.conf +39 -0
  3. data/example/filter_stdout.conf +5 -5
  4. data/example/in_forward.conf +2 -2
  5. data/example/in_http.conf +2 -2
  6. data/example/in_syslog.conf +2 -2
  7. data/example/in_tail.conf +2 -2
  8. data/example/in_tcp.conf +2 -2
  9. data/example/in_udp.conf +2 -2
  10. data/example/out_buffered_null.conf +32 -0
  11. data/example/out_copy.conf +4 -4
  12. data/example/out_file.conf +2 -2
  13. data/example/out_forward.conf +2 -2
  14. data/example/v0_12_filter.conf +8 -8
  15. data/fluentd.gemspec +1 -1
  16. data/lib/fluent/command/fluentd.rb +6 -1
  17. data/lib/fluent/compat/handle_tag_name_mixin.rb +53 -0
  18. data/lib/fluent/compat/input.rb +1 -0
  19. data/lib/fluent/compat/output.rb +1 -0
  20. data/lib/fluent/compat/record_filter_mixin.rb +34 -0
  21. data/lib/fluent/compat/set_tag_key_mixin.rb +50 -0
  22. data/lib/fluent/compat/set_time_key_mixin.rb +69 -0
  23. data/lib/fluent/compat/type_converter.rb +90 -0
  24. data/lib/fluent/config/configure_proxy.rb +24 -4
  25. data/lib/fluent/config/dsl.rb +18 -1
  26. data/lib/fluent/config/v1_parser.rb +3 -2
  27. data/lib/fluent/configurable.rb +1 -1
  28. data/lib/fluent/event.rb +37 -9
  29. data/lib/fluent/mixin.rb +12 -286
  30. data/lib/fluent/plugin/buffer.rb +2 -2
  31. data/lib/fluent/plugin/in_dummy.rb +5 -1
  32. data/lib/fluent/plugin/in_gc_stat.rb +7 -37
  33. data/lib/fluent/plugin/in_http.rb +2 -0
  34. data/lib/fluent/plugin/{in_stream.rb → in_unix.rb} +0 -0
  35. data/lib/fluent/plugin/out_buffered_stdout.rb +60 -0
  36. data/lib/fluent/plugin/out_copy.rb +8 -51
  37. data/lib/fluent/plugin/out_null.rb +5 -5
  38. data/lib/fluent/plugin/out_relabel.rb +5 -5
  39. data/lib/fluent/plugin/out_roundrobin.rb +13 -40
  40. data/lib/fluent/plugin/output.rb +9 -0
  41. data/lib/fluent/plugin_helper.rb +2 -0
  42. data/lib/fluent/plugin_helper/formatter.rb +138 -0
  43. data/lib/fluent/plugin_helper/inject.rb +112 -0
  44. data/lib/fluent/plugin_helper/parser.rb +138 -0
  45. data/lib/fluent/plugin_helper/storage.rb +64 -50
  46. data/lib/fluent/process.rb +6 -1
  47. data/lib/fluent/registry.rb +1 -1
  48. data/lib/fluent/supervisor.rb +20 -2
  49. data/lib/fluent/test.rb +30 -5
  50. data/lib/fluent/test/base.rb +2 -66
  51. data/lib/fluent/test/driver/base.rb +3 -0
  52. data/lib/fluent/test/driver/base_owned.rb +106 -0
  53. data/lib/fluent/test/driver/formatter.rb +30 -0
  54. data/lib/fluent/test/driver/multi_output.rb +52 -0
  55. data/lib/fluent/test/driver/owner.rb +32 -0
  56. data/lib/fluent/test/driver/parser.rb +30 -0
  57. data/lib/fluent/test/helpers.rb +54 -0
  58. data/lib/fluent/test/log.rb +73 -0
  59. data/lib/fluent/time.rb +71 -0
  60. data/lib/fluent/version.rb +1 -1
  61. data/test/compat/test_parser.rb +82 -0
  62. data/test/config/test_configure_proxy.rb +15 -0
  63. data/test/config/test_dsl.rb +180 -2
  64. data/test/helper.rb +2 -24
  65. data/test/plugin/test_in_gc_stat.rb +6 -6
  66. data/test/plugin/test_in_http.rb +49 -32
  67. data/test/plugin/{test_in_stream.rb → test_in_unix.rb} +1 -1
  68. data/test/plugin/test_out_buffered_stdout.rb +108 -0
  69. data/test/plugin/test_out_copy.rb +88 -127
  70. data/test/plugin/test_out_null.rb +29 -0
  71. data/test/plugin/test_out_relabel.rb +28 -0
  72. data/test/plugin/test_out_roundrobin.rb +35 -29
  73. data/test/plugin/test_out_stdout.rb +4 -4
  74. data/test/plugin/test_output_as_buffered.rb +51 -0
  75. data/test/plugin/test_output_as_buffered_secondary.rb +13 -0
  76. data/test/plugin/test_parser_apache.rb +38 -0
  77. data/test/plugin/test_parser_apache2.rb +38 -0
  78. data/test/plugin/test_parser_apache_error.rb +40 -0
  79. data/test/plugin/test_parser_base.rb +32 -0
  80. data/test/plugin/test_parser_csv.rb +94 -0
  81. data/test/plugin/test_parser_json.rb +107 -0
  82. data/test/plugin/test_parser_labeled_tsv.rb +129 -0
  83. data/test/plugin/test_parser_multiline.rb +100 -0
  84. data/test/plugin/test_parser_nginx.rb +42 -0
  85. data/test/plugin/test_parser_none.rb +53 -0
  86. data/test/plugin/test_parser_regexp.rb +110 -0
  87. data/test/plugin/test_parser_syslog.rb +66 -0
  88. data/test/plugin/test_parser_time.rb +46 -0
  89. data/test/plugin/test_parser_tsv.rb +125 -0
  90. data/test/plugin_helper/test_child_process.rb +11 -2
  91. data/test/plugin_helper/test_formatter.rb +212 -0
  92. data/test/plugin_helper/test_inject.rb +388 -0
  93. data/test/plugin_helper/test_parser.rb +223 -0
  94. data/test/plugin_helper/test_retry_state.rb +40 -40
  95. data/test/plugin_helper/test_storage.rb +77 -10
  96. data/test/scripts/fluent/plugin/out_test.rb +22 -17
  97. data/test/scripts/fluent/plugin/out_test2.rb +80 -0
  98. data/test/test_event.rb +57 -0
  99. data/test/test_formatter.rb +0 -178
  100. data/test/test_output.rb +2 -152
  101. data/test/test_root_agent.rb +3 -2
  102. data/test/test_supervisor.rb +93 -26
  103. data/test/test_time_formatter.rb +186 -0
  104. metadata +69 -7
  105. 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, :default => '....'
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.class.new(@name, options)
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.class.new(@name, options)
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
 
@@ -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 # file path
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)
@@ -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]
@@ -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 { |entry| entry.dup } # @entries.map(:dup) doesn't work by ArgumentError
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
- es = MultiEventStream.new
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
@@ -14,292 +14,18 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
- require 'fluent/timezone'
18
- require 'fluent/time'
19
- require 'fluent/config/error'
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
- module Fluent
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
- if conf['localtime']
187
- @localtime = true
188
- elsif conf['utc']
189
- @localtime = false
190
- end
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