fluentd 1.10.0-x64-mingw32 → 1.11.0-x64-mingw32

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

Potentially problematic release.


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

Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +117 -1
  3. data/CONTRIBUTING.md +1 -1
  4. data/README.md +4 -0
  5. data/docs/SECURITY_AUDIT.pdf +0 -0
  6. data/lib/fluent/command/debug.rb +1 -0
  7. data/lib/fluent/command/fluentd.rb +14 -1
  8. data/lib/fluent/config.rb +1 -0
  9. data/lib/fluent/daemonizer.rb +88 -0
  10. data/lib/fluent/log.rb +45 -6
  11. data/lib/fluent/match.rb +1 -1
  12. data/lib/fluent/plugin/in_dummy.rb +2 -2
  13. data/lib/fluent/plugin/in_forward.rb +2 -2
  14. data/lib/fluent/plugin/in_gc_stat.rb +16 -0
  15. data/lib/fluent/plugin/in_http.rb +2 -2
  16. data/lib/fluent/plugin/in_monitor_agent.rb +1 -1
  17. data/lib/fluent/plugin/in_syslog.rb +4 -4
  18. data/lib/fluent/plugin/in_tail.rb +3 -3
  19. data/lib/fluent/plugin/in_tail/position_file.rb +23 -6
  20. data/lib/fluent/plugin/in_unix.rb +77 -77
  21. data/lib/fluent/plugin/out_copy.rb +1 -1
  22. data/lib/fluent/plugin/out_file.rb +1 -1
  23. data/lib/fluent/plugin/out_forward.rb +23 -18
  24. data/lib/fluent/plugin/out_forward/load_balancer.rb +1 -1
  25. data/lib/fluent/plugin/out_http.rb +15 -2
  26. data/lib/fluent/plugin/parser_multiline.rb +1 -1
  27. data/lib/fluent/plugin/parser_syslog.rb +216 -55
  28. data/lib/fluent/plugin_helper/record_accessor.rb +14 -0
  29. data/lib/fluent/plugin_helper/service_discovery.rb +7 -0
  30. data/lib/fluent/plugin_helper/service_discovery/manager.rb +8 -0
  31. data/lib/fluent/plugin_helper/socket.rb +20 -2
  32. data/lib/fluent/plugin_helper/socket_option.rb +2 -2
  33. data/lib/fluent/supervisor.rb +21 -9
  34. data/lib/fluent/system_config.rb +2 -1
  35. data/lib/fluent/test/filter_test.rb +2 -2
  36. data/lib/fluent/test/output_test.rb +3 -3
  37. data/lib/fluent/version.rb +1 -1
  38. data/test/command/test_fluentd.rb +57 -10
  39. data/test/config/test_system_config.rb +2 -0
  40. data/test/plugin/in_tail/test_position_file.rb +24 -0
  41. data/test/plugin/out_forward/test_load_balancer.rb +46 -0
  42. data/test/plugin/test_in_gc_stat.rb +24 -1
  43. data/test/plugin/test_in_syslog.rb +16 -1
  44. data/test/plugin/test_in_tail.rb +39 -16
  45. data/test/plugin/test_in_unix.rb +128 -73
  46. data/test/plugin/test_out_forward.rb +11 -2
  47. data/test/plugin/test_out_http.rb +38 -0
  48. data/test/plugin/test_out_null.rb +1 -1
  49. data/test/plugin/test_output_as_buffered_retries.rb +12 -4
  50. data/test/plugin/test_output_as_buffered_secondary.rb +9 -1
  51. data/test/plugin/test_parser_syslog.rb +77 -29
  52. data/test/plugin_helper/data/cert/cert_chains/ca-cert-key.pem +27 -0
  53. data/test/plugin_helper/data/cert/cert_chains/ca-cert.pem +20 -0
  54. data/test/plugin_helper/data/cert/cert_chains/cert-key.pem +27 -0
  55. data/test/plugin_helper/data/cert/cert_chains/cert.pem +40 -0
  56. data/test/plugin_helper/data/cert/generate_cert.rb +38 -0
  57. data/test/plugin_helper/http_server/test_app.rb +1 -1
  58. data/test/plugin_helper/http_server/test_route.rb +1 -1
  59. data/test/plugin_helper/test_http_server_helper.rb +2 -2
  60. data/test/plugin_helper/test_record_accessor.rb +41 -0
  61. data/test/plugin_helper/test_server.rb +1 -1
  62. data/test/plugin_helper/test_service_discovery.rb +37 -4
  63. data/test/plugin_helper/test_socket.rb +131 -0
  64. data/test/test_daemonizer.rb +91 -0
  65. data/test/test_log.rb +44 -0
  66. metadata +16 -2
@@ -61,7 +61,7 @@ module Fluent::Plugin
61
61
  output.emit_events(tag, @copy_proc ? @copy_proc.call(es) : es)
62
62
  rescue => e
63
63
  if @ignore_errors[i]
64
- log.error "ignore emit error", error: e
64
+ log.error "ignore emit error in #{output.plugin_id}", error: e
65
65
  else
66
66
  raise e
67
67
  end
@@ -155,7 +155,7 @@ module Fluent::Plugin
155
155
  dummy_record_keys = get_placeholders_keys(@path_template) || ['message']
156
156
  dummy_record = Hash[dummy_record_keys.zip(['data'] * dummy_record_keys.size)]
157
157
 
158
- test_chunk1 = chunk_for_test(dummy_tag, Fluent::Engine.now, dummy_record)
158
+ test_chunk1 = chunk_for_test(dummy_tag, Fluent::EventTime.now, dummy_record)
159
159
  test_path = extract_placeholders(@path_template, test_chunk1)
160
160
  unless ::Fluent::FileUtil.writable_p?(test_path)
161
161
  raise Fluent::ConfigError, "out_file: `#{test_path}` is not writable"
@@ -324,7 +324,7 @@ module Fluent::Plugin
324
324
  end
325
325
  end
326
326
 
327
- if @keepalive && @keepalive_timeout
327
+ if @keepalive
328
328
  timer_execute(:out_forward_keep_alived_socket_watcher, @keep_alive_watcher_interval, &method(:on_purge_obsolete_socks))
329
329
  end
330
330
  end
@@ -382,7 +382,12 @@ module Fluent::Plugin
382
382
  cert_logical_store_name: @tls_cert_logical_store_name,
383
383
  cert_use_enterprise_store: @tls_cert_use_enterprise_store,
384
384
 
385
- linger_timeout: @send_timeout,
385
+ # Enabling SO_LINGER causes tcp port exhaustion on Windows.
386
+ # This is because dynamic ports are only 16384 (from 49152 to 65535) and
387
+ # expiring SO_LINGER enabled ports should wait 4 minutes
388
+ # where set by TcpTimeDelay. Its default value is 4 minutes.
389
+ # So, we should disable SO_LINGER on Windows to prevent flood of waiting ports.
390
+ linger_timeout: Fluent.windows? ? nil : @send_timeout,
386
391
  send_timeout: @send_timeout,
387
392
  recv_timeout: @ack_response_timeout,
388
393
  connect_timeout: @connect_timeout,
@@ -578,12 +583,7 @@ module Fluent::Plugin
578
583
 
579
584
  def verify_connection
580
585
  connect do |sock, ri|
581
- if ri.state != :established
582
- establish_connection(sock, ri)
583
- if ri.state != :established
584
- raise "Failed to establish connection to #{@host}:#{@port}"
585
- end
586
- end
586
+ ensure_established_connection(sock, ri)
587
587
  end
588
588
  end
589
589
 
@@ -652,14 +652,7 @@ module Fluent::Plugin
652
652
  def send_data(tag, chunk)
653
653
  ack = @ack_handler && @ack_handler.create_ack(chunk.unique_id, self)
654
654
  connect(nil, ack: ack) do |sock, ri|
655
- if ri.state != :established
656
- establish_connection(sock, ri)
657
-
658
- if ri.state != :established
659
- raise ConnectionClosedError, "failed to establish connection with node #{@name}"
660
- end
661
- end
662
-
655
+ ensure_established_connection(sock, ri)
663
656
  send_data_actual(sock, tag, chunk)
664
657
  end
665
658
 
@@ -684,7 +677,9 @@ module Fluent::Plugin
684
677
 
685
678
  case @sender.heartbeat_type
686
679
  when :transport
687
- connect(dest_addr) do |_ri, _sock|
680
+ connect(dest_addr) do |sock, ri|
681
+ ensure_established_connection(sock, ri)
682
+
688
683
  ## don't send any data to not cause a compatibility problem
689
684
  # sock.write FORWARD_TCP_HEARTBEAT_DATA
690
685
 
@@ -714,7 +709,7 @@ module Fluent::Plugin
714
709
  @resolved_host ||= resolve_dns!
715
710
 
716
711
  else
717
- now = Fluent::Engine.now
712
+ now = Fluent::EventTime.now
718
713
  rh = @resolved_host
719
714
  if !rh || now - @resolved_time >= @sender.expire_dns_cache
720
715
  rh = @resolved_host = resolve_dns!
@@ -776,6 +771,16 @@ module Fluent::Plugin
776
771
 
777
772
  private
778
773
 
774
+ def ensure_established_connection(sock, request_info)
775
+ if request_info.state != :established
776
+ establish_connection(sock, request_info)
777
+
778
+ if request_info.state != :established
779
+ raise ConnectionClosedError, "failed to establish connection with node #{@name}"
780
+ end
781
+ end
782
+ end
783
+
779
784
  def connect(host = nil, ack: false, &block)
780
785
  @connection_manager.connect(host: host || resolved_host, port: port, hostname: @hostname, ack: ack, &block)
781
786
  end
@@ -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)
@@ -175,7 +204,7 @@ module Fluent
175
204
 
176
205
  if @with_priority
177
206
  if (m = RFC5424_PRI_REGEXP.match(text))
178
- record['pri'] = m['pri']
207
+ record['pri'] = m['pri'].to_i
179
208
  idx = m.end(0)
180
209
  else
181
210
  yield(nil, nil)
@@ -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