fluentd 1.7.4-x64-mingw32 → 1.8.0-x64-mingw32

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 (101) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -1
  3. data/.travis.yml +4 -0
  4. data/CHANGELOG.md +70 -0
  5. data/MAINTAINERS.md +1 -0
  6. data/example/out_forward_sd.conf +17 -0
  7. data/example/sd.yaml +8 -0
  8. data/fluentd.gemspec +1 -1
  9. data/lib/fluent/agent.rb +3 -1
  10. data/lib/fluent/command/cat.rb +1 -2
  11. data/lib/fluent/command/fluentd.rb +16 -8
  12. data/lib/fluent/compat/call_super_mixin.rb +9 -0
  13. data/lib/fluent/compat/exec_util.rb +1 -1
  14. data/lib/fluent/config/configure_proxy.rb +4 -4
  15. data/lib/fluent/config/element.rb +28 -15
  16. data/lib/fluent/config/error.rb +6 -0
  17. data/lib/fluent/config/literal_parser.rb +24 -2
  18. data/lib/fluent/config/section.rb +43 -6
  19. data/lib/fluent/config/types.rb +98 -26
  20. data/lib/fluent/configurable.rb +2 -2
  21. data/lib/fluent/counter/base_socket.rb +2 -4
  22. data/lib/fluent/engine.rb +41 -122
  23. data/lib/fluent/event.rb +5 -7
  24. data/lib/fluent/fluent_log_event_router.rb +141 -0
  25. data/lib/fluent/msgpack_factory.rb +19 -2
  26. data/lib/fluent/plugin.rb +10 -1
  27. data/lib/fluent/plugin/base.rb +2 -2
  28. data/lib/fluent/plugin/buf_file.rb +11 -7
  29. data/lib/fluent/plugin/buf_file_single.rb +8 -5
  30. data/lib/fluent/plugin/buffer/chunk.rb +1 -1
  31. data/lib/fluent/plugin/buffer/file_chunk.rb +4 -6
  32. data/lib/fluent/plugin/buffer/file_single_chunk.rb +3 -5
  33. data/lib/fluent/plugin/formatter_csv.rb +23 -1
  34. data/lib/fluent/plugin/formatter_stdout.rb +1 -1
  35. data/lib/fluent/plugin/in_forward.rb +1 -1
  36. data/lib/fluent/plugin/in_monitor_agent.rb +4 -2
  37. data/lib/fluent/plugin/in_tail.rb +6 -0
  38. data/lib/fluent/plugin/in_unix.rb +1 -1
  39. data/lib/fluent/plugin/out_forward.rb +77 -28
  40. data/lib/fluent/plugin/out_forward/ack_handler.rb +1 -1
  41. data/lib/fluent/plugin/out_forward/load_balancer.rb +5 -2
  42. data/lib/fluent/plugin/out_stream.rb +1 -1
  43. data/lib/fluent/plugin/output.rb +11 -3
  44. data/lib/fluent/plugin/parser.rb +1 -0
  45. data/lib/fluent/plugin/sd_file.rb +155 -0
  46. data/lib/fluent/plugin/sd_static.rb +58 -0
  47. data/lib/fluent/plugin/service_discovery.rb +80 -0
  48. data/lib/fluent/plugin_helper.rb +1 -0
  49. data/lib/fluent/plugin_helper/child_process.rb +3 -3
  50. data/lib/fluent/plugin_helper/compat_parameters.rb +11 -1
  51. data/lib/fluent/plugin_helper/extract.rb +1 -1
  52. data/lib/fluent/plugin_helper/inject.rb +1 -1
  53. data/lib/fluent/plugin_helper/record_accessor.rb +10 -19
  54. data/lib/fluent/plugin_helper/server.rb +8 -4
  55. data/lib/fluent/plugin_helper/service_discovery.rb +80 -0
  56. data/lib/fluent/plugin_helper/service_discovery/manager.rb +132 -0
  57. data/lib/fluent/plugin_helper/service_discovery/round_robin_balancer.rb +43 -0
  58. data/lib/fluent/plugin_id.rb +7 -0
  59. data/lib/fluent/root_agent.rb +7 -9
  60. data/lib/fluent/supervisor.rb +192 -211
  61. data/lib/fluent/system_config.rb +26 -52
  62. data/lib/fluent/test/driver/base_owned.rb +15 -2
  63. data/lib/fluent/time.rb +8 -6
  64. data/lib/fluent/version.rb +1 -1
  65. data/test/command/test_fluentd.rb +12 -7
  66. data/test/config/test_configurable.rb +154 -0
  67. data/test/config/test_element.rb +18 -0
  68. data/test/config/test_literal_parser.rb +4 -0
  69. data/test/config/test_system_config.rb +48 -91
  70. data/test/config/test_types.rb +293 -120
  71. data/test/counter/test_client.rb +8 -4
  72. data/test/plugin/data/sd_file/config +11 -0
  73. data/test/plugin/data/sd_file/config.json +17 -0
  74. data/test/plugin/data/sd_file/config.yaml +11 -0
  75. data/test/plugin/data/sd_file/config.yml +11 -0
  76. data/test/plugin/data/sd_file/invalid_config.yml +7 -0
  77. data/test/plugin/out_forward/test_handshake_protocol.rb +2 -2
  78. data/test/plugin/out_forward/test_load_balancer.rb +1 -1
  79. data/test/plugin/out_forward/test_socket_cache.rb +2 -2
  80. data/test/plugin/test_buf_file.rb +40 -0
  81. data/test/plugin/test_buf_file_single.rb +32 -0
  82. data/test/plugin/test_buffer_file_chunk.rb +0 -11
  83. data/test/plugin/test_buffer_file_single_chunk.rb +0 -10
  84. data/test/plugin/test_formatter_csv.rb +9 -0
  85. data/test/plugin/test_in_forward.rb +9 -9
  86. data/test/plugin/test_in_monitor_agent.rb +37 -10
  87. data/test/plugin/test_in_unix.rb +5 -5
  88. data/test/plugin/test_out_forward.rb +45 -1
  89. data/test/plugin/test_out_stdout.rb +36 -1
  90. data/test/plugin/test_out_stream.rb +3 -3
  91. data/test/plugin/test_output.rb +25 -1
  92. data/test/plugin/test_sd_file.rb +211 -0
  93. data/test/plugin_helper/service_discovery/test_manager.rb +93 -0
  94. data/test/plugin_helper/service_discovery/test_round_robin_balancer.rb +21 -0
  95. data/test/plugin_helper/test_server.rb +13 -0
  96. data/test/plugin_helper/test_service_discovery.rb +72 -0
  97. data/test/test_event.rb +15 -15
  98. data/test/test_fluent_log_event_router.rb +99 -0
  99. data/test/test_logger_initializer.rb +26 -0
  100. data/test/test_supervisor.rb +30 -59
  101. metadata +43 -6
@@ -20,7 +20,6 @@ require 'fluent/plugin/compressable'
20
20
  module Fluent
21
21
  class EventStream
22
22
  include Enumerable
23
- include MessagePackFactory::Mixin
24
23
  include Fluent::Plugin::Compressable
25
24
 
26
25
  # dup does deep copy for event stream
@@ -56,7 +55,7 @@ module Fluent
56
55
 
57
56
  def to_msgpack_stream(time_int: false, packer: nil)
58
57
  return to_msgpack_stream_forced_integer(packer: packer) if time_int
59
- out = packer || msgpack_packer
58
+ out = packer || Fluent::MessagePackFactory.msgpack_packer
60
59
  each {|time,record|
61
60
  out.write([time,record])
62
61
  }
@@ -69,7 +68,7 @@ module Fluent
69
68
  end
70
69
 
71
70
  def to_msgpack_stream_forced_integer(packer: nil)
72
- out = packer || msgpack_packer
71
+ out = packer || Fluent::MessagePackFactory.msgpack_packer
73
72
  each {|time,record|
74
73
  out.write([time.to_i,record])
75
74
  }
@@ -238,7 +237,7 @@ module Fluent
238
237
  return if @unpacked_times && @unpacked_records
239
238
  @unpacked_times = []
240
239
  @unpacked_records = []
241
- (unpacker || msgpack_unpacker).feed_each(@data) do |time, record|
240
+ (unpacker || Fluent::MessagePackFactory.msgpack_unpacker).feed_each(@data) do |time, record|
242
241
  @unpacked_times << time
243
242
  @unpacked_records << record
244
243
  end
@@ -262,7 +261,7 @@ module Fluent
262
261
  else
263
262
  @unpacked_times = []
264
263
  @unpacked_records = []
265
- (unpacker || msgpack_unpacker).feed_each(@data) do |time, record|
264
+ (unpacker || Fluent::MessagePackFactory.msgpack_unpacker).feed_each(@data) do |time, record|
266
265
  @unpacked_times << time
267
266
  @unpacked_records << record
268
267
  block.call(time, record)
@@ -319,12 +318,11 @@ module Fluent
319
318
  end
320
319
 
321
320
  module ChunkMessagePackEventStreamer
322
- include MessagePackFactory::Mixin
323
321
  # chunk.extend(ChunkEventStreamer)
324
322
  # => chunk.each{|time, record| ... }
325
323
  def each(unpacker: nil, &block)
326
324
  open do |io|
327
- (unpacker || msgpack_unpacker(io)).each(&block)
325
+ (unpacker || Fluent::MessagePackFactory.msgpack_unpacker(io)).each(&block)
328
326
  end
329
327
  nil
330
328
  end
@@ -0,0 +1,141 @@
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/log'
18
+
19
+ module Fluent
20
+ # DO NOT write any logic here
21
+ class NullFluentLogEventRouter
22
+ def start; end
23
+
24
+ def stop; end
25
+
26
+ def graceful_stop; end
27
+
28
+ def emit_event(_event); end
29
+
30
+ def emittable?
31
+ self.class != NullFluentLogEventRouter
32
+ end
33
+ end
34
+
35
+ # This class is for handling fluentd's inner log
36
+ # e.g. <label @FLUNT_LOG> section and <match fluent.**> section
37
+ class FluentLogEventRouter < NullFluentLogEventRouter
38
+ # @param root_agent [Fluent::RootAgent]
39
+ def self.build(root_agent)
40
+ log_event_router = nil
41
+
42
+ begin
43
+ log_event_agent = root_agent.find_label(Fluent::Log::LOG_EVENT_LABEL)
44
+ log_event_router = log_event_agent.event_router
45
+
46
+ # suppress mismatched tags only for <label @FLUENT_LOG> label.
47
+ # it's not suppressed in default event router for non-log-event events
48
+ log_event_router.suppress_missing_match!
49
+
50
+ log_event_router = log_event_router
51
+
52
+ unmatched_tags = Fluent::Log.event_tags.select { |t| !log_event_router.match?(t) }
53
+ unless unmatched_tags.empty?
54
+ $log.warn "match for some tags of log events are not defined in @FLUENT_LOG label (to be ignored)", tags: unmatched_tags
55
+ end
56
+
57
+ rescue ArgumentError # ArgumentError "#{label_name} label not found"
58
+ # use default event router if <label @FLUENT_LOG> is missing in configuration
59
+ root_log_event_router = root_agent.event_router
60
+ event_tags = Fluent::Log.event_tags
61
+ if event_tags.any? { |t| root_log_event_router.match?(t) }
62
+ log_event_router = root_log_event_router
63
+
64
+ unmatched_tags = event_tags.select { |t| !log_event_router.match?(t) }
65
+ if unmatched_tags.empty?
66
+ $log.warn "define <match fluent.**> to capture fluentd logs in top level is deprecated. Use <label @FLUENT_LOG> instead"
67
+ else
68
+ matched_sections = (event_tags - unmatched_tags).map { |tag| "<match #{tag}>" }.join(', ')
69
+ $log.warn "define #{matched_sections} to capture fluentd logs in top level is deprecated. Use <label @FLUENT_LOG> instead"
70
+ $log.warn "match for some tags of log events are not defined in top level (to be ignored)", tags: unmatched_tags
71
+ end
72
+ end
73
+ end
74
+
75
+ if log_event_router
76
+ FluentLogEventRouter.new(log_event_router)
77
+ else
78
+ $log.debug('No fluent logger for internal event')
79
+ NullFluentLogEventRouter.new
80
+ end
81
+ end
82
+
83
+ STOP = :stop
84
+ GRACEFUL_STOP = :graceful_stop
85
+
86
+ # @param event_router [Fluent::EventRouter]
87
+ def initialize(event_router)
88
+ @event_router = event_router
89
+ @thread = nil
90
+ @graceful_stop = false
91
+ @event_queue = Queue.new
92
+ end
93
+
94
+ def start
95
+ @thread = Thread.new do
96
+ $log.disable_events(Thread.current)
97
+
98
+ loop do
99
+ event = @event_queue.pop
100
+
101
+ case event
102
+ when GRACEFUL_STOP
103
+ @graceful_stop = true
104
+ when STOP
105
+ break
106
+ else
107
+ begin
108
+ tag, time, record = event
109
+ @event_router.emit(tag, time, record)
110
+ rescue => e
111
+ # This $log.error doesn't emit log events, because of `$log.disable_events(Thread.current)` above
112
+ $log.error "failed to emit fluentd's log event", tag: tag, event: record, error: e
113
+ end
114
+ end
115
+
116
+ if @graceful_stop && @event_queue.empty?
117
+ break
118
+ end
119
+ end
120
+ end
121
+
122
+ @thread.abort_on_exception = true
123
+ end
124
+
125
+ def stop
126
+ @event_queue.push(STOP)
127
+ # there is no problem calling Thread#join multiple times.
128
+ @thread && @thread.join
129
+ end
130
+
131
+ def graceful_stop
132
+ # to make sure to emit all log events into router, before shutting down
133
+ @event_queue.push(GRACEFUL_STOP)
134
+ @thread && @thread.join
135
+ end
136
+
137
+ def emit_event(event)
138
+ @event_queue.push(event)
139
+ end
140
+ end
141
+ end
@@ -23,15 +23,24 @@ module Fluent
23
23
 
24
24
  module Mixin
25
25
  def msgpack_factory
26
+ if $log
27
+ $log.warn('Deprecated method: this method is going to be deleted. Use Fluent::MessagePackFactory.engine_factory')
28
+ end
26
29
  MessagePackFactory.engine_factory
27
30
  end
28
31
 
29
32
  def msgpack_packer(*args)
30
- msgpack_factory.packer(*args)
33
+ if $log
34
+ $log.warn('Deprecated method: this method is going to be deleted. Use Fluent::MessagePackFactory.msgpack_packer')
35
+ end
36
+ MessagePackFactory.msgpack_packer(*args)
31
37
  end
32
38
 
33
39
  def msgpack_unpacker(*args)
34
- msgpack_factory.unpacker(*args)
40
+ if $log
41
+ $log.warn('Deprecated method: this method is going to be deleted. Use Fluent::MessagePackFactory.msgpack_unpacker')
42
+ end
43
+ MessagePackFactory.msgpack_unpacker(*args)
35
44
  end
36
45
  end
37
46
 
@@ -39,6 +48,14 @@ module Fluent
39
48
  @@engine_factory || factory
40
49
  end
41
50
 
51
+ def self.msgpack_packer(*args)
52
+ engine_factory.packer(*args)
53
+ end
54
+
55
+ def self.msgpack_unpacker(*args)
56
+ engine_factory.unpacker(*args)
57
+ end
58
+
42
59
  def self.factory
43
60
  factory = MessagePack::Factory.new
44
61
  factory.register_type(Fluent::EventTime::TYPE, Fluent::EventTime)
@@ -35,8 +35,9 @@ module Fluent
35
35
  PARSER_REGISTRY = Registry.new(:parser, 'fluent/plugin/parser_', dir_search_prefix: 'parser_')
36
36
  FORMATTER_REGISTRY = Registry.new(:formatter, 'fluent/plugin/formatter_', dir_search_prefix: 'formatter_')
37
37
  STORAGE_REGISTRY = Registry.new(:storage, 'fluent/plugin/storage_', dir_search_prefix: 'storage_')
38
+ SD_REGISTRY = Registry.new(:sd, 'fluent/plugin/sd_', dir_search_prefix: 'sd_')
38
39
 
39
- REGISTRIES = [INPUT_REGISTRY, OUTPUT_REGISTRY, FILTER_REGISTRY, BUFFER_REGISTRY, PARSER_REGISTRY, FORMATTER_REGISTRY, STORAGE_REGISTRY]
40
+ REGISTRIES = [INPUT_REGISTRY, OUTPUT_REGISTRY, FILTER_REGISTRY, BUFFER_REGISTRY, PARSER_REGISTRY, FORMATTER_REGISTRY, STORAGE_REGISTRY, SD_REGISTRY]
40
41
 
41
42
  def self.register_input(type, klass)
42
43
  register_impl('input', INPUT_REGISTRY, type, klass)
@@ -54,6 +55,10 @@ module Fluent
54
55
  register_impl('buffer', BUFFER_REGISTRY, type, klass)
55
56
  end
56
57
 
58
+ def self.register_sd(type, klass)
59
+ register_impl('sd', SD_REGISTRY, type, klass)
60
+ end
61
+
57
62
  def self.register_parser(type, klass_or_proc)
58
63
  if klass_or_proc.is_a?(Regexp)
59
64
  # This usage is not recommended for new API
@@ -112,6 +117,10 @@ module Fluent
112
117
  new_impl('buffer', BUFFER_REGISTRY, type, parent)
113
118
  end
114
119
 
120
+ def self.new_sd(type, parent: nil)
121
+ new_impl('sd', SD_REGISTRY, type, parent)
122
+ end
123
+
115
124
  def self.new_parser(type, parent: nil)
116
125
  if type[0] == '/' && type[-1] == '/'
117
126
  # This usage is not recommended for new API... create RegexpParser directly
@@ -52,7 +52,7 @@ module Fluent
52
52
  end
53
53
 
54
54
  def configure(conf)
55
- if conf.respond_to?(:for_this_worker?) && conf.for_this_worker?
55
+ if Fluent::Engine.supervisor_mode || (conf.respond_to?(:for_this_worker?) && conf.for_this_worker?)
56
56
  workers = if conf.target_worker_ids && !conf.target_worker_ids.empty?
57
57
  conf.target_worker_ids.size
58
58
  else
@@ -60,7 +60,7 @@ module Fluent
60
60
  end
61
61
  system_config_override(workers: workers)
62
62
  end
63
- super
63
+ super(conf, system_config.strict_config_value)
64
64
  @_state ||= State.new(false, false, false, false, false, false, false, false, false)
65
65
  @_state.configure = true
66
66
  self
@@ -50,6 +50,7 @@ module Fluent
50
50
  @symlink_path = nil
51
51
  @multi_workers_available = false
52
52
  @additional_resume_path = nil
53
+ @buffer_path = nil
53
54
  end
54
55
 
55
56
  def configure(conf)
@@ -73,7 +74,8 @@ module Fluent
73
74
  raise ConfigError, "Other '#{type_using_this_path}' plugin already use same buffer path: type = #{type_of_owner}, buffer path = #{@path}"
74
75
  end
75
76
 
76
- @@buffer_paths[@path] = type_of_owner
77
+ @buffer_path = @path
78
+ @@buffer_paths[@buffer_path] = type_of_owner
77
79
 
78
80
  specified_directory_exists = File.exist?(@path) && File.directory?(@path)
79
81
  unexisting_path_for_directory = !File.exist?(@path) && !@path.include?('.*')
@@ -122,6 +124,12 @@ module Fluent
122
124
  super
123
125
  end
124
126
 
127
+ def stop
128
+ @@buffer_paths.delete(@buffer_path)
129
+
130
+ super
131
+ end
132
+
125
133
  def persistent?
126
134
  true
127
135
  end
@@ -167,12 +175,8 @@ module Fluent
167
175
 
168
176
  def generate_chunk(metadata)
169
177
  # FileChunk generates real path with unique_id
170
- if @file_permission
171
- chunk = Fluent::Plugin::Buffer::FileChunk.new(metadata, @path, :create, perm: @file_permission, compress: @compress)
172
- else
173
- chunk = Fluent::Plugin::Buffer::FileChunk.new(metadata, @path, :create, compress: @compress)
174
- end
175
-
178
+ perm = @file_permission || system_config.file_permission
179
+ chunk = Fluent::Plugin::Buffer::FileChunk.new(metadata, @path, :create, perm: perm, compress: @compress)
176
180
  log.debug "Created new chunk", chunk_id: dump_unique_id_hex(chunk.unique_id), metadata: metadata
177
181
 
178
182
  return chunk
@@ -144,6 +144,12 @@ module Fluent
144
144
  super
145
145
  end
146
146
 
147
+ def stop
148
+ @@buffer_paths.delete(@path)
149
+
150
+ super
151
+ end
152
+
147
153
  def persistent?
148
154
  true
149
155
  end
@@ -189,11 +195,8 @@ module Fluent
189
195
 
190
196
  def generate_chunk(metadata)
191
197
  # FileChunk generates real path with unique_id
192
- if @file_permission
193
- chunk = Fluent::Plugin::Buffer::FileSingleChunk.new(metadata, @path, :create, @key_in_path, perm: @file_permission, compress: @compress)
194
- else
195
- chunk = Fluent::Plugin::Buffer::FileSingleChunk.new(metadata, @path, :create, @key_in_path, compress: @compress)
196
- end
198
+ perm = @file_permission || system_config.file_permission
199
+ chunk = Fluent::Plugin::Buffer::FileSingleChunk.new(metadata, @path, :create, @key_in_path, perm: perm, compress: @compress)
197
200
 
198
201
  log.debug "Created new chunk", chunk_id: dump_unique_id_hex(chunk.unique_id), metadata: metadata
199
202
 
@@ -202,7 +202,7 @@ module Fluent
202
202
  if kwargs[:compressed] == :gzip
203
203
  super
204
204
  else
205
- super(kwargs) do |chunk_io|
205
+ super(**kwargs) do |chunk_io|
206
206
  output_io = if chunk_io.is_a?(StringIO)
207
207
  StringIO.new
208
208
  else
@@ -37,15 +37,13 @@ module Fluent
37
37
  # path_prefix: path prefix string, ended with '.'
38
38
  # path_suffix: path suffix string, like '.log' (or any other user specified)
39
39
 
40
- include SystemConfig::Mixin
41
- include MessagePackFactory::Mixin
42
-
43
40
  FILE_PERMISSION = 0644
44
41
 
45
42
  attr_reader :path, :permission
46
43
 
47
- def initialize(metadata, path, mode, perm: system_config.file_permission || FILE_PERMISSION, compress: :text)
44
+ def initialize(metadata, path, mode, perm: nil, compress: :text)
48
45
  super(metadata, compress: compress)
46
+ perm ||= FILE_PERMISSION
49
47
  @permission = perm.is_a?(String) ? perm.to_i(8) : perm
50
48
  @bytesize = @size = @adding_bytes = @adding_size = 0
51
49
  @meta = nil
@@ -221,7 +219,7 @@ module Fluent
221
219
 
222
220
  unless data
223
221
  # old type of restore
224
- data = msgpack_unpacker(symbolize_keys: true).feed(bindata).read rescue {}
222
+ data = Fluent::MessagePackFactory.msgpack_unpacker(symbolize_keys: true).feed(bindata).read rescue {}
225
223
  end
226
224
 
227
225
  now = Fluent::Clock.real_now
@@ -403,7 +401,7 @@ module Fluent
403
401
  if chunk.slice(0, 2) == BUFFER_HEADER
404
402
  size = chunk.slice(2, 4).unpack('N').first
405
403
  if size
406
- return msgpack_unpacker(symbolize_keys: true).feed(chunk.slice(6, size)).read rescue nil
404
+ return Fluent::MessagePackFactory.msgpack_unpacker(symbolize_keys: true).feed(chunk.slice(6, size)).read rescue nil
407
405
  end
408
406
  end
409
407
 
@@ -29,9 +29,6 @@ module Fluent
29
29
  ## buffer chunk path : /path/to/directory/fsb.key.b513b61c9791029c2513b61c9791029c2.buf
30
30
  ## state: b/q - 'b'(on stage), 'q'(enqueued)
31
31
 
32
- include SystemConfig::Mixin
33
- include MessagePackFactory::Mixin
34
-
35
32
  PATH_EXT = 'buf'
36
33
  PATH_SUFFIX = ".#{PATH_EXT}"
37
34
  PATH_REGEXP = /\.(b|q)([0-9a-f]+)\.#{PATH_EXT}*\Z/n # //n switch means explicit 'ASCII-8BIT' pattern
@@ -39,9 +36,10 @@ module Fluent
39
36
 
40
37
  attr_reader :path, :permission
41
38
 
42
- def initialize(metadata, path, mode, key, perm: system_config.file_permission || FILE_PERMISSION, compress: :text)
39
+ def initialize(metadata, path, mode, key, perm: FILE_PERMISSION, compress: :text)
43
40
  super(metadata, compress: compress)
44
41
  @key = key
42
+ perm ||= FILE_PERMISSION
45
43
  @permission = perm.is_a?(String) ? perm.to_i(8) : perm
46
44
  @bytesize = @size = @adding_bytes = @adding_size = 0
47
45
 
@@ -216,7 +214,7 @@ module Fluent
216
214
  count = 0
217
215
  File.open(@path, 'rb') { |f|
218
216
  if chunk_format == :msgpack
219
- msgpack_unpacker(f).each { |d| count += 1 }
217
+ Fluent::MessagePackFactory.msgpack_unpacker(f).each { |d| count += 1 }
220
218
  else
221
219
  f.each_line { |l| count += 1 }
222
220
  end
@@ -14,6 +14,7 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
+ require 'fluent/plugin_helper'
17
18
  require 'fluent/plugin/formatter'
18
19
  require 'csv'
19
20
 
@@ -22,6 +23,9 @@ module Fluent
22
23
  class CsvFormatter < Formatter
23
24
  Plugin.register_formatter('csv', self)
24
25
 
26
+ include PluginHelper::Mixin
27
+ helpers :record_accessor
28
+
25
29
  config_param :delimiter, default: ',' do |val|
26
30
  ['\t', 'TAB'].include?(val) ? "\t" : val
27
31
  end
@@ -37,6 +41,14 @@ module Fluent
37
41
  @fields = fields.select{|f| !f.empty? }
38
42
  raise ConfigError, "empty value is specified in fields parameter" if @fields.empty?
39
43
 
44
+ if @fields.any? { |f| record_accessor_nested?(f) }
45
+ @accessors = @fields.map { |f| record_accessor_create(f) }
46
+ mformat = method(:format_with_nested_fields)
47
+ singleton_class.module_eval do
48
+ define_method(:format, mformat)
49
+ end
50
+ end
51
+
40
52
  @generate_opts = {col_sep: @delimiter, force_quotes: @force_quotes, headers: @fields,
41
53
  row_sep: @add_newline ? :auto : "".force_encoding(Encoding::ASCII_8BIT)}
42
54
  # Cache CSV object per thread to avoid internal state sharing
@@ -44,13 +56,23 @@ module Fluent
44
56
  end
45
57
 
46
58
  def format(tag, time, record)
47
- csv = (@cache[Thread.current] ||= CSV.new("".force_encoding(Encoding::ASCII_8BIT), @generate_opts))
59
+ csv = (@cache[Thread.current] ||= CSV.new("".force_encoding(Encoding::ASCII_8BIT), **@generate_opts))
48
60
  line = (csv << record).string.dup
49
61
  # Need manual cleanup because CSV writer doesn't provide such method.
50
62
  csv.rewind
51
63
  csv.truncate(0)
52
64
  line
53
65
  end
66
+
67
+ def format_with_nested_fields(tag, time, record)
68
+ csv = (@cache[Thread.current] ||= CSV.new("".force_encoding(Encoding::ASCII_8BIT), **@generate_opts))
69
+ values = @accessors.map { |a| a.call(record) }
70
+ line = (csv << values).string.dup
71
+ # Need manual cleanup because CSV writer doesn't provide such method.
72
+ csv.rewind
73
+ csv.truncate(0)
74
+ line
75
+ end
54
76
  end
55
77
  end
56
78
  end