fluentd 1.13.3 → 1.16.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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