fluentd 1.9.3 → 1.11.1
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/.github/workflows/issue-auto-closer.yml +12 -0
- data/CHANGELOG.md +182 -0
- 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 +25 -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/msgpack_factory.rb +13 -6
- data/lib/fluent/plugin/buffer.rb +2 -2
- data/lib/fluent/plugin/in_dummy.rb +3 -3
- 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 +146 -75
- 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 +40 -31
- 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 +25 -22
- data/lib/fluent/plugin/out_forward/handshake_protocol.rb +4 -0
- 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 +303 -62
- data/lib/fluent/plugin/sd_file.rb +1 -0
- data/lib/fluent/plugin/sd_srv.rb +135 -0
- data/lib/fluent/plugin_helper/cert_option.rb +15 -2
- data/lib/fluent/plugin_helper/child_process.rb +3 -2
- data/lib/fluent/plugin_helper/record_accessor.rb +14 -0
- data/lib/fluent/plugin_helper/server.rb +3 -1
- 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 +21 -3
- 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 +71 -12
- data/test/config/test_system_config.rb +2 -0
- data/test/helper.rb +2 -2
- data/test/plugin/in_tail/test_fifo.rb +121 -0
- data/test/plugin/in_tail/test_io_handler.rb +132 -0
- data/test/plugin/in_tail/test_position_file.rb +25 -1
- data/test/plugin/out_forward/test_handshake_protocol.rb +10 -1
- data/test/plugin/out_forward/test_load_balancer.rb +46 -0
- data/test/plugin/test_buf_file.rb +3 -1
- data/test/plugin/test_buffer.rb +20 -0
- data/test/plugin/test_compressable.rb +7 -4
- data/test/plugin/test_in_dummy.rb +12 -14
- data/test/plugin/test_in_forward.rb +2 -2
- data/test/plugin/test_in_gc_stat.rb +24 -1
- data/test/plugin/test_in_http.rb +57 -0
- data/test/plugin/test_in_syslog.rb +16 -1
- data/test/plugin/test_in_tail.rb +43 -20
- data/test/plugin/test_in_unix.rb +128 -73
- data/test/plugin/test_out_forward.rb +39 -3
- 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 +106 -46
- data/test/plugin/test_sd_file.rb +17 -0
- data/test/plugin/test_sd_srv.rb +230 -0
- data/test/plugin_helper/data/cert/cert-with-CRLF.pem +19 -0
- 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_cert_option.rb +2 -0
- data/test/plugin_helper/test_child_process.rb +20 -3
- 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
- data/test/test_msgpack_factory.rb +18 -0
- metadata +28 -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,8 +382,11 @@ 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
|
-
# Enabling SO_LINGER causes
|
386
|
-
#
|
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.
|
387
390
|
linger_timeout: Fluent.windows? ? nil : @send_timeout,
|
388
391
|
send_timeout: @send_timeout,
|
389
392
|
recv_timeout: @ack_response_timeout,
|
@@ -510,7 +513,7 @@ module Fluent::Plugin
|
|
510
513
|
|
511
514
|
class Node
|
512
515
|
extend Forwardable
|
513
|
-
def_delegators :@server, :discovery_id, :host, :port, :name, :weight, :standby
|
516
|
+
def_delegators :@server, :discovery_id, :host, :port, :name, :weight, :standby
|
514
517
|
|
515
518
|
# @param connection_manager [Fluent::Plugin::ForwardOutput::ConnectionManager]
|
516
519
|
# @param ack_handler [Fluent::Plugin::ForwardOutput::AckHandler]
|
@@ -542,8 +545,8 @@ module Fluent::Plugin
|
|
542
545
|
log: @log,
|
543
546
|
hostname: sender.security && sender.security.self_hostname,
|
544
547
|
shared_key: server.shared_key || (sender.security && sender.security.shared_key) || '',
|
545
|
-
password: server.password,
|
546
|
-
username: server.username,
|
548
|
+
password: server.password || '',
|
549
|
+
username: server.username || '',
|
547
550
|
)
|
548
551
|
|
549
552
|
@unpacker = Fluent::MessagePackFactory.msgpack_unpacker
|
@@ -580,12 +583,7 @@ module Fluent::Plugin
|
|
580
583
|
|
581
584
|
def verify_connection
|
582
585
|
connect do |sock, ri|
|
583
|
-
|
584
|
-
establish_connection(sock, ri)
|
585
|
-
if ri.state != :established
|
586
|
-
raise "Failed to establish connection to #{@host}:#{@port}"
|
587
|
-
end
|
588
|
-
end
|
586
|
+
ensure_established_connection(sock, ri)
|
589
587
|
end
|
590
588
|
end
|
591
589
|
|
@@ -654,14 +652,7 @@ module Fluent::Plugin
|
|
654
652
|
def send_data(tag, chunk)
|
655
653
|
ack = @ack_handler && @ack_handler.create_ack(chunk.unique_id, self)
|
656
654
|
connect(nil, ack: ack) do |sock, ri|
|
657
|
-
|
658
|
-
establish_connection(sock, ri)
|
659
|
-
|
660
|
-
if ri.state != :established
|
661
|
-
raise ConnectionClosedError, "failed to establish connection with node #{@name}"
|
662
|
-
end
|
663
|
-
end
|
664
|
-
|
655
|
+
ensure_established_connection(sock, ri)
|
665
656
|
send_data_actual(sock, tag, chunk)
|
666
657
|
end
|
667
658
|
|
@@ -686,7 +677,9 @@ module Fluent::Plugin
|
|
686
677
|
|
687
678
|
case @sender.heartbeat_type
|
688
679
|
when :transport
|
689
|
-
connect(dest_addr) do |
|
680
|
+
connect(dest_addr) do |sock, ri|
|
681
|
+
ensure_established_connection(sock, ri)
|
682
|
+
|
690
683
|
## don't send any data to not cause a compatibility problem
|
691
684
|
# sock.write FORWARD_TCP_HEARTBEAT_DATA
|
692
685
|
|
@@ -716,7 +709,7 @@ module Fluent::Plugin
|
|
716
709
|
@resolved_host ||= resolve_dns!
|
717
710
|
|
718
711
|
else
|
719
|
-
now = Fluent::
|
712
|
+
now = Fluent::EventTime.now
|
720
713
|
rh = @resolved_host
|
721
714
|
if !rh || now - @resolved_time >= @sender.expire_dns_cache
|
722
715
|
rh = @resolved_host = resolve_dns!
|
@@ -778,6 +771,16 @@ module Fluent::Plugin
|
|
778
771
|
|
779
772
|
private
|
780
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
|
+
|
781
784
|
def connect(host = nil, ack: false, &block)
|
782
785
|
@connection_manager.connect(host: host || resolved_host, port: port, hostname: @hostname, ack: ack, &block)
|
783
786
|
end
|
@@ -105,6 +105,10 @@ module Fluent::Plugin
|
|
105
105
|
.hexdigest
|
106
106
|
ping = ['PING', @hostname, @shared_key_salt, shared_key_hexdigest]
|
107
107
|
if !ri.auth.empty?
|
108
|
+
if @username.nil? || @password.nil?
|
109
|
+
raise PingpongError, "username and password are required"
|
110
|
+
end
|
111
|
+
|
108
112
|
password_hexdigest = Digest::SHA512.new.update(ri.auth).update(@username).update(@password).hexdigest
|
109
113
|
ping.push(@username, password_hexdigest)
|
110
114
|
else
|
@@ -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
|
|
@@ -23,6 +23,7 @@ module Fluent
|
|
23
23
|
class SyslogParser < Parser
|
24
24
|
Plugin.register_parser('syslog', self)
|
25
25
|
|
26
|
+
# TODO: Remove them since these regexps are no longer needed. but keep them for compatibility for now
|
26
27
|
# From existence TextParser pattern
|
27
28
|
REGEXP = /^(?<time>[^ ]*\s*[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[^ :\[]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$/
|
28
29
|
# From in_syslog default pattern
|
@@ -36,7 +37,16 @@ module Fluent
|
|
36
37
|
REGEXP_RFC5424_WITH_PRI = Regexp.new(<<~'EOS'.chomp % REGEXP_RFC5424, Regexp::MULTILINE)
|
37
38
|
\A<(?<pri>[0-9]{1,3})\>[1-9]\d{0,2} %s\z
|
38
39
|
EOS
|
39
|
-
|
40
|
+
|
41
|
+
REGEXP_DETECT_RFC5424 = /^\<[0-9]{1,3}\>[1-9]\d{0,2}/
|
42
|
+
|
43
|
+
RFC3164_WITHOUT_TIME_AND_PRI_REGEXP = /(?<host>[^ ]*) (?<ident>[^ :\[]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$/
|
44
|
+
RFC3164_CAPTURES = RFC3164_WITHOUT_TIME_AND_PRI_REGEXP.names.freeze
|
45
|
+
RFC3164_PRI_REGEXP = /^<(?<pri>[0-9]{1,3})>/
|
46
|
+
|
47
|
+
RFC5424_WITHOUT_TIME_AND_PRI_REGEXP = /(?<host>[!-~]{1,255}) (?<ident>[!-~]{1,48}) (?<pid>[!-~]{1,128}) (?<msgid>[!-~]{1,32}) (?<extradata>(?:\-|(?:\[.*?(?<!\\)\])+))(?: (?<message>.+))?\z/m
|
48
|
+
RFC5424_CAPTURES = RFC5424_WITHOUT_TIME_AND_PRI_REGEXP.names.freeze
|
49
|
+
RFC5424_PRI_REGEXP = /^<(?<pri>\d{1,3})>\d\d{0,2}\s/
|
40
50
|
|
41
51
|
config_set_default :time_format, "%b %d %H:%M:%S"
|
42
52
|
desc 'If the incoming logs have priority prefix, e.g. <9>, set true'
|
@@ -53,46 +63,80 @@ module Fluent
|
|
53
63
|
def initialize
|
54
64
|
super
|
55
65
|
@mutex = Mutex.new
|
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
|
73
|
+
@space_count_rfc5424 = nil
|
74
|
+
@skip_space_count_rfc3164 = false
|
75
|
+
@skip_space_count_rfc5424 = false
|
76
|
+
@time_parser_rfc5424_without_subseconds = nil
|
56
77
|
end
|
57
78
|
|
58
79
|
def configure(conf)
|
59
80
|
super
|
60
81
|
|
61
|
-
@time_parser_rfc3164 = @time_parser_rfc5424 = nil
|
62
|
-
@time_parser_rfc5424_without_subseconds = nil
|
63
|
-
@support_rfc5424_without_subseconds = false
|
64
82
|
@regexp_parser = @parser_type == :regexp
|
65
83
|
@regexp = case @message_format
|
66
84
|
when :rfc3164
|
67
85
|
if @regexp_parser
|
68
86
|
class << self
|
69
|
-
alias_method :parse, :
|
87
|
+
alias_method :parse, :parse_rfc3164_regex
|
70
88
|
end
|
71
89
|
else
|
72
90
|
class << self
|
73
91
|
alias_method :parse, :parse_rfc3164
|
74
92
|
end
|
75
93
|
end
|
76
|
-
@
|
94
|
+
setup_time_parser_3164(@time_format)
|
95
|
+
RFC3164_WITHOUT_TIME_AND_PRI_REGEXP
|
77
96
|
when :rfc5424
|
78
|
-
|
79
|
-
|
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
|
80
105
|
end
|
81
106
|
@time_format = @rfc5424_time_format unless conf.has_key?('time_format')
|
82
|
-
@
|
83
|
-
|
107
|
+
setup_time_parser_5424(@time_format)
|
108
|
+
RFC5424_WITHOUT_TIME_AND_PRI_REGEXP
|
84
109
|
when :auto
|
85
110
|
class << self
|
86
111
|
alias_method :parse, :parse_auto
|
87
112
|
end
|
88
|
-
|
89
|
-
|
113
|
+
setup_time_parser_3164(@time_format)
|
114
|
+
setup_time_parser_5424(@rfc5424_time_format)
|
90
115
|
nil
|
91
116
|
end
|
92
|
-
|
117
|
+
|
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)
|
93
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
|
94
137
|
end
|
95
138
|
|
139
|
+
# this method is for tests
|
96
140
|
def patterns
|
97
141
|
{'format' => @regexp, 'time_format' => @time_format}
|
98
142
|
end
|
@@ -102,52 +146,113 @@ module Fluent
|
|
102
146
|
end
|
103
147
|
|
104
148
|
def parse_auto(text, &block)
|
105
|
-
if REGEXP_DETECT_RFC5424.match(text)
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
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
|
110
155
|
else
|
111
|
-
@regexp = @with_priority ? REGEXP_WITH_PRI : REGEXP
|
112
|
-
@time_parser = @time_parser_rfc3164
|
113
156
|
if @regexp_parser
|
114
|
-
|
157
|
+
parse_rfc3164_regex(text, &block)
|
115
158
|
else
|
116
159
|
parse_rfc3164(text, &block)
|
117
160
|
end
|
118
161
|
end
|
119
162
|
end
|
120
163
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
164
|
+
SPLIT_CHAR = ' '.freeze
|
165
|
+
|
166
|
+
def parse_rfc3164_regex(text, &block)
|
167
|
+
idx = 0
|
168
|
+
record = {}
|
169
|
+
|
170
|
+
if @with_priority
|
171
|
+
if RFC3164_PRI_REGEXP.match?(text)
|
172
|
+
v = text.index('>')
|
173
|
+
record['pri'] = text[1..v].to_i # trim `<` and ``>
|
174
|
+
idx = v + 1
|
175
|
+
else
|
176
|
+
yield(nil, nil)
|
177
|
+
return
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
i = idx - 1
|
182
|
+
sq = false
|
183
|
+
@space_count_rfc3164.times do
|
184
|
+
while text[i + 1] == SPLIT_CHAR
|
185
|
+
sq = true
|
186
|
+
i += 1
|
187
|
+
end
|
188
|
+
|
189
|
+
i = text.index(SPLIT_CHAR, i + 1)
|
126
190
|
end
|
127
191
|
|
128
|
-
|
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) }
|
194
|
+
if @keep_time_key
|
195
|
+
record['time'] = time_str
|
196
|
+
end
|
197
|
+
|
198
|
+
parse_plain(@regexp3164, time, text, i + 1, record, RFC3164_CAPTURES, &block)
|
199
|
+
end
|
200
|
+
|
201
|
+
def parse_rfc5424_regex(text, &block)
|
202
|
+
idx = 0
|
129
203
|
record = {}
|
130
204
|
|
131
|
-
|
132
|
-
if
|
205
|
+
if @with_priority
|
206
|
+
if (m = RFC5424_PRI_REGEXP.match(text))
|
207
|
+
record['pri'] = m['pri'].to_i
|
208
|
+
idx = m.end(0)
|
209
|
+
else
|
210
|
+
yield(nil, nil)
|
211
|
+
return
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
i = idx - 1
|
216
|
+
sq = false
|
217
|
+
@space_count_rfc5424.times {
|
218
|
+
while text[i + 1] == SPLIT_CHAR
|
219
|
+
sq = true
|
220
|
+
i += 1
|
221
|
+
end
|
222
|
+
|
223
|
+
i = text.index(SPLIT_CHAR, i + 1)
|
224
|
+
}
|
225
|
+
|
226
|
+
time_str = sq ? text.slice(idx, i - idx).squeeze(SPLIT_CHAR) : text.slice(idx, i - idx)
|
227
|
+
time = @mutex.synchronize do
|
228
|
+
begin
|
229
|
+
@time_parser_rfc5424.parse(time_str)
|
230
|
+
rescue Fluent::TimeParser::TimeParseError => e
|
231
|
+
log.trace(e)
|
232
|
+
@time_parser_rfc5424_without_subseconds.parse(time_str)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
if @keep_time_key
|
237
|
+
record['time'] = time_str
|
238
|
+
end
|
239
|
+
parse_plain(@regexp5424, time, text, i + 1, record, RFC5424_CAPTURES, &block)
|
240
|
+
end
|
241
|
+
|
242
|
+
# @param time [EventTime]
|
243
|
+
# @param idx [Integer] note: this argument is needed to avoid string creation
|
244
|
+
# @param record [Hash]
|
245
|
+
# @param capture_list [Array] for performance
|
246
|
+
def parse_plain(re, time, text, idx, record, capture_list, &block)
|
247
|
+
m = re.match(text, idx)
|
248
|
+
if m.nil?
|
249
|
+
yield nil, nil
|
250
|
+
return
|
251
|
+
end
|
252
|
+
|
253
|
+
capture_list.each { |name|
|
254
|
+
if value = (m[name] rescue nil)
|
133
255
|
case name
|
134
|
-
when "pri"
|
135
|
-
record['pri'] = value.to_i
|
136
|
-
when "time"
|
137
|
-
time = @mutex.synchronize do
|
138
|
-
time_str = value.squeeze(' ')
|
139
|
-
begin
|
140
|
-
@time_parser.parse(time_str)
|
141
|
-
rescue Fluent::TimeParser::TimeParseError => e
|
142
|
-
if @support_rfc5424_without_subseconds
|
143
|
-
log.trace(e)
|
144
|
-
@time_parser_rfc5424_without_subseconds.parse(time_str)
|
145
|
-
else
|
146
|
-
raise
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
record[name] = value if @keep_time_key
|
151
256
|
when "message"
|
152
257
|
value.chomp!
|
153
258
|
record[name] = value
|
@@ -164,8 +269,6 @@ module Fluent
|
|
164
269
|
yield time, record
|
165
270
|
end
|
166
271
|
|
167
|
-
SPLIT_CHAR = ' '.freeze
|
168
|
-
|
169
272
|
def parse_rfc3164(text, &block)
|
170
273
|
pri = nil
|
171
274
|
cursor = 0
|
@@ -184,20 +287,35 @@ module Fluent
|
|
184
287
|
end
|
185
288
|
end
|
186
289
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
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
|
198
306
|
else
|
199
|
-
|
200
|
-
|
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
|
201
319
|
end
|
202
320
|
|
203
321
|
i = text.index(SPLIT_CHAR, cursor)
|
@@ -245,7 +363,130 @@ module Fluent
|
|
245
363
|
msg.chomp!
|
246
364
|
record['message'] = msg
|
247
365
|
|
248
|
-
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
|
249
490
|
record['time'] = time_str if @keep_time_key
|
250
491
|
|
251
492
|
yield time, record
|