fluentd 1.10.2-x64-mingw32 → 1.11.2-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of fluentd might be problematic. Click here for more details.

Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +102 -1
  3. data/CONTRIBUTING.md +1 -1
  4. data/example/copy_roundrobin.conf +3 -3
  5. data/example/counter.conf +1 -1
  6. data/example/filter_stdout.conf +2 -2
  7. data/example/{in_dummy_blocks.conf → in_sample_blocks.conf} +4 -4
  8. data/example/{in_dummy_with_compression.conf → in_sample_with_compression.conf} +3 -3
  9. data/example/logevents.conf +5 -5
  10. data/example/multi_filters.conf +1 -1
  11. data/example/out_exec_filter.conf +2 -2
  12. data/example/out_forward.conf +1 -1
  13. data/example/out_forward_buf_file.conf +1 -1
  14. data/example/out_forward_client.conf +5 -5
  15. data/example/out_forward_heartbeat_none.conf +1 -1
  16. data/example/out_forward_sd.conf +1 -1
  17. data/example/out_forward_shared_key.conf +2 -2
  18. data/example/out_forward_tls.conf +1 -1
  19. data/example/out_forward_users.conf +3 -3
  20. data/example/out_null.conf +4 -4
  21. data/example/secondary_file.conf +1 -1
  22. data/lib/fluent/command/fluentd.rb +11 -0
  23. data/lib/fluent/config.rb +1 -0
  24. data/lib/fluent/match.rb +10 -1
  25. data/lib/fluent/plugin/buffer.rb +24 -4
  26. data/lib/fluent/plugin/in_dummy.rb +2 -123
  27. data/lib/fluent/plugin/in_forward.rb +2 -2
  28. data/lib/fluent/plugin/in_gc_stat.rb +16 -0
  29. data/lib/fluent/plugin/in_http.rb +148 -77
  30. data/lib/fluent/plugin/in_monitor_agent.rb +1 -1
  31. data/lib/fluent/plugin/in_sample.rb +141 -0
  32. data/lib/fluent/plugin/in_tail.rb +4 -4
  33. data/lib/fluent/plugin/in_unix.rb +77 -77
  34. data/lib/fluent/plugin/out_file.rb +1 -1
  35. data/lib/fluent/plugin/out_forward.rb +7 -2
  36. data/lib/fluent/plugin/out_forward/load_balancer.rb +1 -1
  37. data/lib/fluent/plugin/out_http.rb +15 -2
  38. data/lib/fluent/plugin/parser_multiline.rb +1 -1
  39. data/lib/fluent/plugin/parser_syslog.rb +215 -54
  40. data/lib/fluent/plugin_helper/cert_option.rb +5 -8
  41. data/lib/fluent/plugin_helper/child_process.rb +3 -2
  42. data/lib/fluent/plugin_helper/record_accessor.rb +14 -0
  43. data/lib/fluent/plugin_helper/service_discovery.rb +7 -0
  44. data/lib/fluent/plugin_helper/service_discovery/manager.rb +8 -0
  45. data/lib/fluent/plugin_helper/socket.rb +1 -1
  46. data/lib/fluent/plugin_helper/socket_option.rb +2 -2
  47. data/lib/fluent/supervisor.rb +6 -3
  48. data/lib/fluent/test/filter_test.rb +2 -2
  49. data/lib/fluent/test/output_test.rb +3 -3
  50. data/lib/fluent/version.rb +1 -1
  51. data/test/plugin/out_forward/test_load_balancer.rb +46 -0
  52. data/test/plugin/test_in_gc_stat.rb +24 -1
  53. data/test/plugin/test_in_http.rb +57 -0
  54. data/test/plugin/{test_in_dummy.rb → test_in_sample.rb} +25 -25
  55. data/test/plugin/test_in_tail.rb +17 -0
  56. data/test/plugin/test_in_unix.rb +128 -73
  57. data/test/plugin/test_out_http.rb +38 -0
  58. data/test/plugin/test_parser_syslog.rb +66 -29
  59. data/test/plugin_helper/data/cert/empty.pem +0 -0
  60. data/test/plugin_helper/test_cert_option.rb +7 -0
  61. data/test/plugin_helper/test_child_process.rb +15 -0
  62. data/test/plugin_helper/test_record_accessor.rb +41 -0
  63. data/test/plugin_helper/test_server.rb +34 -0
  64. data/test/plugin_helper/test_service_discovery.rb +37 -4
  65. data/test/plugin_helper/test_socket.rb +8 -0
  66. data/test/test_match.rb +11 -0
  67. data/test/test_static_config_analysis.rb +2 -2
  68. metadata +9 -6
@@ -56,7 +56,7 @@ module Fluent::Plugin
56
56
  end
57
57
 
58
58
  def rebuild_weight_array(nodes)
59
- standby_nodes, regular_nodes = nodes.partition {|n|
59
+ standby_nodes, regular_nodes = nodes.select { |e| e.weight > 0 }.partition {|n|
60
60
  n.standby?
61
61
  }
62
62
 
@@ -37,6 +37,8 @@ module Fluent::Plugin
37
37
  config_param :proxy, :string, default: ENV['HTTP_PROXY'] || ENV['http_proxy']
38
38
  desc 'Content-Type for HTTP request'
39
39
  config_param :content_type, :string, default: nil
40
+ desc 'JSON array data format for HTTP request body'
41
+ config_param :json_array, :bool, default: false
40
42
  desc 'Additional headers for HTTP request'
41
43
  config_param :headers, :hash, default: nil
42
44
 
@@ -100,6 +102,13 @@ module Fluent::Plugin
100
102
  @proxy_uri = URI.parse(@proxy) if @proxy
101
103
  @formatter = formatter_create
102
104
  @content_type = setup_content_type unless @content_type
105
+
106
+ if @json_array
107
+ if @formatter_configs.first[:@type] != "json"
108
+ raise Fluent::ConfigError, "json_array option could be used with json formatter only"
109
+ end
110
+ define_singleton_method(:format, method(:format_json_array))
111
+ end
103
112
  end
104
113
 
105
114
  def multi_workers_ready?
@@ -114,6 +123,10 @@ module Fluent::Plugin
114
123
  @formatter.format(tag, time, record)
115
124
  end
116
125
 
126
+ def format_json_array(tag, time, record)
127
+ @formatter.format(tag, time, record) << ","
128
+ end
129
+
117
130
  def write(chunk)
118
131
  uri = parse_endpoint(chunk)
119
132
  req = create_request(chunk, uri)
@@ -128,7 +141,7 @@ module Fluent::Plugin
128
141
  def setup_content_type
129
142
  case @formatter_configs.first[:@type]
130
143
  when 'json'
131
- 'application/x-ndjson'
144
+ @json_array ? 'application/json' : 'application/x-ndjson'
132
145
  when 'csv'
133
146
  'text/csv'
134
147
  when 'tsv', 'ltsv'
@@ -202,7 +215,7 @@ module Fluent::Plugin
202
215
  req.basic_auth(@auth.username, @auth.password)
203
216
  end
204
217
  set_headers(req)
205
- req.body = chunk.read
218
+ req.body = @json_array ? "[#{chunk.read.chop!}]" : chunk.read
206
219
  req
207
220
  end
208
221
 
@@ -104,7 +104,7 @@ module Fluent
104
104
  end
105
105
 
106
106
  def firstline?(text)
107
- @firstline_regex.match(text)
107
+ @firstline_regex.match?(text)
108
108
  end
109
109
 
110
110
  private
@@ -63,16 +63,22 @@ module Fluent
63
63
  def initialize
64
64
  super
65
65
  @mutex = Mutex.new
66
- @space_count = nil
66
+ @regexp = nil
67
+ @regexp3164 = nil
68
+ @regexp5424 = nil
69
+ @regexp_parser = nil
70
+ @time_parser_rfc3164 = nil
71
+ @time_parser_rfc5424 = nil
72
+ @space_count_rfc3164 = nil
67
73
  @space_count_rfc5424 = nil
74
+ @skip_space_count_rfc3164 = false
75
+ @skip_space_count_rfc5424 = false
76
+ @time_parser_rfc5424_without_subseconds = nil
68
77
  end
69
78
 
70
79
  def configure(conf)
71
80
  super
72
81
 
73
- @time_parser_rfc3164 = @time_parser_rfc5424 = nil
74
- @time_parser_rfc5424_without_subseconds = nil
75
- @support_rfc5424_without_subseconds = false
76
82
  @regexp_parser = @parser_type == :regexp
77
83
  @regexp = case @message_format
78
84
  when :rfc3164
@@ -85,27 +91,49 @@ module Fluent
85
91
  alias_method :parse, :parse_rfc3164
86
92
  end
87
93
  end
94
+ setup_time_parser_3164(@time_format)
88
95
  RFC3164_WITHOUT_TIME_AND_PRI_REGEXP
89
96
  when :rfc5424
90
- class << self
91
- alias_method :parse, :parse_rfc5424_regex
97
+ if @regexp_parser
98
+ class << self
99
+ alias_method :parse, :parse_rfc5424_regex
100
+ end
101
+ else
102
+ class << self
103
+ alias_method :parse, :parse_rfc5424
104
+ end
92
105
  end
93
106
  @time_format = @rfc5424_time_format unless conf.has_key?('time_format')
94
- @support_rfc5424_without_subseconds = true
107
+ setup_time_parser_5424(@time_format)
95
108
  RFC5424_WITHOUT_TIME_AND_PRI_REGEXP
96
109
  when :auto
97
110
  class << self
98
111
  alias_method :parse, :parse_auto
99
112
  end
100
- @time_parser_rfc3164 = time_parser_create(format: @time_format)
101
- @time_parser_rfc5424 = time_parser_create(format: @rfc5424_time_format)
113
+ setup_time_parser_3164(@time_format)
114
+ setup_time_parser_5424(@rfc5424_time_format)
102
115
  nil
103
116
  end
104
117
 
105
- @space_count = @time_format.squeeze(' ').count(' ') + 1
106
- @space_count_rfc5424 = @rfc5424_time_format.squeeze(' ').count(' ') + 1
107
- @time_parser = time_parser_create
118
+ if @regexp_parser
119
+ @regexp3164 = RFC3164_WITHOUT_TIME_AND_PRI_REGEXP
120
+ @regexp5424 = RFC5424_WITHOUT_TIME_AND_PRI_REGEXP
121
+ end
122
+ end
123
+
124
+ def setup_time_parser_3164(time_fmt)
125
+ @time_parser_rfc3164 = time_parser_create(format: time_fmt)
126
+ if ['%b %d %H:%M:%S', '%b %d %H:%M:%S.%N'].include?(time_fmt)
127
+ @skip_space_count_rfc3164 = true
128
+ end
129
+ @space_count_rfc3164 = time_fmt.squeeze(' ').count(' ') + 1
130
+ end
131
+
132
+ def setup_time_parser_5424(time_fmt)
133
+ @time_parser_rfc5424 = time_parser_create(format: time_fmt)
108
134
  @time_parser_rfc5424_without_subseconds = time_parser_create(format: "%Y-%m-%dT%H:%M:%S%z")
135
+ @skip_space_count_rfc5424 = time_fmt.count(' ').zero?
136
+ @space_count_rfc5424 = time_fmt.squeeze(' ').count(' ') + 1
109
137
  end
110
138
 
111
139
  # this method is for tests
@@ -118,14 +146,13 @@ module Fluent
118
146
  end
119
147
 
120
148
  def parse_auto(text, &block)
121
- if REGEXP_DETECT_RFC5424.match(text)
122
- @regexp = RFC5424_WITHOUT_TIME_AND_PRI_REGEXP
123
- @time_parser = @time_parser_rfc5424
124
- @support_rfc5424_without_subseconds = true
125
- parse_rfc5424_regex(text, &block)
149
+ if REGEXP_DETECT_RFC5424.match?(text)
150
+ if @regexp_parser
151
+ parse_rfc5424_regex(text, &block)
152
+ else
153
+ parse_rfc5424(text, &block)
154
+ end
126
155
  else
127
- @regexp = RFC3164_WITHOUT_TIME_AND_PRI_REGEXP
128
- @time_parser = @time_parser_rfc3164
129
156
  if @regexp_parser
130
157
  parse_rfc3164_regex(text, &block)
131
158
  else
@@ -134,6 +161,8 @@ module Fluent
134
161
  end
135
162
  end
136
163
 
164
+ SPLIT_CHAR = ' '.freeze
165
+
137
166
  def parse_rfc3164_regex(text, &block)
138
167
  idx = 0
139
168
  record = {}
@@ -151,22 +180,22 @@ module Fluent
151
180
 
152
181
  i = idx - 1
153
182
  sq = false
154
- @space_count.times do
155
- while text[i + 1] == ' '.freeze
183
+ @space_count_rfc3164.times do
184
+ while text[i + 1] == SPLIT_CHAR
156
185
  sq = true
157
186
  i += 1
158
187
  end
159
188
 
160
- i = text.index(' '.freeze, i + 1)
189
+ i = text.index(SPLIT_CHAR, i + 1)
161
190
  end
162
191
 
163
- time_str = sq ? text.slice(idx, i - idx).squeeze(' ') : text.slice(idx, i - idx)
164
- time = @mutex.synchronize { @time_parser.parse(time_str) }
192
+ time_str = sq ? text.slice(idx, i - idx).squeeze(SPLIT_CHAR) : text.slice(idx, i - idx)
193
+ time = @mutex.synchronize { @time_parser_rfc3164.parse(time_str) }
165
194
  if @keep_time_key
166
195
  record['time'] = time_str
167
196
  end
168
197
 
169
- parse_plain(time, text, i + 1, record, RFC3164_CAPTURES, &block)
198
+ parse_plain(@regexp3164, time, text, i + 1, record, RFC3164_CAPTURES, &block)
170
199
  end
171
200
 
172
201
  def parse_rfc5424_regex(text, &block)
@@ -186,40 +215,36 @@ module Fluent
186
215
  i = idx - 1
187
216
  sq = false
188
217
  @space_count_rfc5424.times {
189
- while text[i + 1] == ' '.freeze
218
+ while text[i + 1] == SPLIT_CHAR
190
219
  sq = true
191
220
  i += 1
192
221
  end
193
222
 
194
- i = text.index(' '.freeze, i + 1)
223
+ i = text.index(SPLIT_CHAR, i + 1)
195
224
  }
196
225
 
197
- time_str = sq ? text.slice(idx, i - idx).squeeze(' '.freeze) : text.slice(idx, i - idx)
226
+ time_str = sq ? text.slice(idx, i - idx).squeeze(SPLIT_CHAR) : text.slice(idx, i - idx)
198
227
  time = @mutex.synchronize do
199
228
  begin
200
- @time_parser.parse(time_str)
229
+ @time_parser_rfc5424.parse(time_str)
201
230
  rescue Fluent::TimeParser::TimeParseError => e
202
- if @support_rfc5424_without_subseconds
203
- log.trace(e)
204
- @time_parser_rfc5424_without_subseconds.parse(time_str)
205
- else
206
- raise
207
- end
231
+ log.trace(e)
232
+ @time_parser_rfc5424_without_subseconds.parse(time_str)
208
233
  end
209
234
  end
210
235
 
211
236
  if @keep_time_key
212
237
  record['time'] = time_str
213
238
  end
214
- parse_plain(time, text, i + 1, record, RFC5424_CAPTURES, &block)
239
+ parse_plain(@regexp5424, time, text, i + 1, record, RFC5424_CAPTURES, &block)
215
240
  end
216
241
 
217
242
  # @param time [EventTime]
218
243
  # @param idx [Integer] note: this argument is needed to avoid string creation
219
244
  # @param record [Hash]
220
245
  # @param capture_list [Array] for performance
221
- def parse_plain(time, text, idx, record, capture_list, &block)
222
- m = @regexp.match(text, idx)
246
+ def parse_plain(re, time, text, idx, record, capture_list, &block)
247
+ m = re.match(text, idx)
223
248
  if m.nil?
224
249
  yield nil, nil
225
250
  return
@@ -244,8 +269,6 @@ module Fluent
244
269
  yield time, record
245
270
  end
246
271
 
247
- SPLIT_CHAR = ' '.freeze
248
-
249
272
  def parse_rfc3164(text, &block)
250
273
  pri = nil
251
274
  cursor = 0
@@ -264,20 +287,35 @@ module Fluent
264
287
  end
265
288
  end
266
289
 
267
- # header part
268
- time_size = 15 # skip Mmm dd hh:mm:ss
269
- time_end = text[cursor + time_size]
270
- if time_end == SPLIT_CHAR
271
- time_str = text.slice(cursor, time_size)
272
- cursor += 16 # time + ' '
273
- elsif time_end == '.'.freeze
274
- # support subsecond time
275
- i = text.index(SPLIT_CHAR, time_size)
276
- time_str = text.slice(cursor, i - cursor)
277
- cursor = i + 1
290
+ if @skip_space_count_rfc3164
291
+ # header part
292
+ time_size = 15 # skip Mmm dd hh:mm:ss
293
+ time_end = text[cursor + time_size]
294
+ if time_end == SPLIT_CHAR
295
+ time_str = text.slice(cursor, time_size)
296
+ cursor += 16 # time + ' '
297
+ elsif time_end == '.'.freeze
298
+ # support subsecond time
299
+ i = text.index(SPLIT_CHAR, time_size)
300
+ time_str = text.slice(cursor, i - cursor)
301
+ cursor = i + 1
302
+ else
303
+ yield nil, nil
304
+ return
305
+ end
278
306
  else
279
- yield nil, nil
280
- return
307
+ i = cursor - 1
308
+ sq = false
309
+ @space_count_rfc3164.times do
310
+ while text[i + 1] == SPLIT_CHAR
311
+ sq = true
312
+ i += 1
313
+ end
314
+ i = text.index(SPLIT_CHAR, i + 1)
315
+ end
316
+
317
+ time_str = sq ? text.slice(idx, i - cursor).squeeze(SPLIT_CHAR) : text.slice(cursor, i - cursor)
318
+ cursor = i + 1
281
319
  end
282
320
 
283
321
  i = text.index(SPLIT_CHAR, cursor)
@@ -325,7 +363,130 @@ module Fluent
325
363
  msg.chomp!
326
364
  record['message'] = msg
327
365
 
328
- time = @time_parser.parse(time_str)
366
+ time = @time_parser_rfc3164.parse(time_str)
367
+ record['time'] = time_str if @keep_time_key
368
+
369
+ yield time, record
370
+ end
371
+
372
+ NILVALUE = '-'.freeze
373
+
374
+ def parse_rfc5424(text, &block)
375
+ pri = nil
376
+ cursor = 0
377
+ if @with_priority
378
+ if text.start_with?('<'.freeze)
379
+ i = text.index('>'.freeze, 1)
380
+ if i < 2
381
+ yield nil, nil
382
+ return
383
+ end
384
+ pri = text.slice(1, i - 1).to_i
385
+ i = text.index(SPLIT_CHAR, i)
386
+ cursor = i + 1
387
+ else
388
+ yield nil, nil
389
+ return
390
+ end
391
+ end
392
+
393
+ # timestamp part
394
+ if @skip_space_count_rfc5424
395
+ i = text.index(SPLIT_CHAR, cursor)
396
+ time_str = text.slice(cursor, i - cursor)
397
+ cursor = i + 1
398
+ else
399
+ i = cursor - 1
400
+ sq = false
401
+ @space_count_rfc5424.times do
402
+ while text[i + 1] == SPLIT_CHAR
403
+ sq = true
404
+ i += 1
405
+ end
406
+ i = text.index(SPLIT_CHAR, i + 1)
407
+ end
408
+
409
+ time_str = sq ? text.slice(idx, i - cursor).squeeze(SPLIT_CHAR) : text.slice(cursor, i - cursor)
410
+ cursor = i + 1
411
+ end
412
+
413
+ # Repeat same code for the performance
414
+
415
+ # host part
416
+ i = text.index(SPLIT_CHAR, cursor)
417
+ unless i
418
+ yield nil, nil
419
+ return
420
+ end
421
+ slice_size = i - cursor
422
+ host = text.slice(cursor, slice_size)
423
+ cursor += slice_size + 1
424
+
425
+ # ident part
426
+ i = text.index(SPLIT_CHAR, cursor)
427
+ unless i
428
+ yield nil, nil
429
+ return
430
+ end
431
+ slice_size = i - cursor
432
+ ident = text.slice(cursor, slice_size)
433
+ cursor += slice_size + 1
434
+
435
+ # pid part
436
+ i = text.index(SPLIT_CHAR, cursor)
437
+ unless i
438
+ yield nil, nil
439
+ return
440
+ end
441
+ slice_size = i - cursor
442
+ pid = text.slice(cursor, slice_size)
443
+ cursor += slice_size + 1
444
+
445
+ # msgid part
446
+ i = text.index(SPLIT_CHAR, cursor)
447
+ unless i
448
+ yield nil, nil
449
+ return
450
+ end
451
+ slice_size = i - cursor
452
+ msgid = text.slice(cursor, slice_size)
453
+ cursor += slice_size + 1
454
+
455
+ record = {'host' => host, 'ident' => ident, 'pid' => pid, 'msgid' => msgid}
456
+ record['pri'] = pri if pri
457
+
458
+ # extradata part
459
+ ed_start = text[cursor]
460
+ if ed_start == NILVALUE
461
+ record['extradata'] = NILVALUE
462
+ cursor += 1
463
+ else
464
+ start = cursor
465
+ i = text.index('] '.freeze, cursor)
466
+ extradata = if i
467
+ diff = i + 1 - start # calculate ']' position
468
+ cursor += diff
469
+ text.slice(start, diff)
470
+ else # No message part case
471
+ cursor = text.bytesize
472
+ text.slice(start, cursor)
473
+ end
474
+ extradata.tr!("\\".freeze, ''.freeze)
475
+ record['extradata'] = extradata
476
+ end
477
+
478
+ # message part
479
+ if cursor != text.bytesize
480
+ msg = text.slice(cursor + 1, text.bytesize)
481
+ msg.chomp!
482
+ record['message'] = msg
483
+ end
484
+
485
+ time = begin
486
+ @time_parser_rfc5424.parse(time_str)
487
+ rescue Fluent::TimeParser::TimeParseError => e
488
+ @time_parser_rfc5424_without_subseconds.parse(time_str)
489
+ end
329
490
  record['time'] = time_str if @keep_time_key
330
491
 
331
492
  yield time, record
@@ -27,13 +27,9 @@ module Fluent
27
27
  cert, key, extra = cert_option_server_validate!(conf)
28
28
 
29
29
  ctx = OpenSSL::SSL::SSLContext.new
30
- unless insecure
31
- # inject OpenSSL::SSL::SSLContext::DEFAULT_PARAMS
32
- # https://bugs.ruby-lang.org/issues/9424
33
- ctx.set_params({})
34
-
35
- ctx.ciphers = ciphers
36
- end
30
+ # inject OpenSSL::SSL::SSLContext::DEFAULT_PARAMS
31
+ # https://bugs.ruby-lang.org/issues/9424
32
+ ctx.set_params({}) unless insecure
37
33
 
38
34
  if conf.client_cert_auth
39
35
  ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
@@ -56,6 +52,7 @@ module Fluent
56
52
  end
57
53
 
58
54
  Fluent::TLS.set_version_to_context(ctx, version, conf.min_version, conf.max_version)
55
+ ctx.ciphers = ciphers unless insecure
59
56
 
60
57
  ctx
61
58
  end
@@ -185,7 +182,7 @@ module Fluent
185
182
  list = []
186
183
  data.scan(pattern){|match| list << OpenSSL::X509::Certificate.new(match) }
187
184
  if list.length == 0
188
- log.warn "cert_path does not contain a valid certificate"
185
+ raise Fluent::ConfigError, "cert_path does not contain a valid certificate"
189
186
  end
190
187
  list
191
188
  end