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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +117 -1
- data/CONTRIBUTING.md +1 -1
- data/README.md +4 -0
- data/docs/SECURITY_AUDIT.pdf +0 -0
- data/lib/fluent/command/debug.rb +1 -0
- data/lib/fluent/command/fluentd.rb +14 -1
- data/lib/fluent/config.rb +1 -0
- data/lib/fluent/daemonizer.rb +88 -0
- data/lib/fluent/log.rb +45 -6
- data/lib/fluent/match.rb +1 -1
- data/lib/fluent/plugin/in_dummy.rb +2 -2
- data/lib/fluent/plugin/in_forward.rb +2 -2
- data/lib/fluent/plugin/in_gc_stat.rb +16 -0
- data/lib/fluent/plugin/in_http.rb +2 -2
- data/lib/fluent/plugin/in_monitor_agent.rb +1 -1
- data/lib/fluent/plugin/in_syslog.rb +4 -4
- data/lib/fluent/plugin/in_tail.rb +3 -3
- data/lib/fluent/plugin/in_tail/position_file.rb +23 -6
- data/lib/fluent/plugin/in_unix.rb +77 -77
- data/lib/fluent/plugin/out_copy.rb +1 -1
- data/lib/fluent/plugin/out_file.rb +1 -1
- data/lib/fluent/plugin/out_forward.rb +23 -18
- data/lib/fluent/plugin/out_forward/load_balancer.rb +1 -1
- data/lib/fluent/plugin/out_http.rb +15 -2
- data/lib/fluent/plugin/parser_multiline.rb +1 -1
- data/lib/fluent/plugin/parser_syslog.rb +216 -55
- data/lib/fluent/plugin_helper/record_accessor.rb +14 -0
- data/lib/fluent/plugin_helper/service_discovery.rb +7 -0
- data/lib/fluent/plugin_helper/service_discovery/manager.rb +8 -0
- data/lib/fluent/plugin_helper/socket.rb +20 -2
- data/lib/fluent/plugin_helper/socket_option.rb +2 -2
- data/lib/fluent/supervisor.rb +21 -9
- data/lib/fluent/system_config.rb +2 -1
- data/lib/fluent/test/filter_test.rb +2 -2
- data/lib/fluent/test/output_test.rb +3 -3
- data/lib/fluent/version.rb +1 -1
- data/test/command/test_fluentd.rb +57 -10
- data/test/config/test_system_config.rb +2 -0
- data/test/plugin/in_tail/test_position_file.rb +24 -0
- data/test/plugin/out_forward/test_load_balancer.rb +46 -0
- data/test/plugin/test_in_gc_stat.rb +24 -1
- data/test/plugin/test_in_syslog.rb +16 -1
- data/test/plugin/test_in_tail.rb +39 -16
- data/test/plugin/test_in_unix.rb +128 -73
- data/test/plugin/test_out_forward.rb +11 -2
- data/test/plugin/test_out_http.rb +38 -0
- data/test/plugin/test_out_null.rb +1 -1
- data/test/plugin/test_output_as_buffered_retries.rb +12 -4
- data/test/plugin/test_output_as_buffered_secondary.rb +9 -1
- data/test/plugin/test_parser_syslog.rb +77 -29
- data/test/plugin_helper/data/cert/cert_chains/ca-cert-key.pem +27 -0
- data/test/plugin_helper/data/cert/cert_chains/ca-cert.pem +20 -0
- data/test/plugin_helper/data/cert/cert_chains/cert-key.pem +27 -0
- data/test/plugin_helper/data/cert/cert_chains/cert.pem +40 -0
- data/test/plugin_helper/data/cert/generate_cert.rb +38 -0
- data/test/plugin_helper/http_server/test_app.rb +1 -1
- data/test/plugin_helper/http_server/test_route.rb +1 -1
- data/test/plugin_helper/test_http_server_helper.rb +2 -2
- data/test/plugin_helper/test_record_accessor.rb +41 -0
- data/test/plugin_helper/test_server.rb +1 -1
- data/test/plugin_helper/test_service_discovery.rb +37 -4
- data/test/plugin_helper/test_socket.rb +131 -0
- data/test/test_daemonizer.rb +91 -0
- data/test/test_log.rb +44 -0
- 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::
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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 |
|
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::
|
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
|
@@ -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
|
|
@@ -63,16 +63,22 @@ module Fluent
|
|
63
63
|
def initialize
|
64
64
|
super
|
65
65
|
@mutex = Mutex.new
|
66
|
-
@
|
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
|
-
|
91
|
-
|
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
|
-
@
|
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
|
-
|
101
|
-
|
113
|
+
setup_time_parser_3164(@time_format)
|
114
|
+
setup_time_parser_5424(@rfc5424_time_format)
|
102
115
|
nil
|
103
116
|
end
|
104
117
|
|
105
|
-
|
106
|
-
|
107
|
-
|
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
|
-
@
|
123
|
-
|
124
|
-
|
125
|
-
|
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
|
-
@
|
155
|
-
while text[i + 1] ==
|
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(
|
189
|
+
i = text.index(SPLIT_CHAR, i + 1)
|
161
190
|
end
|
162
191
|
|
163
|
-
time_str = sq ? text.slice(idx, i - idx).squeeze(
|
164
|
-
time = @mutex.synchronize { @
|
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] ==
|
218
|
+
while text[i + 1] == SPLIT_CHAR
|
190
219
|
sq = true
|
191
220
|
i += 1
|
192
221
|
end
|
193
222
|
|
194
|
-
i = text.index(
|
223
|
+
i = text.index(SPLIT_CHAR, i + 1)
|
195
224
|
}
|
196
225
|
|
197
|
-
time_str = sq ? text.slice(idx, i - idx).squeeze(
|
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
|
-
@
|
229
|
+
@time_parser_rfc5424.parse(time_str)
|
201
230
|
rescue Fluent::TimeParser::TimeParseError => e
|
202
|
-
|
203
|
-
|
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 =
|
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
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
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
|
-
|
280
|
-
|
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 = @
|
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
|