fluentd 1.13.3 → 1.16.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (179) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/{bug_report.yaml → bug_report.yml} +2 -0
  3. data/.github/ISSUE_TEMPLATE/config.yml +2 -2
  4. data/.github/ISSUE_TEMPLATE/{feature_request.yaml → feature_request.yml} +1 -0
  5. data/.github/workflows/stale-actions.yml +11 -9
  6. data/.github/workflows/test.yml +32 -0
  7. data/CHANGELOG.md +490 -10
  8. data/CONTRIBUTING.md +2 -2
  9. data/MAINTAINERS.md +7 -5
  10. data/README.md +3 -23
  11. data/Rakefile +1 -1
  12. data/SECURITY.md +14 -0
  13. data/fluentd.gemspec +7 -8
  14. data/lib/fluent/command/cat.rb +13 -3
  15. data/lib/fluent/command/ctl.rb +6 -3
  16. data/lib/fluent/command/fluentd.rb +73 -65
  17. data/lib/fluent/command/plugin_config_formatter.rb +1 -1
  18. data/lib/fluent/compat/output.rb +9 -6
  19. data/lib/fluent/config/dsl.rb +1 -1
  20. data/lib/fluent/config/error.rb +12 -0
  21. data/lib/fluent/config/literal_parser.rb +2 -2
  22. data/lib/fluent/config/parser.rb +1 -1
  23. data/lib/fluent/config/v1_parser.rb +3 -3
  24. data/lib/fluent/config/yaml_parser/fluent_value.rb +47 -0
  25. data/lib/fluent/config/yaml_parser/loader.rb +108 -0
  26. data/lib/fluent/config/yaml_parser/parser.rb +166 -0
  27. data/lib/fluent/config/yaml_parser/section_builder.rb +107 -0
  28. data/lib/fluent/config/yaml_parser.rb +56 -0
  29. data/lib/fluent/config.rb +14 -1
  30. data/lib/fluent/counter/server.rb +1 -1
  31. data/lib/fluent/counter/validator.rb +3 -3
  32. data/lib/fluent/daemon.rb +2 -4
  33. data/lib/fluent/engine.rb +1 -1
  34. data/lib/fluent/env.rb +4 -0
  35. data/lib/fluent/error.rb +3 -0
  36. data/lib/fluent/event.rb +8 -4
  37. data/lib/fluent/event_router.rb +47 -2
  38. data/lib/fluent/file_wrapper.rb +137 -0
  39. data/lib/fluent/log/console_adapter.rb +66 -0
  40. data/lib/fluent/log.rb +44 -5
  41. data/lib/fluent/match.rb +1 -1
  42. data/lib/fluent/msgpack_factory.rb +6 -1
  43. data/lib/fluent/oj_options.rb +1 -2
  44. data/lib/fluent/plugin/bare_output.rb +49 -8
  45. data/lib/fluent/plugin/base.rb +26 -9
  46. data/lib/fluent/plugin/buf_file.rb +34 -5
  47. data/lib/fluent/plugin/buf_file_single.rb +32 -3
  48. data/lib/fluent/plugin/buffer/file_chunk.rb +1 -1
  49. data/lib/fluent/plugin/buffer.rb +216 -70
  50. data/lib/fluent/plugin/filter.rb +35 -1
  51. data/lib/fluent/plugin/filter_record_transformer.rb +1 -1
  52. data/lib/fluent/plugin/in_forward.rb +2 -2
  53. data/lib/fluent/plugin/in_http.rb +39 -10
  54. data/lib/fluent/plugin/in_monitor_agent.rb +4 -2
  55. data/lib/fluent/plugin/in_sample.rb +1 -1
  56. data/lib/fluent/plugin/in_syslog.rb +13 -1
  57. data/lib/fluent/plugin/in_tail/group_watch.rb +204 -0
  58. data/lib/fluent/plugin/in_tail/position_file.rb +33 -33
  59. data/lib/fluent/plugin/in_tail.rb +216 -84
  60. data/lib/fluent/plugin/in_tcp.rb +47 -2
  61. data/lib/fluent/plugin/input.rb +39 -1
  62. data/lib/fluent/plugin/metrics.rb +119 -0
  63. data/lib/fluent/plugin/metrics_local.rb +96 -0
  64. data/lib/fluent/plugin/multi_output.rb +43 -6
  65. data/lib/fluent/plugin/out_copy.rb +1 -1
  66. data/lib/fluent/plugin/out_exec_filter.rb +2 -2
  67. data/lib/fluent/plugin/out_file.rb +20 -2
  68. data/lib/fluent/plugin/out_forward/ack_handler.rb +19 -4
  69. data/lib/fluent/plugin/out_forward/socket_cache.rb +2 -0
  70. data/lib/fluent/plugin/out_forward.rb +17 -9
  71. data/lib/fluent/plugin/out_secondary_file.rb +39 -22
  72. data/lib/fluent/plugin/output.rb +167 -78
  73. data/lib/fluent/plugin/parser.rb +3 -4
  74. data/lib/fluent/plugin/parser_apache2.rb +1 -1
  75. data/lib/fluent/plugin/parser_json.rb +1 -1
  76. data/lib/fluent/plugin/parser_syslog.rb +1 -1
  77. data/lib/fluent/plugin/storage_local.rb +3 -5
  78. data/lib/fluent/plugin.rb +10 -1
  79. data/lib/fluent/plugin_helper/child_process.rb +3 -0
  80. data/lib/fluent/plugin_helper/event_emitter.rb +8 -1
  81. data/lib/fluent/plugin_helper/event_loop.rb +2 -2
  82. data/lib/fluent/plugin_helper/http_server/server.rb +2 -1
  83. data/lib/fluent/plugin_helper/metrics.rb +129 -0
  84. data/lib/fluent/plugin_helper/record_accessor.rb +1 -1
  85. data/lib/fluent/plugin_helper/retry_state.rb +14 -4
  86. data/lib/fluent/plugin_helper/server.rb +35 -6
  87. data/lib/fluent/plugin_helper/service_discovery.rb +2 -2
  88. data/lib/fluent/plugin_helper/socket.rb +13 -2
  89. data/lib/fluent/plugin_helper/thread.rb +3 -3
  90. data/lib/fluent/plugin_helper.rb +1 -0
  91. data/lib/fluent/plugin_id.rb +3 -2
  92. data/lib/fluent/registry.rb +2 -1
  93. data/lib/fluent/root_agent.rb +6 -0
  94. data/lib/fluent/rpc.rb +4 -3
  95. data/lib/fluent/supervisor.rb +283 -259
  96. data/lib/fluent/system_config.rb +13 -3
  97. data/lib/fluent/test/driver/base.rb +11 -5
  98. data/lib/fluent/test/driver/filter.rb +4 -0
  99. data/lib/fluent/test/startup_shutdown.rb +6 -8
  100. data/lib/fluent/time.rb +21 -20
  101. data/lib/fluent/version.rb +1 -1
  102. data/lib/fluent/win32api.rb +38 -0
  103. data/lib/fluent/winsvc.rb +5 -8
  104. data/templates/new_gem/test/helper.rb.erb +0 -1
  105. data/test/command/test_cat.rb +31 -2
  106. data/test/command/test_ctl.rb +1 -2
  107. data/test/command/test_fluentd.rb +209 -24
  108. data/test/command/test_plugin_config_formatter.rb +0 -1
  109. data/test/compat/test_parser.rb +6 -6
  110. data/test/config/test_system_config.rb +13 -11
  111. data/test/config/test_types.rb +1 -1
  112. data/test/log/test_console_adapter.rb +110 -0
  113. data/test/plugin/in_tail/test_io_handler.rb +26 -8
  114. data/test/plugin/in_tail/test_position_file.rb +48 -59
  115. data/test/plugin/out_forward/test_ack_handler.rb +39 -0
  116. data/test/plugin/out_forward/test_socket_cache.rb +26 -1
  117. data/test/plugin/test_bare_output.rb +14 -1
  118. data/test/plugin/test_base.rb +133 -1
  119. data/test/plugin/test_buf_file.rb +62 -23
  120. data/test/plugin/test_buf_file_single.rb +65 -0
  121. data/test/plugin/test_buffer.rb +267 -3
  122. data/test/plugin/test_buffer_chunk.rb +11 -0
  123. data/test/plugin/test_filter.rb +12 -1
  124. data/test/plugin/test_filter_parser.rb +1 -1
  125. data/test/plugin/test_filter_stdout.rb +2 -2
  126. data/test/plugin/test_in_forward.rb +9 -11
  127. data/test/plugin/test_in_http.rb +65 -3
  128. data/test/plugin/test_in_monitor_agent.rb +216 -11
  129. data/test/plugin/test_in_object_space.rb +9 -3
  130. data/test/plugin/test_in_syslog.rb +35 -0
  131. data/test/plugin/test_in_tail.rb +1393 -385
  132. data/test/plugin/test_in_tcp.rb +87 -2
  133. data/test/plugin/test_in_udp.rb +28 -0
  134. data/test/plugin/test_in_unix.rb +2 -2
  135. data/test/plugin/test_input.rb +12 -1
  136. data/test/plugin/test_metrics.rb +294 -0
  137. data/test/plugin/test_metrics_local.rb +96 -0
  138. data/test/plugin/test_multi_output.rb +25 -1
  139. data/test/plugin/test_out_exec.rb +6 -4
  140. data/test/plugin/test_out_exec_filter.rb +6 -2
  141. data/test/plugin/test_out_file.rb +34 -17
  142. data/test/plugin/test_out_forward.rb +78 -77
  143. data/test/plugin/test_out_http.rb +1 -0
  144. data/test/plugin/test_out_stdout.rb +2 -2
  145. data/test/plugin/test_output.rb +297 -12
  146. data/test/plugin/test_output_as_buffered.rb +44 -44
  147. data/test/plugin/test_output_as_buffered_compress.rb +32 -18
  148. data/test/plugin/test_output_as_buffered_retries.rb +54 -7
  149. data/test/plugin/test_output_as_buffered_secondary.rb +4 -4
  150. data/test/plugin/test_parser_regexp.rb +1 -6
  151. data/test/plugin/test_parser_syslog.rb +1 -1
  152. data/test/plugin_helper/test_cert_option.rb +1 -1
  153. data/test/plugin_helper/test_child_process.rb +38 -16
  154. data/test/plugin_helper/test_event_emitter.rb +29 -0
  155. data/test/plugin_helper/test_http_server_helper.rb +1 -1
  156. data/test/plugin_helper/test_metrics.rb +137 -0
  157. data/test/plugin_helper/test_retry_state.rb +602 -38
  158. data/test/plugin_helper/test_server.rb +78 -6
  159. data/test/plugin_helper/test_timer.rb +2 -2
  160. data/test/test_config.rb +191 -24
  161. data/test/test_event_router.rb +17 -0
  162. data/test/test_file_wrapper.rb +53 -0
  163. data/test/test_formatter.rb +24 -21
  164. data/test/test_log.rb +122 -40
  165. data/test/test_msgpack_factory.rb +32 -0
  166. data/test/test_plugin_classes.rb +102 -0
  167. data/test/test_root_agent.rb +30 -1
  168. data/test/test_supervisor.rb +477 -257
  169. data/test/test_time_parser.rb +22 -0
  170. metadata +55 -34
  171. data/.drone.yml +0 -35
  172. data/.github/workflows/issue-auto-closer.yml +0 -12
  173. data/.github/workflows/linux-test.yaml +0 -36
  174. data/.github/workflows/macos-test.yaml +0 -30
  175. data/.github/workflows/windows-test.yaml +0 -46
  176. data/.gitlab-ci.yml +0 -103
  177. data/lib/fluent/plugin/file_wrapper.rb +0 -187
  178. data/test/plugin/test_file_wrapper.rb +0 -126
  179. data/test/test_logger_initializer.rb +0 -46
@@ -64,31 +64,29 @@ module Fluent::Plugin
64
64
  end
65
65
 
66
66
  def multi_workers_ready?
67
- ### TODO: add hack to synchronize for multi workers
68
67
  true
69
68
  end
70
69
 
71
70
  def write(chunk)
72
71
  path_without_suffix = extract_placeholders(@path_without_suffix, chunk)
73
- path = generate_path(path_without_suffix)
74
- FileUtils.mkdir_p File.dirname(path), mode: @dir_perm
75
-
76
- case @compress
77
- when :text
78
- File.open(path, "ab", @file_perm) {|f|
79
- f.flock(File::LOCK_EX)
80
- chunk.write_to(f)
81
- }
82
- when :gzip
83
- File.open(path, "ab", @file_perm) {|f|
84
- f.flock(File::LOCK_EX)
85
- gz = Zlib::GzipWriter.new(f)
86
- chunk.write_to(gz)
87
- gz.close
88
- }
72
+ generate_path(path_without_suffix) do |path|
73
+ FileUtils.mkdir_p File.dirname(path), mode: @dir_perm
74
+
75
+ case @compress
76
+ when :text
77
+ File.open(path, "ab", @file_perm) {|f|
78
+ f.flock(File::LOCK_EX)
79
+ chunk.write_to(f)
80
+ }
81
+ when :gzip
82
+ File.open(path, "ab", @file_perm) {|f|
83
+ f.flock(File::LOCK_EX)
84
+ gz = Zlib::GzipWriter.new(f)
85
+ chunk.write_to(gz)
86
+ gz.close
87
+ }
88
+ end
89
89
  end
90
-
91
- path
92
90
  end
93
91
 
94
92
  private
@@ -117,15 +115,34 @@ module Fluent::Plugin
117
115
 
118
116
  def generate_path(path_without_suffix)
119
117
  if @append
120
- "#{path_without_suffix}#{@suffix}"
121
- else
118
+ path = "#{path_without_suffix}#{@suffix}"
119
+ synchronize_path(path) do
120
+ yield path
121
+ end
122
+ return path
123
+ end
124
+
125
+ begin
122
126
  i = 0
123
127
  loop do
124
128
  path = "#{path_without_suffix}.#{i}#{@suffix}"
125
- return path unless File.exist?(path)
129
+ break unless File.exist?(path)
126
130
  i += 1
127
131
  end
132
+ synchronize_path(path) do
133
+ # If multiple processes or threads select the same path and another
134
+ # one entered this locking block first, the file should already
135
+ # exist and this one should retry to find new path.
136
+ raise FileAlreadyExist if File.exist?(path)
137
+ yield path
138
+ end
139
+ rescue FileAlreadyExist
140
+ retry
128
141
  end
142
+ path
143
+ end
144
+
145
+ class FileAlreadyExist < StandardError
129
146
  end
130
147
  end
131
148
  end
@@ -14,6 +14,7 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
+ require 'fluent/env'
17
18
  require 'fluent/error'
18
19
  require 'fluent/plugin/base'
19
20
  require 'fluent/plugin/buffer'
@@ -37,7 +38,7 @@ module Fluent
37
38
  include PluginHelper::Mixin
38
39
  include UniqueId::Mixin
39
40
 
40
- helpers_internal :thread, :retry_state
41
+ helpers_internal :thread, :retry_state, :metrics
41
42
 
42
43
  CHUNK_KEY_PATTERN = /^[-_.@a-zA-Z0-9]+$/
43
44
  CHUNK_KEY_PLACEHOLDER_PATTERN = /\$\{([-_.@$a-zA-Z0-9]+)\}/
@@ -98,7 +99,6 @@ module Fluent
98
99
  config_param :retry_max_interval, :time, default: nil, desc: 'The maximum interval seconds for exponential backoff between retries while failing.'
99
100
 
100
101
  config_param :retry_randomize, :bool, default: true, desc: 'If true, output plugin will retry after randomized interval not to do burst retries.'
101
- config_param :disable_chunk_backup, :bool, default: false, desc: 'If true, chunks are thrown away when unrecoverable error happens'
102
102
  end
103
103
 
104
104
  config_section :secondary, param_name: :secondary_config, required: false, multi: false, final: true do
@@ -164,7 +164,6 @@ module Fluent
164
164
  end
165
165
 
166
166
  attr_reader :as_secondary, :delayed_commit, :delayed_commit_timeout, :timekey_zone
167
- attr_reader :num_errors, :emit_count, :emit_records, :write_count, :rollback_count
168
167
 
169
168
  # for tests
170
169
  attr_reader :buffer, :retry, :secondary, :chunk_keys, :chunk_key_accessors, :chunk_key_time, :chunk_key_tag
@@ -172,22 +171,49 @@ module Fluent
172
171
  # output_enqueue_thread_waiting: for test of output.rb itself
173
172
  attr_accessor :retry_for_error_chunk # if true, error flush will be retried even if under_plugin_development is true
174
173
 
174
+ def num_errors
175
+ @num_errors_metrics.get
176
+ end
177
+
178
+ def emit_count
179
+ @emit_count_metrics.get
180
+ end
181
+
182
+ def emit_size
183
+ @emit_size_metrics.get
184
+ end
185
+
186
+ def emit_records
187
+ @emit_records_metrics.get
188
+ end
189
+
190
+ def write_count
191
+ @write_count_metrics.get
192
+ end
193
+
194
+ def rollback_count
195
+ @rollback_count_metrics.get
196
+ end
197
+
175
198
  def initialize
176
199
  super
177
200
  @counter_mutex = Mutex.new
201
+ @flush_thread_mutex = Mutex.new
178
202
  @buffering = false
179
203
  @delayed_commit = false
180
204
  @as_secondary = false
181
205
  @primary_instance = nil
182
206
 
183
207
  # TODO: well organized counters
184
- @num_errors = 0
185
- @emit_count = 0
186
- @emit_records = 0
187
- @write_count = 0
188
- @rollback_count = 0
189
- @flush_time_count = 0
190
- @slow_flush_count = 0
208
+ @num_errors_metrics = nil
209
+ @emit_count_metrics = nil
210
+ @emit_records_metrics = nil
211
+ @emit_size_metrics = nil
212
+ @write_count_metrics = nil
213
+ @rollback_count_metrics = nil
214
+ @flush_time_count_metrics = nil
215
+ @slow_flush_count_metrics = nil
216
+ @enable_size_metrics = false
191
217
 
192
218
  # How to process events is decided here at once, but it will be decided in delayed way on #configure & #start
193
219
  if implement?(:synchronous)
@@ -209,6 +235,7 @@ module Fluent
209
235
  @dequeued_chunks_mutex = nil
210
236
  @output_enqueue_thread = nil
211
237
  @output_flush_threads = nil
238
+ @output_flush_thread_current_position = 0
212
239
 
213
240
  @simple_chunking = nil
214
241
  @chunk_keys = @chunk_key_accessors = @chunk_key_time = @chunk_key_tag = nil
@@ -246,6 +273,15 @@ module Fluent
246
273
 
247
274
  super
248
275
 
276
+ @num_errors_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "num_errors", help_text: "Number of count num errors")
277
+ @emit_count_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "emit_count", help_text: "Number of count emits")
278
+ @emit_records_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "emit_records", help_text: "Number of emit records")
279
+ @emit_size_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "emit_size", help_text: "Total size of emit events")
280
+ @write_count_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "write_count", help_text: "Number of writing events")
281
+ @rollback_count_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "rollback_count", help_text: "Number of rollbacking operations")
282
+ @flush_time_count_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "flush_time_count", help_text: "Count of flush time")
283
+ @slow_flush_count_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "slow_flush_count", help_text: "Count of slow flush occurred time(s)")
284
+
249
285
  if has_buffer_section
250
286
  unless implement?(:buffered) || implement?(:delayed_commit)
251
287
  raise Fluent::ConfigError, "<buffer> section is configured, but plugin '#{self.class}' doesn't support buffering"
@@ -271,6 +307,8 @@ module Fluent
271
307
  @buffering = true
272
308
  end
273
309
  end
310
+ # Enable to update record size metrics or not
311
+ @enable_size_metrics = !!system_config.enable_size_metrics
274
312
 
275
313
  if @as_secondary
276
314
  if !@buffering && !@buffering.nil?
@@ -340,6 +378,7 @@ module Fluent
340
378
  buffer_conf = conf.elements(name: 'buffer').first || Fluent::Config::Element.new('buffer', '', {}, [])
341
379
  @buffer = Plugin.new_buffer(buffer_type, parent: self)
342
380
  @buffer.configure(buffer_conf)
381
+ keep_buffer_config_compat
343
382
  @buffer.enable_update_timekeys if @chunk_key_time
344
383
 
345
384
  @flush_at_shutdown = @buffer_config.flush_at_shutdown
@@ -387,7 +426,9 @@ module Fluent
387
426
  end
388
427
  @secondary.acts_as_secondary(self)
389
428
  @secondary.configure(secondary_conf)
390
- if (self.class != @secondary.class) && (@custom_format || @secondary.implement?(:custom_format))
429
+ if (@secondary.class.to_s != "Fluent::Plugin::SecondaryFileOutput") &&
430
+ (self.class != @secondary.class) &&
431
+ (@custom_format || @secondary.implement?(:custom_format))
391
432
  log.warn "Use different plugin for secondary. Check the plugin works with primary like secondary_file", primary: self.class.to_s, secondary: @secondary.class.to_s
392
433
  end
393
434
  else
@@ -397,6 +438,12 @@ module Fluent
397
438
  self
398
439
  end
399
440
 
441
+ def keep_buffer_config_compat
442
+ # Need this to call `@buffer_config.disable_chunk_backup` just as before,
443
+ # since some plugins may use this option in this way.
444
+ @buffer_config[:disable_chunk_backup] = @buffer.disable_chunk_backup
445
+ end
446
+
400
447
  def start
401
448
  super
402
449
 
@@ -455,6 +502,7 @@ module Fluent
455
502
  @dequeued_chunks = []
456
503
  @dequeued_chunks_mutex = Mutex.new
457
504
 
505
+ @output_flush_thread_current_position = 0
458
506
  @buffer_config.flush_thread_count.times do |i|
459
507
  thread_title = "flush_thread_#{i}".to_sym
460
508
  thread_state = FlushThreadState.new(nil, nil, Mutex.new, ConditionVariable.new)
@@ -466,7 +514,6 @@ module Fluent
466
514
  @output_flush_threads << thread_state
467
515
  end
468
516
  end
469
- @output_flush_thread_current_position = 0
470
517
 
471
518
  if !@under_plugin_development && (@flush_mode == :interval || @chunk_key_time)
472
519
  @output_enqueue_thread = thread_create(:enqueue_thread, &method(:enqueue_thread_run))
@@ -553,6 +600,42 @@ module Fluent
553
600
  super
554
601
  end
555
602
 
603
+ def actual_flush_thread_count
604
+ return 0 unless @buffering
605
+ return @buffer_config.flush_thread_count unless @as_secondary
606
+ @primary_instance.buffer_config.flush_thread_count
607
+ end
608
+
609
+ # Ensures `path` (filename or filepath) processable
610
+ # only by the current thread in the current process.
611
+ # For multiple workers, the lock is shared if `path` is the same value.
612
+ # For multiple threads, the lock is shared by all threads in the same process.
613
+ def synchronize_path(path)
614
+ synchronize_path_in_workers(path) do
615
+ synchronize_in_threads do
616
+ yield
617
+ end
618
+ end
619
+ end
620
+
621
+ def synchronize_path_in_workers(path)
622
+ need_worker_lock = system_config.workers > 1
623
+ if need_worker_lock
624
+ acquire_worker_lock(path) { yield }
625
+ else
626
+ yield
627
+ end
628
+ end
629
+
630
+ def synchronize_in_threads
631
+ need_thread_lock = actual_flush_thread_count > 1
632
+ if need_thread_lock
633
+ @flush_thread_mutex.synchronize { yield }
634
+ else
635
+ yield
636
+ end
637
+ end
638
+
556
639
  def support_in_v12_style?(feature)
557
640
  # for plugins written in v0.12 styles
558
641
  case feature
@@ -741,7 +824,7 @@ module Fluent
741
824
  if str.include?('${tag}')
742
825
  rvalue = rvalue.gsub('${tag}', metadata.tag)
743
826
  end
744
- if str =~ CHUNK_TAG_PLACEHOLDER_PATTERN
827
+ if CHUNK_TAG_PLACEHOLDER_PATTERN.match?(str)
745
828
  hash = {}
746
829
  tag_parts = metadata.tag.split('.')
747
830
  tag_parts.each_with_index do |part, i|
@@ -797,18 +880,19 @@ module Fluent
797
880
  end
798
881
 
799
882
  def emit_sync(tag, es)
800
- @counter_mutex.synchronize{ @emit_count += 1 }
883
+ @emit_count_metrics.inc
801
884
  begin
802
885
  process(tag, es)
803
- @counter_mutex.synchronize{ @emit_records += es.size }
886
+ @emit_records_metrics.add(es.size)
887
+ @emit_size_metrics.add(es.to_msgpack_stream.bytesize) if @enable_size_metrics
804
888
  rescue
805
- @counter_mutex.synchronize{ @num_errors += 1 }
889
+ @num_errors_metrics.inc
806
890
  raise
807
891
  end
808
892
  end
809
893
 
810
894
  def emit_buffered(tag, es)
811
- @counter_mutex.synchronize{ @emit_count += 1 }
895
+ @emit_count_metrics.inc
812
896
  begin
813
897
  execute_chunking(tag, es, enqueue: (@flush_mode == :immediate))
814
898
  if !@retry && @buffer.queued?(nil, optimistic: true)
@@ -816,7 +900,7 @@ module Fluent
816
900
  end
817
901
  rescue
818
902
  # TODO: separate number of errors into emit errors and write/flush errors
819
- @counter_mutex.synchronize{ @num_errors += 1 }
903
+ @num_errors_metrics.inc
820
904
  raise
821
905
  end
822
906
  end
@@ -966,7 +1050,8 @@ module Fluent
966
1050
  write_guard do
967
1051
  @buffer.write(meta_and_data, enqueue: enqueue)
968
1052
  end
969
- @counter_mutex.synchronize{ @emit_records += records }
1053
+ @emit_records_metrics.add(es.size)
1054
+ @emit_size_metrics.add(es.to_msgpack_stream.bytesize) if @enable_size_metrics
970
1055
  true
971
1056
  end
972
1057
 
@@ -983,7 +1068,8 @@ module Fluent
983
1068
  write_guard do
984
1069
  @buffer.write(meta_and_data, format: format_proc, enqueue: enqueue)
985
1070
  end
986
- @counter_mutex.synchronize{ @emit_records += records }
1071
+ @emit_records_metrics.add(es.size)
1072
+ @emit_size_metrics.add(es.to_msgpack_stream.bytesize) if @enable_size_metrics
987
1073
  true
988
1074
  end
989
1075
 
@@ -1008,7 +1094,8 @@ module Fluent
1008
1094
  write_guard do
1009
1095
  @buffer.write({meta => data}, format: format_proc, enqueue: enqueue)
1010
1096
  end
1011
- @counter_mutex.synchronize{ @emit_records += records }
1097
+ @emit_records_metrics.add(es.size)
1098
+ @emit_size_metrics.add(es.to_msgpack_stream.bytesize) if @enable_size_metrics
1012
1099
  true
1013
1100
  end
1014
1101
 
@@ -1046,7 +1133,7 @@ module Fluent
1046
1133
  # false if chunk was already flushed and couldn't be rollbacked unexpectedly
1047
1134
  # in many cases, false can be just ignored
1048
1135
  if @buffer.takeback_chunk(chunk_id)
1049
- @counter_mutex.synchronize{ @rollback_count += 1 }
1136
+ @rollback_count_metrics.inc
1050
1137
  if update_retry
1051
1138
  primary = @as_secondary ? @primary_instance : self
1052
1139
  primary.update_retry_state(chunk_id, @as_secondary)
@@ -1062,7 +1149,7 @@ module Fluent
1062
1149
  while @dequeued_chunks.first && @dequeued_chunks.first.expired?
1063
1150
  info = @dequeued_chunks.shift
1064
1151
  if @buffer.takeback_chunk(info.chunk_id)
1065
- @counter_mutex.synchronize{ @rollback_count += 1 }
1152
+ @rollback_count_metrics.inc
1066
1153
  log.warn "failed to flush the buffer chunk, timeout to commit.", chunk_id: dump_unique_id_hex(info.chunk_id), flushed_at: info.time
1067
1154
  primary = @as_secondary ? @primary_instance : self
1068
1155
  primary.update_retry_state(info.chunk_id, @as_secondary)
@@ -1077,7 +1164,7 @@ module Fluent
1077
1164
  until @dequeued_chunks.empty?
1078
1165
  info = @dequeued_chunks.shift
1079
1166
  if @buffer.takeback_chunk(info.chunk_id)
1080
- @counter_mutex.synchronize{ @rollback_count += 1 }
1167
+ @rollback_count_metrics.inc
1081
1168
  log.info "delayed commit for buffer chunks was cancelled in shutdown", chunk_id: dump_unique_id_hex(info.chunk_id)
1082
1169
  primary = @as_secondary ? @primary_instance : self
1083
1170
  primary.update_retry_state(info.chunk_id, @as_secondary)
@@ -1120,7 +1207,7 @@ module Fluent
1120
1207
 
1121
1208
  if output.delayed_commit
1122
1209
  log.trace "executing delayed write and commit", chunk: dump_unique_id_hex(chunk.unique_id)
1123
- @counter_mutex.synchronize{ @write_count += 1 }
1210
+ @write_count_metrics.inc
1124
1211
  @dequeued_chunks_mutex.synchronize do
1125
1212
  # delayed_commit_timeout for secondary is configured in <buffer> of primary (<secondary> don't get <buffer>)
1126
1213
  @dequeued_chunks << DequeuedChunkInfo.new(chunk.unique_id, Time.now, self.delayed_commit_timeout)
@@ -1132,7 +1219,7 @@ module Fluent
1132
1219
  chunk_id = chunk.unique_id
1133
1220
  dump_chunk_id = dump_unique_id_hex(chunk_id)
1134
1221
  log.trace "adding write count", instance: self.object_id
1135
- @counter_mutex.synchronize{ @write_count += 1 }
1222
+ @write_count_metrics.inc
1136
1223
  log.trace "executing sync write", chunk: dump_chunk_id
1137
1224
 
1138
1225
  output.write(chunk)
@@ -1188,7 +1275,7 @@ module Fluent
1188
1275
  end
1189
1276
 
1190
1277
  if @buffer.takeback_chunk(chunk.unique_id)
1191
- @counter_mutex.synchronize { @rollback_count += 1 }
1278
+ @rollback_count_metrics.inc
1192
1279
  end
1193
1280
 
1194
1281
  update_retry_state(chunk.unique_id, using_secondary, e)
@@ -1198,18 +1285,10 @@ module Fluent
1198
1285
  end
1199
1286
 
1200
1287
  def backup_chunk(chunk, using_secondary, delayed_commit)
1201
- if @buffer_config.disable_chunk_backup
1288
+ if @buffer.disable_chunk_backup
1202
1289
  log.warn "disable_chunk_backup is true. #{dump_unique_id_hex(chunk.unique_id)} chunk is thrown away"
1203
1290
  else
1204
- unique_id = dump_unique_id_hex(chunk.unique_id)
1205
- safe_plugin_id = plugin_id.gsub(/[ "\/\\:;|*<>?]/, '_')
1206
- backup_base_dir = system_config.root_dir || DEFAULT_BACKUP_DIR
1207
- backup_file = File.join(backup_base_dir, 'backup', "worker#{fluentd_worker_id}", safe_plugin_id, "#{unique_id}.log")
1208
- backup_dir = File.dirname(backup_file)
1209
-
1210
- log.warn "bad chunk is moved to #{backup_file}"
1211
- FileUtils.mkdir_p(backup_dir, mode: system_config.dir_permission || 0755) unless Dir.exist?(backup_dir)
1212
- File.open(backup_file, 'ab', system_config.file_permission || 0644) { |f|
1291
+ @buffer.backup(chunk.unique_id) { |f|
1213
1292
  chunk.write_to(f)
1214
1293
  }
1215
1294
  end
@@ -1219,9 +1298,9 @@ module Fluent
1219
1298
  def check_slow_flush(start)
1220
1299
  elapsed_time = Fluent::Clock.now - start
1221
1300
  elapsed_millsec = (elapsed_time * 1000).to_i
1222
- @counter_mutex.synchronize { @flush_time_count += elapsed_millsec }
1301
+ @flush_time_count_metrics.add(elapsed_millsec)
1223
1302
  if elapsed_time > @slow_flush_log_threshold
1224
- @counter_mutex.synchronize { @slow_flush_count += 1 }
1303
+ @slow_flush_count_metrics.inc
1225
1304
  log.warn "buffer flush took longer time than slow_flush_log_threshold:",
1226
1305
  elapsed_time: elapsed_time, slow_flush_log_threshold: @slow_flush_log_threshold, plugin_id: self.plugin_id
1227
1306
  end
@@ -1229,53 +1308,62 @@ module Fluent
1229
1308
 
1230
1309
  def update_retry_state(chunk_id, using_secondary, error = nil)
1231
1310
  @retry_mutex.synchronize do
1232
- @counter_mutex.synchronize{ @num_errors += 1 }
1311
+ @num_errors_metrics.inc
1233
1312
  chunk_id_hex = dump_unique_id_hex(chunk_id)
1234
1313
 
1235
1314
  unless @retry
1236
1315
  @retry = retry_state(@buffer_config.retry_randomize)
1237
- if error
1238
- log.warn "failed to flush the buffer.", retry_time: @retry.steps, next_retry_seconds: @retry.next_time, chunk: chunk_id_hex, error: error
1239
- log.warn_backtrace error.backtrace
1316
+
1317
+ if @retry.limit?
1318
+ handle_limit_reached(error)
1319
+ elsif error
1320
+ log_retry_error(error, chunk_id_hex, using_secondary)
1240
1321
  end
1322
+
1241
1323
  return
1242
1324
  end
1243
1325
 
1244
1326
  # @retry exists
1245
1327
 
1246
- if @retry.limit?
1247
- if error
1248
- records = @buffer.queued_records
1249
- msg = "failed to flush the buffer, and hit limit for retries. dropping all chunks in the buffer queue."
1250
- log.error msg, retry_times: @retry.steps, records: records, error: error
1251
- log.error_backtrace error.backtrace
1252
- end
1253
- @buffer.clear_queue!
1254
- log.debug "buffer queue cleared"
1255
- @retry = nil
1328
+ # Ensure that the current time is greater than or equal to @retry.next_time to avoid the situation when
1329
+ # @retry.step is called almost as many times as the number of flush threads in a short time.
1330
+ if Time.now >= @retry.next_time
1331
+ @retry.step
1256
1332
  else
1257
- # Ensure that the current time is greater than or equal to @retry.next_time to avoid the situation when
1258
- # @retry.step is called almost as many times as the number of flush threads in a short time.
1259
- if Time.now >= @retry.next_time
1260
- @retry.step
1261
- else
1262
- @retry.recalc_next_time # to prevent all flush threads from retrying at the same time
1263
- end
1264
- if error
1265
- if using_secondary
1266
- msg = "failed to flush the buffer with secondary output."
1267
- log.warn msg, retry_time: @retry.steps, next_retry_seconds: @retry.next_time, chunk: chunk_id_hex, error: error
1268
- log.warn_backtrace error.backtrace
1269
- else
1270
- msg = "failed to flush the buffer."
1271
- log.warn msg, retry_time: @retry.steps, next_retry_seconds: @retry.next_time, chunk: chunk_id_hex, error: error
1272
- log.warn_backtrace error.backtrace
1273
- end
1274
- end
1333
+ @retry.recalc_next_time # to prevent all flush threads from retrying at the same time
1334
+ end
1335
+
1336
+ if @retry.limit?
1337
+ handle_limit_reached(error)
1338
+ elsif error
1339
+ log_retry_error(error, chunk_id_hex, using_secondary)
1275
1340
  end
1276
1341
  end
1277
1342
  end
1278
1343
 
1344
+ def log_retry_error(error, chunk_id_hex, using_secondary)
1345
+ return unless error
1346
+ if using_secondary
1347
+ msg = "failed to flush the buffer with secondary output."
1348
+ else
1349
+ msg = "failed to flush the buffer."
1350
+ end
1351
+ log.warn(msg, retry_times: @retry.steps, next_retry_time: @retry.next_time.round, chunk: chunk_id_hex, error: error)
1352
+ log.warn_backtrace(error.backtrace)
1353
+ end
1354
+
1355
+ def handle_limit_reached(error)
1356
+ if error
1357
+ records = @buffer.queued_records
1358
+ msg = "Hit limit for retries. dropping all chunks in the buffer queue."
1359
+ log.error msg, retry_times: @retry.steps, records: records, error: error
1360
+ log.error_backtrace error.backtrace
1361
+ end
1362
+ @buffer.clear_queue!
1363
+ log.debug "buffer queue cleared"
1364
+ @retry = nil
1365
+ end
1366
+
1279
1367
  def retry_state(randomize)
1280
1368
  if @secondary
1281
1369
  retry_state_create(
@@ -1490,15 +1578,16 @@ module Fluent
1490
1578
 
1491
1579
  def statistics
1492
1580
  stats = {
1493
- 'emit_records' => @emit_records,
1581
+ 'emit_records' => @emit_records_metrics.get,
1582
+ 'emit_size' => @emit_size_metrics.get,
1494
1583
  # Respect original name
1495
1584
  # https://github.com/fluent/fluentd/blob/45c7b75ba77763eaf87136864d4942c4e0c5bfcd/lib/fluent/plugin/in_monitor_agent.rb#L284
1496
- 'retry_count' => @num_errors,
1497
- 'emit_count' => @emit_count,
1498
- 'write_count' => @write_count,
1499
- 'rollback_count' => @rollback_count,
1500
- 'slow_flush_count' => @slow_flush_count,
1501
- 'flush_time_count' => @flush_time_count,
1585
+ 'retry_count' => @num_errors_metrics.get,
1586
+ 'emit_count' => @emit_count_metrics.get,
1587
+ 'write_count' => @write_count_metrics.get,
1588
+ 'rollback_count' => @rollback_count_metrics.get,
1589
+ 'slow_flush_count' => @slow_flush_count_metrics.get,
1590
+ 'flush_time_count' => @flush_time_count_metrics.get,
1502
1591
  }
1503
1592
 
1504
1593
  if @buffer && @buffer.respond_to?(:statistics)
@@ -89,7 +89,7 @@ module Fluent
89
89
  # : format[, timezone]
90
90
 
91
91
  config_param :time_key, :string, default: nil
92
- config_param :null_value_pattern, :string, default: nil
92
+ config_param :null_value_pattern, :regexp, default: nil
93
93
  config_param :null_empty_string, :bool, default: false
94
94
  config_param :estimate_current_event, :bool, default: true
95
95
  config_param :keep_time_key, :bool, default: false
@@ -115,9 +115,8 @@ module Fluent
115
115
  super
116
116
 
117
117
  @time_parser = time_parser_create
118
- @null_value_regexp = @null_value_pattern && Regexp.new(@null_value_pattern)
119
118
  @type_converters = build_type_converters(@types)
120
- @execute_convert_values = @type_converters || @null_value_regexp || @null_empty_string
119
+ @execute_convert_values = @type_converters || @null_value_pattern || @null_empty_string
121
120
  @timeout_checker = if @timeout
122
121
  class << self
123
122
  alias_method :parse_orig, :parse
@@ -220,7 +219,7 @@ module Fluent
220
219
  return time, record
221
220
  end
222
221
 
223
- def string_like_null(value, null_empty_string = @null_empty_string, null_value_regexp = @null_value_regexp)
222
+ def string_like_null(value, null_empty_string = @null_empty_string, null_value_regexp = @null_value_pattern)
224
223
  null_empty_string && value.empty? || null_value_regexp && string_safe_encoding(value){|s| null_value_regexp.match(s) }
225
224
  end
226
225
 
@@ -21,7 +21,7 @@ module Fluent
21
21
  class Apache2Parser < Parser
22
22
  Plugin.register_parser('apache2', self)
23
23
 
24
- REGEXP = /^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>(?:[^\"]|\\.)*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>(?:[^\"]|\\.)*)" "(?<agent>(?:[^\"]|\\.)*)")?$/
24
+ REGEXP = /^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>(?:[^\"]|\\")*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>(?:[^\"]|\\")*)" "(?<agent>(?:[^\"]|\\")*)")?$/
25
25
  TIME_FORMAT = "%d/%b/%Y:%H:%M:%S %z"
26
26
 
27
27
  def initialize
@@ -60,7 +60,7 @@ module Fluent
60
60
  rescue LoadError => ex
61
61
  name = :yajl
62
62
  if log
63
- if /\boj\z/ =~ ex.message
63
+ if /\boj\z/.match?(ex.message)
64
64
  log.info "Oj is not installed, and failing back to Yajl for json parser"
65
65
  else
66
66
  log.warn ex.message
@@ -484,7 +484,7 @@ module Fluent
484
484
 
485
485
  time = begin
486
486
  @time_parser_rfc5424.parse(time_str)
487
- rescue Fluent::TimeParser::TimeParseError => e
487
+ rescue Fluent::TimeParser::TimeParseError
488
488
  @time_parser_rfc5424_without_subseconds.parse(time_str)
489
489
  end
490
490
  record['time'] = time_str if @keep_time_key
@@ -14,6 +14,7 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
+ require 'fluent/env'
17
18
  require 'fluent/plugin'
18
19
  require 'fluent/plugin/storage'
19
20
 
@@ -25,14 +26,11 @@ module Fluent
25
26
  class LocalStorage < Storage
26
27
  Fluent::Plugin.register_storage('local', self)
27
28
 
28
- DEFAULT_DIR_MODE = 0755
29
- DEFAULT_FILE_MODE = 0644
30
-
31
29
  config_param :path, :string, default: nil
32
- config_param :mode, default: DEFAULT_FILE_MODE do |v|
30
+ config_param :mode, default: Fluent::DEFAULT_FILE_PERMISSION do |v|
33
31
  v.to_i(8)
34
32
  end
35
- config_param :dir_mode, default: DEFAULT_DIR_MODE do |v|
33
+ config_param :dir_mode, default: Fluent::DEFAULT_DIR_PERMISSION do |v|
36
34
  v.to_i(8)
37
35
  end
38
36
  config_param :pretty_print, :bool, default: false