fluentd 1.16.5-x86-mingw32 → 1.17.1-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (268) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +88 -0
  3. data/README.md +2 -1
  4. data/Rakefile +1 -1
  5. data/SECURITY.md +2 -2
  6. data/fluent.conf +14 -14
  7. data/lib/fluent/command/binlog_reader.rb +1 -1
  8. data/lib/fluent/command/cap_ctl.rb +4 -4
  9. data/lib/fluent/compat/call_super_mixin.rb +3 -3
  10. data/lib/fluent/compat/propagate_default.rb +4 -4
  11. data/lib/fluent/config/configure_proxy.rb +2 -2
  12. data/lib/fluent/config/types.rb +1 -1
  13. data/lib/fluent/config/yaml_parser/parser.rb +4 -0
  14. data/lib/fluent/configurable.rb +2 -2
  15. data/lib/fluent/counter/mutex_hash.rb +1 -1
  16. data/lib/fluent/fluent_log_event_router.rb +0 -2
  17. data/lib/fluent/log/console_adapter.rb +4 -2
  18. data/lib/fluent/plugin/buf_file.rb +1 -1
  19. data/lib/fluent/plugin/buffer/file_chunk.rb +1 -1
  20. data/lib/fluent/plugin/buffer/file_single_chunk.rb +2 -3
  21. data/lib/fluent/plugin/filter_parser.rb +26 -8
  22. data/lib/fluent/plugin/in_exec.rb +14 -2
  23. data/lib/fluent/plugin/in_http.rb +19 -54
  24. data/lib/fluent/plugin/in_sample.rb +13 -7
  25. data/lib/fluent/plugin/in_tail.rb +99 -25
  26. data/lib/fluent/plugin/out_copy.rb +1 -1
  27. data/lib/fluent/plugin/out_file.rb +8 -0
  28. data/lib/fluent/plugin/out_http.rb +137 -13
  29. data/lib/fluent/plugin/owned_by_mixin.rb +0 -1
  30. data/lib/fluent/plugin/parser_json.rb +26 -17
  31. data/lib/fluent/plugin/parser_msgpack.rb +24 -3
  32. data/lib/fluent/plugin_helper/http_server/server.rb +1 -1
  33. data/lib/fluent/plugin_helper/metrics.rb +2 -2
  34. data/lib/fluent/registry.rb +6 -6
  35. data/lib/fluent/test/output_test.rb +1 -1
  36. data/lib/fluent/unique_id.rb +1 -1
  37. data/lib/fluent/version.rb +1 -1
  38. data/templates/new_gem/fluent-plugin.gemspec.erb +6 -5
  39. metadata +109 -459
  40. data/.github/ISSUE_TEMPLATE/bug_report.yml +0 -71
  41. data/.github/ISSUE_TEMPLATE/config.yml +0 -5
  42. data/.github/ISSUE_TEMPLATE/feature_request.yml +0 -39
  43. data/.github/ISSUE_TEMPLATE.md +0 -17
  44. data/.github/PULL_REQUEST_TEMPLATE.md +0 -14
  45. data/.github/workflows/stale-actions.yml +0 -24
  46. data/.github/workflows/test.yml +0 -32
  47. data/.gitignore +0 -30
  48. data/Gemfile +0 -9
  49. data/fluentd.gemspec +0 -54
  50. data/test/command/test_binlog_reader.rb +0 -362
  51. data/test/command/test_ca_generate.rb +0 -70
  52. data/test/command/test_cap_ctl.rb +0 -100
  53. data/test/command/test_cat.rb +0 -128
  54. data/test/command/test_ctl.rb +0 -56
  55. data/test/command/test_fluentd.rb +0 -1291
  56. data/test/command/test_plugin_config_formatter.rb +0 -397
  57. data/test/command/test_plugin_generator.rb +0 -109
  58. data/test/compat/test_calls_super.rb +0 -166
  59. data/test/compat/test_parser.rb +0 -92
  60. data/test/config/assertions.rb +0 -42
  61. data/test/config/test_config_parser.rb +0 -551
  62. data/test/config/test_configurable.rb +0 -1784
  63. data/test/config/test_configure_proxy.rb +0 -604
  64. data/test/config/test_dsl.rb +0 -415
  65. data/test/config/test_element.rb +0 -518
  66. data/test/config/test_literal_parser.rb +0 -309
  67. data/test/config/test_plugin_configuration.rb +0 -56
  68. data/test/config/test_section.rb +0 -191
  69. data/test/config/test_system_config.rb +0 -195
  70. data/test/config/test_types.rb +0 -408
  71. data/test/counter/test_client.rb +0 -563
  72. data/test/counter/test_error.rb +0 -44
  73. data/test/counter/test_mutex_hash.rb +0 -179
  74. data/test/counter/test_server.rb +0 -589
  75. data/test/counter/test_store.rb +0 -258
  76. data/test/counter/test_validator.rb +0 -137
  77. data/test/helper.rb +0 -155
  78. data/test/helpers/fuzzy_assert.rb +0 -89
  79. data/test/helpers/process_extenstion.rb +0 -33
  80. data/test/log/test_console_adapter.rb +0 -110
  81. data/test/plugin/data/2010/01/20100102-030405.log +0 -0
  82. data/test/plugin/data/2010/01/20100102-030406.log +0 -0
  83. data/test/plugin/data/2010/01/20100102.log +0 -0
  84. data/test/plugin/data/log/bar +0 -0
  85. data/test/plugin/data/log/foo/bar.log +0 -0
  86. data/test/plugin/data/log/foo/bar2 +0 -0
  87. data/test/plugin/data/log/test.log +0 -0
  88. data/test/plugin/data/sd_file/config +0 -11
  89. data/test/plugin/data/sd_file/config.json +0 -17
  90. data/test/plugin/data/sd_file/config.yaml +0 -11
  91. data/test/plugin/data/sd_file/config.yml +0 -11
  92. data/test/plugin/data/sd_file/invalid_config.yml +0 -7
  93. data/test/plugin/in_tail/test_fifo.rb +0 -121
  94. data/test/plugin/in_tail/test_io_handler.rb +0 -150
  95. data/test/plugin/in_tail/test_position_file.rb +0 -346
  96. data/test/plugin/out_forward/test_ack_handler.rb +0 -140
  97. data/test/plugin/out_forward/test_connection_manager.rb +0 -145
  98. data/test/plugin/out_forward/test_handshake_protocol.rb +0 -112
  99. data/test/plugin/out_forward/test_load_balancer.rb +0 -106
  100. data/test/plugin/out_forward/test_socket_cache.rb +0 -174
  101. data/test/plugin/test_bare_output.rb +0 -131
  102. data/test/plugin/test_base.rb +0 -247
  103. data/test/plugin/test_buf_file.rb +0 -1314
  104. data/test/plugin/test_buf_file_single.rb +0 -898
  105. data/test/plugin/test_buf_memory.rb +0 -42
  106. data/test/plugin/test_buffer.rb +0 -1493
  107. data/test/plugin/test_buffer_chunk.rb +0 -209
  108. data/test/plugin/test_buffer_file_chunk.rb +0 -871
  109. data/test/plugin/test_buffer_file_single_chunk.rb +0 -611
  110. data/test/plugin/test_buffer_memory_chunk.rb +0 -339
  111. data/test/plugin/test_compressable.rb +0 -87
  112. data/test/plugin/test_file_util.rb +0 -96
  113. data/test/plugin/test_filter.rb +0 -368
  114. data/test/plugin/test_filter_grep.rb +0 -697
  115. data/test/plugin/test_filter_parser.rb +0 -731
  116. data/test/plugin/test_filter_record_transformer.rb +0 -577
  117. data/test/plugin/test_filter_stdout.rb +0 -207
  118. data/test/plugin/test_formatter_csv.rb +0 -136
  119. data/test/plugin/test_formatter_hash.rb +0 -38
  120. data/test/plugin/test_formatter_json.rb +0 -61
  121. data/test/plugin/test_formatter_ltsv.rb +0 -70
  122. data/test/plugin/test_formatter_msgpack.rb +0 -28
  123. data/test/plugin/test_formatter_out_file.rb +0 -116
  124. data/test/plugin/test_formatter_single_value.rb +0 -44
  125. data/test/plugin/test_formatter_tsv.rb +0 -76
  126. data/test/plugin/test_in_debug_agent.rb +0 -49
  127. data/test/plugin/test_in_exec.rb +0 -261
  128. data/test/plugin/test_in_forward.rb +0 -1178
  129. data/test/plugin/test_in_gc_stat.rb +0 -62
  130. data/test/plugin/test_in_http.rb +0 -1102
  131. data/test/plugin/test_in_monitor_agent.rb +0 -922
  132. data/test/plugin/test_in_object_space.rb +0 -66
  133. data/test/plugin/test_in_sample.rb +0 -190
  134. data/test/plugin/test_in_syslog.rb +0 -505
  135. data/test/plugin/test_in_tail.rb +0 -3288
  136. data/test/plugin/test_in_tcp.rb +0 -328
  137. data/test/plugin/test_in_udp.rb +0 -296
  138. data/test/plugin/test_in_unix.rb +0 -181
  139. data/test/plugin/test_input.rb +0 -137
  140. data/test/plugin/test_metadata.rb +0 -89
  141. data/test/plugin/test_metrics.rb +0 -294
  142. data/test/plugin/test_metrics_local.rb +0 -96
  143. data/test/plugin/test_multi_output.rb +0 -204
  144. data/test/plugin/test_out_copy.rb +0 -308
  145. data/test/plugin/test_out_exec.rb +0 -312
  146. data/test/plugin/test_out_exec_filter.rb +0 -606
  147. data/test/plugin/test_out_file.rb +0 -1038
  148. data/test/plugin/test_out_forward.rb +0 -1349
  149. data/test/plugin/test_out_http.rb +0 -429
  150. data/test/plugin/test_out_null.rb +0 -105
  151. data/test/plugin/test_out_relabel.rb +0 -28
  152. data/test/plugin/test_out_roundrobin.rb +0 -146
  153. data/test/plugin/test_out_secondary_file.rb +0 -458
  154. data/test/plugin/test_out_stdout.rb +0 -205
  155. data/test/plugin/test_out_stream.rb +0 -103
  156. data/test/plugin/test_output.rb +0 -1334
  157. data/test/plugin/test_output_as_buffered.rb +0 -2024
  158. data/test/plugin/test_output_as_buffered_backup.rb +0 -363
  159. data/test/plugin/test_output_as_buffered_compress.rb +0 -179
  160. data/test/plugin/test_output_as_buffered_overflow.rb +0 -250
  161. data/test/plugin/test_output_as_buffered_retries.rb +0 -966
  162. data/test/plugin/test_output_as_buffered_secondary.rb +0 -882
  163. data/test/plugin/test_output_as_standard.rb +0 -374
  164. data/test/plugin/test_owned_by.rb +0 -35
  165. data/test/plugin/test_parser.rb +0 -399
  166. data/test/plugin/test_parser_apache.rb +0 -42
  167. data/test/plugin/test_parser_apache2.rb +0 -47
  168. data/test/plugin/test_parser_apache_error.rb +0 -45
  169. data/test/plugin/test_parser_csv.rb +0 -200
  170. data/test/plugin/test_parser_json.rb +0 -138
  171. data/test/plugin/test_parser_labeled_tsv.rb +0 -160
  172. data/test/plugin/test_parser_multiline.rb +0 -111
  173. data/test/plugin/test_parser_nginx.rb +0 -88
  174. data/test/plugin/test_parser_none.rb +0 -52
  175. data/test/plugin/test_parser_regexp.rb +0 -284
  176. data/test/plugin/test_parser_syslog.rb +0 -650
  177. data/test/plugin/test_parser_tsv.rb +0 -122
  178. data/test/plugin/test_sd_file.rb +0 -228
  179. data/test/plugin/test_sd_srv.rb +0 -230
  180. data/test/plugin/test_storage.rb +0 -167
  181. data/test/plugin/test_storage_local.rb +0 -335
  182. data/test/plugin/test_string_util.rb +0 -26
  183. data/test/plugin_helper/data/cert/cert-key.pem +0 -27
  184. data/test/plugin_helper/data/cert/cert-with-CRLF.pem +0 -19
  185. data/test/plugin_helper/data/cert/cert-with-no-newline.pem +0 -19
  186. data/test/plugin_helper/data/cert/cert.pem +0 -19
  187. data/test/plugin_helper/data/cert/cert_chains/ca-cert-key.pem +0 -27
  188. data/test/plugin_helper/data/cert/cert_chains/ca-cert.pem +0 -20
  189. data/test/plugin_helper/data/cert/cert_chains/cert-key.pem +0 -27
  190. data/test/plugin_helper/data/cert/cert_chains/cert.pem +0 -40
  191. data/test/plugin_helper/data/cert/empty.pem +0 -0
  192. data/test/plugin_helper/data/cert/generate_cert.rb +0 -125
  193. data/test/plugin_helper/data/cert/with_ca/ca-cert-key-pass.pem +0 -30
  194. data/test/plugin_helper/data/cert/with_ca/ca-cert-key.pem +0 -27
  195. data/test/plugin_helper/data/cert/with_ca/ca-cert-pass.pem +0 -20
  196. data/test/plugin_helper/data/cert/with_ca/ca-cert.pem +0 -20
  197. data/test/plugin_helper/data/cert/with_ca/cert-key-pass.pem +0 -30
  198. data/test/plugin_helper/data/cert/with_ca/cert-key.pem +0 -27
  199. data/test/plugin_helper/data/cert/with_ca/cert-pass.pem +0 -21
  200. data/test/plugin_helper/data/cert/with_ca/cert.pem +0 -21
  201. data/test/plugin_helper/data/cert/without_ca/cert-key-pass.pem +0 -30
  202. data/test/plugin_helper/data/cert/without_ca/cert-key.pem +0 -27
  203. data/test/plugin_helper/data/cert/without_ca/cert-pass.pem +0 -20
  204. data/test/plugin_helper/data/cert/without_ca/cert.pem +0 -20
  205. data/test/plugin_helper/http_server/test_app.rb +0 -65
  206. data/test/plugin_helper/http_server/test_route.rb +0 -32
  207. data/test/plugin_helper/service_discovery/test_manager.rb +0 -93
  208. data/test/plugin_helper/service_discovery/test_round_robin_balancer.rb +0 -21
  209. data/test/plugin_helper/test_cert_option.rb +0 -25
  210. data/test/plugin_helper/test_child_process.rb +0 -862
  211. data/test/plugin_helper/test_compat_parameters.rb +0 -358
  212. data/test/plugin_helper/test_event_emitter.rb +0 -80
  213. data/test/plugin_helper/test_event_loop.rb +0 -52
  214. data/test/plugin_helper/test_extract.rb +0 -194
  215. data/test/plugin_helper/test_formatter.rb +0 -255
  216. data/test/plugin_helper/test_http_server_helper.rb +0 -372
  217. data/test/plugin_helper/test_inject.rb +0 -561
  218. data/test/plugin_helper/test_metrics.rb +0 -137
  219. data/test/plugin_helper/test_parser.rb +0 -264
  220. data/test/plugin_helper/test_record_accessor.rb +0 -238
  221. data/test/plugin_helper/test_retry_state.rb +0 -1006
  222. data/test/plugin_helper/test_server.rb +0 -1895
  223. data/test/plugin_helper/test_service_discovery.rb +0 -165
  224. data/test/plugin_helper/test_socket.rb +0 -146
  225. data/test/plugin_helper/test_storage.rb +0 -542
  226. data/test/plugin_helper/test_thread.rb +0 -164
  227. data/test/plugin_helper/test_timer.rb +0 -130
  228. data/test/scripts/exec_script.rb +0 -32
  229. data/test/scripts/fluent/plugin/formatter1/formatter_test1.rb +0 -7
  230. data/test/scripts/fluent/plugin/formatter2/formatter_test2.rb +0 -7
  231. data/test/scripts/fluent/plugin/formatter_known.rb +0 -8
  232. data/test/scripts/fluent/plugin/out_test.rb +0 -81
  233. data/test/scripts/fluent/plugin/out_test2.rb +0 -80
  234. data/test/scripts/fluent/plugin/parser_known.rb +0 -4
  235. data/test/test_capability.rb +0 -74
  236. data/test/test_clock.rb +0 -164
  237. data/test/test_config.rb +0 -369
  238. data/test/test_configdsl.rb +0 -148
  239. data/test/test_daemonizer.rb +0 -91
  240. data/test/test_engine.rb +0 -203
  241. data/test/test_event.rb +0 -531
  242. data/test/test_event_router.rb +0 -348
  243. data/test/test_event_time.rb +0 -199
  244. data/test/test_file_wrapper.rb +0 -53
  245. data/test/test_filter.rb +0 -121
  246. data/test/test_fluent_log_event_router.rb +0 -99
  247. data/test/test_formatter.rb +0 -369
  248. data/test/test_input.rb +0 -31
  249. data/test/test_log.rb +0 -1076
  250. data/test/test_match.rb +0 -148
  251. data/test/test_mixin.rb +0 -351
  252. data/test/test_msgpack_factory.rb +0 -50
  253. data/test/test_oj_options.rb +0 -55
  254. data/test/test_output.rb +0 -278
  255. data/test/test_plugin.rb +0 -251
  256. data/test/test_plugin_classes.rb +0 -370
  257. data/test/test_plugin_helper.rb +0 -81
  258. data/test/test_plugin_id.rb +0 -119
  259. data/test/test_process.rb +0 -14
  260. data/test/test_root_agent.rb +0 -951
  261. data/test/test_static_config_analysis.rb +0 -177
  262. data/test/test_supervisor.rb +0 -821
  263. data/test/test_test_drivers.rb +0 -136
  264. data/test/test_time_formatter.rb +0 -301
  265. data/test/test_time_parser.rb +0 -362
  266. data/test/test_tls.rb +0 -65
  267. data/test/test_unique_id.rb +0 -47
  268. data/test/test_variable_store.rb +0 -65
@@ -39,6 +39,8 @@ module Fluent::Plugin
39
39
  config_param :auto_increment_key, :string, default: nil
40
40
  desc "The boolean to suspend-and-resume incremental value after restart"
41
41
  config_param :suspend, :bool, default: false,deprecated: 'This parameters is ignored'
42
+ desc "Reuse the sample data to reduce the load when sending large amounts of data. You can enable it if filter does not do destructive change"
43
+ config_param :reuse_record, :bool, default: false
42
44
  desc "The sample data to be generated. An array of JSON hashes or a single JSON hash."
43
45
  config_param :sample, alias: :dummy, default: [{"message" => "sample"}] do |val|
44
46
  begin
@@ -117,15 +119,19 @@ module Fluent::Plugin
117
119
  end
118
120
  end
119
121
 
120
- def generate
121
- d = @sample[@sample_index]
122
- unless d
123
- @sample_index = 0
124
- d = @sample[@sample_index]
125
- end
122
+ def next_sample
123
+ d = @reuse_record ? @sample[@sample_index] : @sample[@sample_index].dup
126
124
  @sample_index += 1
125
+ return d if d
126
+
127
+ @sample_index = 0
128
+ next_sample
129
+ end
130
+
131
+ def generate
132
+ d = next_sample
127
133
  if @auto_increment_key
128
- d = d.dup
134
+ d = d.dup if @reuse_record
129
135
  d[@auto_increment_key] = @storage.update(:auto_increment_value){|v| v + 1 }
130
136
  end
131
137
  d
@@ -36,7 +36,7 @@ module Fluent::Plugin
36
36
  helpers :timer, :event_loop, :parser, :compat_parameters
37
37
 
38
38
  RESERVED_CHARS = ['/', '*', '%'].freeze
39
- MetricsInfo = Struct.new(:opened, :closed, :rotated)
39
+ MetricsInfo = Struct.new(:opened, :closed, :rotated, :throttled)
40
40
 
41
41
  class WatcherSetupError < StandardError
42
42
  def initialize(msg)
@@ -65,6 +65,8 @@ module Fluent::Plugin
65
65
  config_param :path, :string
66
66
  desc 'path delimiter used for spliting path config'
67
67
  config_param :path_delimiter, :string, default: ','
68
+ desc 'Choose using glob patterns. Adding capabilities to handle [] and ?, and {}.'
69
+ config_param :glob_policy, :enum, list: [:backward_compatible, :extended, :always], default: :backward_compatible
68
70
  desc 'The tag of the event.'
69
71
  config_param :tag, :string
70
72
  desc 'The paths to exclude the files from watcher list.'
@@ -141,6 +143,14 @@ module Fluent::Plugin
141
143
  raise Fluent::ConfigError, "either of enable_watch_timer or enable_stat_watcher must be true"
142
144
  end
143
145
 
146
+ if @glob_policy == :always && @path_delimiter == ','
147
+ raise Fluent::ConfigError, "cannot use glob_policy as always with the default path_delimitor: `,\""
148
+ end
149
+
150
+ if @glob_policy == :extended && /\{.*,.*\}/.match(@path) && extended_glob_pattern(@path)
151
+ raise Fluent::ConfigError, "cannot include curly braces with glob patterns in `#{@path}\". Use glob_policy always instead."
152
+ end
153
+
144
154
  if RESERVED_CHARS.include?(@path_delimiter)
145
155
  rc = RESERVED_CHARS.join(', ')
146
156
  raise Fluent::ConfigError, "#{rc} are reserved words: #{@path_delimiter}"
@@ -198,7 +208,8 @@ module Fluent::Plugin
198
208
  opened_file_metrics = metrics_create(namespace: "fluentd", subsystem: "input", name: "files_opened_total", help_text: "Total number of opened files")
199
209
  closed_file_metrics = metrics_create(namespace: "fluentd", subsystem: "input", name: "files_closed_total", help_text: "Total number of closed files")
200
210
  rotated_file_metrics = metrics_create(namespace: "fluentd", subsystem: "input", name: "files_rotated_total", help_text: "Total number of rotated files")
201
- @metrics = MetricsInfo.new(opened_file_metrics, closed_file_metrics, rotated_file_metrics)
211
+ throttling_metrics = metrics_create(namespace: "fluentd", subsystem: "input", name: "files_throttled_total", help_text: "Total number of times throttling occurs per file when throttling enabled")
212
+ @metrics = MetricsInfo.new(opened_file_metrics, closed_file_metrics, rotated_file_metrics, throttling_metrics)
202
213
  end
203
214
 
204
215
  def configure_tag
@@ -288,6 +299,28 @@ module Fluent::Plugin
288
299
  @capability.have_capability?(:effective, :dac_override)
289
300
  end
290
301
 
302
+ def extended_glob_pattern(path)
303
+ path.include?('*') || path.include?('?') || /\[.*\]/.match(path)
304
+ end
305
+
306
+ # Curly braces is not supported with default path_delimiter
307
+ # because the default delimiter of path is ",".
308
+ # This should be collided for wildcard pattern for curly braces and
309
+ # be handled as an error on #configure.
310
+ def use_glob?(path)
311
+ if @glob_policy == :always
312
+ # For future extensions, we decided to use `always' term to handle
313
+ # regular expressions as much as possible.
314
+ # This is because not using `true' as a returning value
315
+ # when choosing :always here.
316
+ extended_glob_pattern(path) || /\{.*,.*\}/.match(path)
317
+ elsif @glob_policy == :extended
318
+ extended_glob_pattern(path)
319
+ elsif @glob_policy == :backward_compatible
320
+ path.include?('*')
321
+ end
322
+ end
323
+
291
324
  def expand_paths
292
325
  date = Fluent::EventTime.now
293
326
  paths = []
@@ -297,7 +330,7 @@ module Fluent::Plugin
297
330
  else
298
331
  date.to_time.strftime(path)
299
332
  end
300
- if path.include?('*')
333
+ if use_glob?(path)
301
334
  paths += Dir.glob(path).select { |p|
302
335
  begin
303
336
  is_file = !File.directory?(p)
@@ -332,7 +365,7 @@ module Fluent::Plugin
332
365
  else
333
366
  date.to_time.strftime(path)
334
367
  end
335
- path.include?('*') ? Dir.glob(path) : path
368
+ use_glob?(path) ? Dir.glob(path) : path
336
369
  }.flatten.uniq
337
370
  # filter out non existing files, so in case pattern is without '*' we don't do unnecessary work
338
371
  hash = {}
@@ -534,7 +567,7 @@ module Fluent::Plugin
534
567
  if @follow_inodes && new_inode.nil?
535
568
  # nil inode means the file disappeared, so we only need to stop it.
536
569
  @tails.delete(tail_watcher.path)
537
- # https://github.com/fluent/fluentd/pull/4237#issuecomment-1633358632
570
+ # https://github.com/fluent/fluentd/pull/4237#issuecomment-1633358632
538
571
  # Because of this problem, log duplication can occur during `rotate_wait`.
539
572
  # Need to set `rotate_wait 0` for a workaround.
540
573
  # Duplication will occur if `refresh_watcher` is called during the `rotate_wait`.
@@ -664,14 +697,6 @@ module Fluent::Plugin
664
697
 
665
698
  # @return true if no error or unrecoverable error happens in emit action. false if got BufferOverflowError
666
699
  def receive_lines(lines, tail_watcher)
667
- lines = lines.reject do |line|
668
- skip_line = @max_line_size ? line.bytesize > @max_line_size : false
669
- if skip_line
670
- log.warn "received line length is longer than #{@max_line_size}"
671
- log.debug "skipped line: #{line.chomp}"
672
- end
673
- skip_line
674
- end
675
700
  es = @receive_handler.call(lines, tail_watcher)
676
701
  unless es.empty?
677
702
  tag = if @tag_prefix || @tag_suffix
@@ -769,6 +794,7 @@ module Fluent::Plugin
769
794
  'opened_file_count' => @metrics.opened.get,
770
795
  'closed_file_count' => @metrics.closed.get,
771
796
  'rotated_file_count' => @metrics.rotated.get,
797
+ 'throttled_log_count' => @metrics.throttled.get,
772
798
  })
773
799
  }
774
800
  stats
@@ -787,6 +813,7 @@ module Fluent::Plugin
787
813
  from_encoding: @from_encoding,
788
814
  encoding: @encoding,
789
815
  metrics: @metrics,
816
+ max_line_size: @max_line_size,
790
817
  &method(:receive_lines)
791
818
  )
792
819
  end
@@ -979,15 +1006,19 @@ module Fluent::Plugin
979
1006
  end
980
1007
 
981
1008
  class FIFO
982
- def initialize(from_encoding, encoding)
1009
+ def initialize(from_encoding, encoding, log, max_line_size=nil)
983
1010
  @from_encoding = from_encoding
984
1011
  @encoding = encoding
985
1012
  @need_enc = from_encoding != encoding
986
1013
  @buffer = ''.force_encoding(from_encoding)
987
1014
  @eol = "\n".encode(from_encoding).freeze
1015
+ @max_line_size = max_line_size
1016
+ @skip_current_line = false
1017
+ @skipping_current_line_bytesize = 0
1018
+ @log = log
988
1019
  end
989
1020
 
990
- attr_reader :from_encoding, :encoding, :buffer
1021
+ attr_reader :from_encoding, :encoding, :buffer, :max_line_size
991
1022
 
992
1023
  def <<(chunk)
993
1024
  # Although "chunk" is most likely transient besides String#force_encoding itself
@@ -1019,6 +1050,7 @@ module Fluent::Plugin
1019
1050
 
1020
1051
  def read_lines(lines)
1021
1052
  idx = @buffer.index(@eol)
1053
+ has_skipped_line = false
1022
1054
 
1023
1055
  until idx.nil?
1024
1056
  # Using freeze and slice is faster than slice!
@@ -1027,11 +1059,47 @@ module Fluent::Plugin
1027
1059
  rbuf = @buffer.slice(0, idx + 1)
1028
1060
  @buffer = @buffer.slice(idx + 1, @buffer.size)
1029
1061
  idx = @buffer.index(@eol)
1062
+
1063
+ is_long_line = @max_line_size && (
1064
+ @skip_current_line || rbuf.bytesize > @max_line_size
1065
+ )
1066
+
1067
+ if is_long_line
1068
+ @log.warn "received line length is longer than #{@max_line_size}"
1069
+ if @skip_current_line
1070
+ @log.debug("The continuing line is finished. Finally discarded data: ") { convert(rbuf).chomp }
1071
+ else
1072
+ @log.debug("skipped line: ") { convert(rbuf).chomp }
1073
+ end
1074
+ has_skipped_line = true
1075
+ @skip_current_line = false
1076
+ @skipping_current_line_bytesize = 0
1077
+ next
1078
+ end
1079
+
1030
1080
  lines << convert(rbuf)
1031
1081
  end
1082
+
1083
+ is_long_current_line = @max_line_size && (
1084
+ @skip_current_line || @buffer.bytesize > @max_line_size
1085
+ )
1086
+
1087
+ if is_long_current_line
1088
+ @log.debug(
1089
+ "The continuing current line length is longer than #{@max_line_size}." +
1090
+ " The received data will be discarded until this line is finished." +
1091
+ " Discarded data: "
1092
+ ) { convert(@buffer).chomp }
1093
+ @skip_current_line = true
1094
+ @skipping_current_line_bytesize += @buffer.bytesize
1095
+ @buffer.clear
1096
+ end
1097
+
1098
+ return has_skipped_line
1032
1099
  end
1033
1100
 
1034
- def bytesize
1101
+ def reading_bytesize
1102
+ return @skipping_current_line_bytesize if @skip_current_line
1035
1103
  @buffer.bytesize
1036
1104
  end
1037
1105
  end
@@ -1042,14 +1110,14 @@ module Fluent::Plugin
1042
1110
 
1043
1111
  attr_accessor :shutdown_timeout
1044
1112
 
1045
- def initialize(watcher, path:, read_lines_limit:, read_bytes_limit_per_second:, log:, open_on_every_update:, from_encoding: nil, encoding: nil, metrics:, &receive_lines)
1113
+ def initialize(watcher, path:, read_lines_limit:, read_bytes_limit_per_second:, max_line_size: nil, log:, open_on_every_update:, from_encoding: nil, encoding: nil, metrics:, &receive_lines)
1046
1114
  @watcher = watcher
1047
1115
  @path = path
1048
1116
  @read_lines_limit = read_lines_limit
1049
1117
  @read_bytes_limit_per_second = read_bytes_limit_per_second
1050
1118
  @receive_lines = receive_lines
1051
1119
  @open_on_every_update = open_on_every_update
1052
- @fifo = FIFO.new(from_encoding || Encoding::ASCII_8BIT, encoding || Encoding::ASCII_8BIT)
1120
+ @fifo = FIFO.new(from_encoding || Encoding::ASCII_8BIT, encoding || Encoding::ASCII_8BIT, log, max_line_size)
1053
1121
  @iobuf = ''.force_encoding('ASCII-8BIT')
1054
1122
  @lines = []
1055
1123
  @io = nil
@@ -1126,12 +1194,15 @@ module Fluent::Plugin
1126
1194
  end
1127
1195
 
1128
1196
  def handle_notify
1129
- return if limit_bytes_per_second_reached?
1130
- return if group_watcher&.limit_lines_reached?(@path)
1197
+ if limit_bytes_per_second_reached? || group_watcher&.limit_lines_reached?(@path)
1198
+ @metrics.throttled.inc
1199
+ return
1200
+ end
1131
1201
 
1132
1202
  with_io do |io|
1133
1203
  begin
1134
1204
  read_more = false
1205
+ has_skipped_line = false
1135
1206
 
1136
1207
  if !io.nil? && @lines.empty?
1137
1208
  begin
@@ -1145,7 +1216,7 @@ module Fluent::Plugin
1145
1216
  @fifo << data
1146
1217
 
1147
1218
  n_lines_before_read = @lines.size
1148
- @fifo.read_lines(@lines)
1219
+ has_skipped_line = @fifo.read_lines(@lines) || has_skipped_line
1149
1220
  group_watcher&.update_lines_read(@path, @lines.size - n_lines_before_read)
1150
1221
 
1151
1222
  group_watcher_limit = group_watcher&.limit_lines_reached?(@path)
@@ -1153,6 +1224,7 @@ module Fluent::Plugin
1153
1224
 
1154
1225
  if group_watcher_limit || limit_bytes_per_second_reached? || should_shutdown_now?
1155
1226
  # Just get out from tailing loop.
1227
+ @metrics.throttled.inc if group_watcher_limit || limit_bytes_per_second_reached?
1156
1228
  read_more = false
1157
1229
  break
1158
1230
  end
@@ -1168,9 +1240,11 @@ module Fluent::Plugin
1168
1240
  end
1169
1241
  end
1170
1242
 
1171
- unless @lines.empty?
1243
+ if @lines.empty?
1244
+ @watcher.pe.update_pos(io.pos - @fifo.reading_bytesize) if has_skipped_line
1245
+ else
1172
1246
  if @receive_lines.call(@lines, @watcher)
1173
- @watcher.pe.update_pos(io.pos - @fifo.bytesize)
1247
+ @watcher.pe.update_pos(io.pos - @fifo.reading_bytesize)
1174
1248
  @lines.clear
1175
1249
  else
1176
1250
  read_more = false
@@ -1182,12 +1256,12 @@ module Fluent::Plugin
1182
1256
 
1183
1257
  def open
1184
1258
  io = Fluent::FileWrapper.open(@path)
1185
- io.seek(@watcher.pe.read_pos + @fifo.bytesize)
1259
+ io.seek(@watcher.pe.read_pos + @fifo.reading_bytesize)
1186
1260
  @metrics.opened.inc
1187
1261
  io
1188
1262
  rescue RangeError
1189
1263
  io.close if io
1190
- raise WatcherSetupError, "seek error with #{@path}: file position = #{@watcher.pe.read_pos.to_s(16)}, reading bytesize = #{@fifo.bytesize.to_s(16)}"
1264
+ raise WatcherSetupError, "seek error with #{@path}: file position = #{@watcher.pe.read_pos.to_s(16)}, reading bytesize = #{@fifo.reading_bytesize.to_s(16)}"
1191
1265
  rescue Errno::EACCES => e
1192
1266
  @log.warn "#{e}"
1193
1267
  nil
@@ -89,7 +89,7 @@ module Fluent::Plugin
89
89
 
90
90
  case @copy_mode
91
91
  when :no_copy
92
- nil
92
+ nil
93
93
  when :shallow
94
94
  Proc.new { |es| es.dup }
95
95
  when :deep
@@ -172,6 +172,14 @@ module Fluent::Plugin
172
172
  log.warn "symlink_path is unavailable on Windows platform. disabled."
173
173
  @symlink_path = nil
174
174
  else
175
+ placeholder_validators(:symlink_path, @symlink_path).reject{ |v| v.type == :time }.each do |v|
176
+ begin
177
+ v.validate!
178
+ rescue Fluent::ConfigError => e
179
+ log.warn "#{e}. This means multiple chunks are competing for a single symlink_path, so some logs may not be taken from the symlink."
180
+ end
181
+ end
182
+
175
183
  @buffer.extend SymlinkBufferMixin
176
184
  @buffer.symlink_path = @symlink_path
177
185
  @buffer.output_plugin_for_symlink = self
@@ -37,6 +37,8 @@ module Fluent::Plugin
37
37
 
38
38
  class RetryableResponse < StandardError; end
39
39
 
40
+ ConnectionCache = Struct.new(:uri, :conn)
41
+
40
42
  helpers :formatter
41
43
 
42
44
  desc 'The endpoint for HTTP request, e.g. http://example.com/api'
@@ -53,6 +55,8 @@ module Fluent::Plugin
53
55
  config_param :headers, :hash, default: nil
54
56
  desc 'Additional placeholder based headers for HTTP request'
55
57
  config_param :headers_from_placeholders, :hash, default: nil
58
+ desc 'Compress HTTP request body'
59
+ config_param :compress, :enum, list: [:text, :gzip], default: :text
56
60
 
57
61
  desc 'The connection open timeout in seconds'
58
62
  config_param :open_timeout, :integer, default: nil
@@ -60,6 +64,8 @@ module Fluent::Plugin
60
64
  config_param :read_timeout, :integer, default: nil
61
65
  desc 'The TLS timeout in seconds'
62
66
  config_param :ssl_timeout, :integer, default: nil
67
+ desc 'Try to reuse connections'
68
+ config_param :reuse_connections, :bool, default: false
63
69
 
64
70
  desc 'The CA certificate path for TLS'
65
71
  config_param :tls_ca_cert_path, :string, default: nil
@@ -87,11 +93,29 @@ module Fluent::Plugin
87
93
 
88
94
  config_section :auth, required: false, multi: false do
89
95
  desc 'The method for HTTP authentication'
90
- config_param :method, :enum, list: [:basic], default: :basic
96
+ config_param :method, :enum, list: [:basic, :aws_sigv4], default: :basic
91
97
  desc 'The username for basic authentication'
92
98
  config_param :username, :string, default: nil
93
99
  desc 'The password for basic authentication'
94
100
  config_param :password, :string, default: nil, secret: true
101
+ desc 'The AWS service to authenticate against'
102
+ config_param :aws_service, :string, default: nil
103
+ desc 'The AWS region to use when authenticating'
104
+ config_param :aws_region, :string, default: nil
105
+ desc 'The AWS role ARN to assume when authenticating'
106
+ config_param :aws_role_arn, :string, default: nil
107
+ end
108
+
109
+ def connection_cache_id_thread_key
110
+ "#{plugin_id}_connection_cache_id"
111
+ end
112
+
113
+ def connection_cache_id_for_thread
114
+ Thread.current[connection_cache_id_thread_key]
115
+ end
116
+
117
+ def connection_cache_id_for_thread=(id)
118
+ Thread.current[connection_cache_id_thread_key] = id
95
119
  end
96
120
 
97
121
  def initialize
@@ -100,11 +124,23 @@ module Fluent::Plugin
100
124
  @uri = nil
101
125
  @proxy_uri = nil
102
126
  @formatter = nil
127
+
128
+ @connection_cache = []
129
+ @connection_cache_id_mutex = Mutex.new
130
+ @connection_cache_next_id = 0
131
+ end
132
+
133
+ def close
134
+ super
135
+
136
+ @connection_cache.each {|entry| entry.conn.finish if entry.conn&.started? }
103
137
  end
104
138
 
105
139
  def configure(conf)
106
140
  super
107
141
 
142
+ @connection_cache = Array.new(actual_flush_thread_count, ConnectionCache.new("", nil)) if @reuse_connections
143
+
108
144
  if @retryable_response_codes.nil?
109
145
  log.warn('Status code 503 is going to be removed from default `retryable_response_codes` from fluentd v2. Please add it by yourself if you wish')
110
146
  @retryable_response_codes = [503]
@@ -121,6 +157,36 @@ module Fluent::Plugin
121
157
  end
122
158
  define_singleton_method(:format, method(:format_json_array))
123
159
  end
160
+
161
+ if @auth and @auth.method == :aws_sigv4
162
+ begin
163
+ require 'aws-sigv4'
164
+ require 'aws-sdk-core'
165
+ rescue LoadError
166
+ raise Fluent::ConfigError, "The aws-sdk-core and aws-sigv4 gems are required for aws_sigv4 auth. Run: gem install aws-sdk-core -v '~> 3.191'"
167
+ end
168
+
169
+ raise Fluent::ConfigError, "aws_service is required for aws_sigv4 auth" unless @auth.aws_service != nil
170
+ raise Fluent::ConfigError, "aws_region is required for aws_sigv4 auth" unless @auth.aws_region != nil
171
+
172
+ if @auth.aws_role_arn == nil
173
+ aws_credentials = Aws::CredentialProviderChain.new.resolve
174
+ else
175
+ aws_credentials = Aws::AssumeRoleCredentials.new(
176
+ client: Aws::STS::Client.new(
177
+ region: @auth.aws_region
178
+ ),
179
+ role_arn: @auth.aws_role_arn,
180
+ role_session_name: "fluentd"
181
+ )
182
+ end
183
+
184
+ @aws_signer = Aws::Sigv4::Signer.new(
185
+ service: @auth.aws_service,
186
+ region: @auth.aws_region,
187
+ credentials_provider: aws_credentials
188
+ )
189
+ end
124
190
  end
125
191
 
126
192
  def multi_workers_ready?
@@ -215,7 +281,7 @@ module Fluent::Plugin
215
281
  URI.parse(endpoint)
216
282
  end
217
283
 
218
- def set_headers(req, chunk)
284
+ def set_headers(req, uri, chunk)
219
285
  if @headers
220
286
  @headers.each do |k, v|
221
287
  req[k] = v
@@ -226,9 +292,34 @@ module Fluent::Plugin
226
292
  req[k] = extract_placeholders(v, chunk)
227
293
  end
228
294
  end
295
+ if @compress == :gzip
296
+ req['Content-Encoding'] = "gzip"
297
+ end
229
298
  req['Content-Type'] = @content_type
230
299
  end
231
300
 
301
+ def set_auth(req, uri)
302
+ return unless @auth
303
+
304
+ if @auth.method == :basic
305
+ req.basic_auth(@auth.username, @auth.password)
306
+ elsif @auth.method == :aws_sigv4
307
+ signature = @aws_signer.sign_request(
308
+ http_method: req.method,
309
+ url: uri.request_uri,
310
+ headers: {
311
+ 'Content-Type' => @content_type,
312
+ 'Host' => uri.host
313
+ },
314
+ body: req.body
315
+ )
316
+ req.add_field('x-amz-date', signature.headers['x-amz-date'])
317
+ req.add_field('x-amz-security-token', signature.headers['x-amz-security-token'])
318
+ req.add_field('x-amz-content-sha256', signature.headers['x-amz-content-sha256'])
319
+ req.add_field('authorization', signature.headers['authorization'])
320
+ end
321
+ end
322
+
232
323
  def create_request(chunk, uri)
233
324
  req = case @http_method
234
325
  when :post
@@ -236,23 +327,56 @@ module Fluent::Plugin
236
327
  when :put
237
328
  Net::HTTP::Put.new(uri.request_uri)
238
329
  end
239
- if @auth
240
- req.basic_auth(@auth.username, @auth.password)
241
- end
242
- set_headers(req, chunk)
330
+ set_headers(req, uri, chunk)
331
+
243
332
  req.body = @json_array ? "[#{chunk.read.chop}]" : chunk.read
333
+
334
+ if @compress == :gzip
335
+ gz = Zlib::GzipWriter.new(StringIO.new)
336
+ gz << req.body
337
+ req.body = gz.close.string
338
+ end
339
+
340
+ # At least one authentication method requires the body and other headers, so the order of this call matters
341
+ set_auth(req, uri)
244
342
  req
245
343
  end
246
344
 
345
+ def make_request_cached(uri, req)
346
+ id = self.connection_cache_id_for_thread
347
+ if id.nil?
348
+ @connection_cache_id_mutex.synchronize {
349
+ id = @connection_cache_next_id
350
+ @connection_cache_next_id += 1
351
+ }
352
+ self.connection_cache_id_for_thread = id
353
+ end
354
+ uri_str = uri.to_s
355
+ if @connection_cache[id].uri != uri_str
356
+ @connection_cache[id].conn.finish if @connection_cache[id].conn&.started?
357
+ http = if @proxy_uri
358
+ Net::HTTP.start(uri.host, uri.port, @proxy_uri.host, @proxy_uri.port, @proxy_uri.user, @proxy_uri.password, @http_opt)
359
+ else
360
+ Net::HTTP.start(uri.host, uri.port, @http_opt)
361
+ end
362
+ @connection_cache[id] = ConnectionCache.new(uri_str, http)
363
+ end
364
+ @connection_cache[id].conn.request(req)
365
+ end
366
+
367
+ def make_request(uri, req, &block)
368
+ if @proxy_uri
369
+ Net::HTTP.start(uri.host, uri.port, @proxy_uri.host, @proxy_uri.port, @proxy_uri.user, @proxy_uri.password, @http_opt, &block)
370
+ else
371
+ Net::HTTP.start(uri.host, uri.port, @http_opt, &block)
372
+ end
373
+ end
374
+
247
375
  def send_request(uri, req)
248
- res = if @proxy_uri
249
- Net::HTTP.start(uri.host, uri.port, @proxy_uri.host, @proxy_uri.port, @proxy_uri.user, @proxy_uri.password, @http_opt) { |http|
250
- http.request(req)
251
- }
376
+ res = if @reuse_connections
377
+ make_request_cached(uri, req)
252
378
  else
253
- Net::HTTP.start(uri.host, uri.port, @http_opt) { |http|
254
- http.request(req)
255
- }
379
+ make_request(uri, req) { |http| http.request(req) }
256
380
  end
257
381
 
258
382
  if res.is_a?(Net::HTTPSuccess)
@@ -21,7 +21,6 @@ module Fluent
21
21
  @_owner = plugin
22
22
 
23
23
  @_plugin_id = plugin.plugin_id
24
- @_plugin_id_configured = plugin.plugin_id_configured?
25
24
 
26
25
  @log = plugin.log
27
26
  end
@@ -50,36 +50,45 @@ module Fluent
50
50
  def configure_json_parser(name)
51
51
  case name
52
52
  when :oj
53
- raise LoadError unless Fluent::OjOptions.available?
54
- [Oj.method(:load), Oj::ParseError]
53
+ return [Oj.method(:load), Oj::ParseError] if Fluent::OjOptions.available?
54
+
55
+ log&.info "Oj is not installed, and failing back to Yajl for json parser"
56
+ configure_json_parser(:yajl)
55
57
  when :json then [JSON.method(:load), JSON::ParserError]
56
58
  when :yajl then [Yajl.method(:load), Yajl::ParseError]
57
59
  else
58
60
  raise "BUG: unknown json parser specified: #{name}"
59
61
  end
60
- rescue LoadError => ex
61
- name = :yajl
62
- if log
63
- if /\boj\z/.match?(ex.message)
64
- log.info "Oj is not installed, and failing back to Yajl for json parser"
65
- else
66
- log.warn ex.message
67
- end
68
- end
69
- retry
70
62
  end
71
63
 
72
64
  def parse(text)
73
- record = @load_proc.call(text)
74
- time = parse_time(record)
75
- if @execute_convert_values
76
- time, record = convert_values(time, record)
65
+ parsed_json = @load_proc.call(text)
66
+
67
+ if parsed_json.is_a?(Hash)
68
+ time, record = parse_one_record(parsed_json)
69
+ yield time, record
70
+ elsif parsed_json.is_a?(Array)
71
+ parsed_json.each do |record|
72
+ unless record.is_a?(Hash)
73
+ yield nil, nil
74
+ next
75
+ end
76
+ time, parsed_record = parse_one_record(record)
77
+ yield time, parsed_record
78
+ end
79
+ else
80
+ yield nil, nil
77
81
  end
78
- yield time, record
82
+
79
83
  rescue @error_class, EncodingError # EncodingError is for oj 3.x or later
80
84
  yield nil, nil
81
85
  end
82
86
 
87
+ def parse_one_record(record)
88
+ time = parse_time(record)
89
+ convert_values(time, record)
90
+ end
91
+
83
92
  def parser_type
84
93
  :text
85
94
  end
@@ -31,9 +31,9 @@ module Fluent
31
31
  :binary
32
32
  end
33
33
 
34
- def parse(data)
34
+ def parse(data, &block)
35
35
  @unpacker.feed_each(data) do |obj|
36
- yield convert_values(parse_time(obj), obj)
36
+ parse_unpacked_data(obj, &block)
37
37
  end
38
38
  end
39
39
  alias parse_partial_data parse
@@ -41,8 +41,29 @@ module Fluent
41
41
  def parse_io(io, &block)
42
42
  u = Fluent::MessagePackFactory.engine_factory.unpacker(io)
43
43
  u.each do |obj|
44
- time, record = convert_values(parse_time(obj), obj)
44
+ parse_unpacked_data(obj, &block)
45
+ end
46
+ end
47
+
48
+ def parse_unpacked_data(data)
49
+ if data.is_a?(Hash)
50
+ time, record = convert_values(parse_time(data), data)
45
51
  yield time, record
52
+ return
53
+ end
54
+
55
+ unless data.is_a?(Array)
56
+ yield nil, nil
57
+ return
58
+ end
59
+
60
+ data.each do |record|
61
+ unless record.is_a?(Hash)
62
+ yield nil, nil
63
+ next
64
+ end
65
+ time, converted_record = convert_values(parse_time(record), record)
66
+ yield time, converted_record
46
67
  end
47
68
  end
48
69
  end