fluentd 1.19.2 → 1.19.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +81 -0
- data/Rakefile +7 -0
- data/lib/fluent/command/cat.rb +1 -1
- data/lib/fluent/config/basic_parser.rb +0 -1
- data/lib/fluent/config/literal_parser.rb +18 -7
- data/lib/fluent/config/types.rb +10 -2
- data/lib/fluent/configurable.rb +1 -0
- data/lib/fluent/daemon.rb +2 -1
- data/lib/fluent/engine.rb +1 -1
- data/lib/fluent/env.rb +1 -0
- data/lib/fluent/event.rb +2 -1
- data/lib/fluent/plugin/base.rb +7 -2
- data/lib/fluent/plugin/buf_file.rb +4 -4
- data/lib/fluent/plugin/buf_file_single.rb +2 -2
- data/lib/fluent/plugin/buf_memory.rb +1 -1
- data/lib/fluent/plugin/buffer/chunk.rb +16 -7
- data/lib/fluent/plugin/buffer/file_chunk.rb +7 -5
- data/lib/fluent/plugin/buffer/file_single_chunk.rb +7 -5
- data/lib/fluent/plugin/buffer/memory_chunk.rb +1 -1
- data/lib/fluent/plugin/buffer.rb +26 -5
- data/lib/fluent/plugin/compressable.rb +7 -62
- data/lib/fluent/plugin/extractor.rb +132 -0
- data/lib/fluent/plugin/filter_record_transformer.rb +2 -1
- data/lib/fluent/plugin/in_debug_agent.rb +1 -1
- data/lib/fluent/plugin/in_forward.rb +3 -1
- data/lib/fluent/plugin/in_http.rb +91 -6
- data/lib/fluent/plugin/in_monitor_agent.rb +21 -23
- data/lib/fluent/plugin/in_sample.rb +2 -1
- data/lib/fluent/plugin/in_syslog.rb +70 -4
- data/lib/fluent/plugin/out_file.rb +10 -0
- data/lib/fluent/plugin/out_forward/connection_manager.rb +18 -0
- data/lib/fluent/plugin/out_forward/socket_cache.rb +45 -10
- data/lib/fluent/plugin/out_forward.rb +13 -2
- data/lib/fluent/plugin/out_http.rb +31 -1
- data/lib/fluent/plugin/output.rb +69 -5
- data/lib/fluent/plugin/parser_csv.rb +5 -0
- data/lib/fluent/plugin/parser_json.rb +6 -1
- data/lib/fluent/plugin/parser_syslog.rb +3 -3
- data/lib/fluent/plugin/sd_file.rb +2 -1
- data/lib/fluent/plugin/storage_local.rb +4 -4
- data/lib/fluent/supervisor.rb +22 -1
- data/lib/fluent/test/base.rb +5 -0
- data/lib/fluent/version.rb +1 -1
- metadata +3 -3
- data/.deepsource.toml +0 -13
|
@@ -31,20 +31,26 @@ module Fluent::Plugin
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def checkout_or(key)
|
|
34
|
+
obsolete_sockets = []
|
|
35
|
+
|
|
34
36
|
@mutex.synchronize do
|
|
35
|
-
tsock = pick_socket(key)
|
|
37
|
+
tsock, obsolete_sockets = pick_socket(key)
|
|
36
38
|
|
|
37
39
|
if tsock
|
|
38
|
-
tsock.sock
|
|
40
|
+
return tsock.sock
|
|
39
41
|
else
|
|
40
42
|
sock = yield
|
|
41
43
|
new_tsock = TimedSocket.new(timeout, key, sock)
|
|
42
44
|
@log.debug("connect new socket #{new_tsock}")
|
|
43
45
|
|
|
44
46
|
@inflight_sockets[sock] = new_tsock
|
|
45
|
-
new_tsock.sock
|
|
47
|
+
return new_tsock.sock
|
|
46
48
|
end
|
|
47
49
|
end
|
|
50
|
+
ensure
|
|
51
|
+
obsolete_sockets.each do |sock|
|
|
52
|
+
sock.sock.close rescue nil
|
|
53
|
+
end
|
|
48
54
|
end
|
|
49
55
|
|
|
50
56
|
def checkin(sock)
|
|
@@ -117,17 +123,32 @@ module Fluent::Plugin
|
|
|
117
123
|
# this method is not thread safe
|
|
118
124
|
def pick_socket(key)
|
|
119
125
|
if @available_sockets[key].empty?
|
|
120
|
-
return nil
|
|
126
|
+
return nil, []
|
|
121
127
|
end
|
|
122
128
|
|
|
123
129
|
t = Time.now
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
+
selected = nil
|
|
131
|
+
remaining = []
|
|
132
|
+
obsolete_sockets = []
|
|
133
|
+
|
|
134
|
+
@available_sockets[key].each do |sock|
|
|
135
|
+
if expired_socket?(sock, time: t) || unavailable_socket?(sock.sock)
|
|
136
|
+
obsolete_sockets << sock
|
|
137
|
+
elsif selected.nil?
|
|
138
|
+
selected = sock
|
|
139
|
+
else
|
|
140
|
+
remaining << sock
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
@available_sockets[key] = remaining
|
|
145
|
+
|
|
146
|
+
if selected
|
|
147
|
+
@inflight_sockets[selected.sock] = selected
|
|
148
|
+
selected.timeout = timeout
|
|
130
149
|
end
|
|
150
|
+
|
|
151
|
+
[selected, obsolete_sockets]
|
|
131
152
|
end
|
|
132
153
|
|
|
133
154
|
def timeout
|
|
@@ -137,6 +158,20 @@ module Fluent::Plugin
|
|
|
137
158
|
def expired_socket?(sock, time: Time.now)
|
|
138
159
|
sock.timeout ? sock.timeout < time : false
|
|
139
160
|
end
|
|
161
|
+
|
|
162
|
+
def unavailable_socket?(sock)
|
|
163
|
+
return sock.closed? if sock.respond_to?(:closed?) && sock.closed?
|
|
164
|
+
|
|
165
|
+
io = if sock.respond_to?(:to_io)
|
|
166
|
+
sock.to_io
|
|
167
|
+
elsif sock.is_a?(IO)
|
|
168
|
+
sock
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
io ? !!IO.select([io], nil, nil, 0) : false
|
|
172
|
+
rescue IOError, SystemCallError
|
|
173
|
+
true
|
|
174
|
+
end
|
|
140
175
|
end
|
|
141
176
|
end
|
|
142
177
|
end
|
|
@@ -525,17 +525,28 @@ module Fluent::Plugin
|
|
|
525
525
|
|
|
526
526
|
def ack_check(select_interval)
|
|
527
527
|
@ack_handler.collect_response(select_interval) do |chunk_id, node, sock, result|
|
|
528
|
-
@connection_manager.close(sock)
|
|
529
|
-
|
|
530
528
|
case result
|
|
531
529
|
when AckHandler::Result::SUCCESS
|
|
530
|
+
@connection_manager.close(sock)
|
|
532
531
|
commit_write(chunk_id)
|
|
533
532
|
when AckHandler::Result::FAILED
|
|
533
|
+
# The ack timed out or the peer closed the connection. A keepalive
|
|
534
|
+
# socket may still have an in-flight ack for this chunk, so drop it
|
|
535
|
+
# instead of returning it to the reuse pool; otherwise a late ack
|
|
536
|
+
# could later be read against a chunk sent on the reused socket (#4057).
|
|
537
|
+
@connection_manager.discard(sock)
|
|
534
538
|
node&.disable!
|
|
535
539
|
rollback_write(chunk_id, update_retry: false) if chunk_id
|
|
536
540
|
when AckHandler::Result::CHUNKID_UNMATCHED
|
|
541
|
+
# The ack read from this socket belongs to a different chunk than the
|
|
542
|
+
# one tracked for it: the keepalive connection's ack stream is out of
|
|
543
|
+
# sync (e.g. a stale ack left over from before an aggregator restart).
|
|
544
|
+
# Discard the socket so the following acks are not each offset by one,
|
|
545
|
+
# which would otherwise flood the log with mismatch warnings (#4057).
|
|
546
|
+
@connection_manager.discard(sock)
|
|
537
547
|
rollback_write(chunk_id, update_retry: false)
|
|
538
548
|
else
|
|
549
|
+
@connection_manager.close(sock)
|
|
539
550
|
log.warn("BUG: invalid status #{result} #{chunk_id}")
|
|
540
551
|
|
|
541
552
|
if chunk_id
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
require 'net/http'
|
|
18
18
|
require 'uri'
|
|
19
19
|
require 'openssl'
|
|
20
|
+
require 'securerandom'
|
|
20
21
|
require 'fluent/tls'
|
|
21
22
|
require 'fluent/plugin/output'
|
|
22
23
|
require 'fluent/plugin_helper/socket'
|
|
@@ -58,6 +59,9 @@ module Fluent::Plugin
|
|
|
58
59
|
desc 'Compress HTTP request body'
|
|
59
60
|
config_param :compress, :enum, list: [:text, :gzip], default: :text
|
|
60
61
|
|
|
62
|
+
desc 'Allowed hosts list for dynamic endpoints'
|
|
63
|
+
config_param :allowed_hosts, :array, default: []
|
|
64
|
+
|
|
61
65
|
desc 'The connection open timeout in seconds'
|
|
62
66
|
config_param :open_timeout, :integer, default: nil
|
|
63
67
|
desc 'The read timeout in seconds'
|
|
@@ -106,6 +110,11 @@ module Fluent::Plugin
|
|
|
106
110
|
config_param :aws_role_arn, :string, default: nil
|
|
107
111
|
end
|
|
108
112
|
|
|
113
|
+
# To prevent URI::InvalidURIError, we replace Fluentd placeholders with a dummy string.
|
|
114
|
+
# We use the ".invalid" TLD (RFC 2606) to ensure it is RFC-compliant for URI parsing,
|
|
115
|
+
# while guaranteeing it will never conflict with a real-world hostname.
|
|
116
|
+
REPLACED_ENDPOINT_PLACEHOLDER = "#{SecureRandom.uuid}.invalid".freeze
|
|
117
|
+
|
|
109
118
|
def connection_cache_id_thread_key
|
|
110
119
|
"#{plugin_id}_connection_cache_id"
|
|
111
120
|
end
|
|
@@ -146,6 +155,15 @@ module Fluent::Plugin
|
|
|
146
155
|
@retryable_response_codes = [503]
|
|
147
156
|
end
|
|
148
157
|
|
|
158
|
+
begin
|
|
159
|
+
# Replace all Fluentd placeholder syntaxes (${...} or %{...})
|
|
160
|
+
endpoint = @endpoint.gsub(%r([$%]{[^}]+}), REPLACED_ENDPOINT_PLACEHOLDER)
|
|
161
|
+
# If @endpoint has placeholder as host name, then, @endpoint_host == REPLACED_ENDPOINT_PLACEHOLDER
|
|
162
|
+
@endpoint_host = URI.parse(endpoint).host
|
|
163
|
+
rescue URI::InvalidURIError => e
|
|
164
|
+
raise Fluent::ConfigError, "Invalid endpoint URI: #{@endpoint} (#{e.message})"
|
|
165
|
+
end
|
|
166
|
+
|
|
149
167
|
@http_opt = setup_http_option
|
|
150
168
|
@proxy_uri = URI.parse(@proxy) if @proxy
|
|
151
169
|
@formatter = formatter_create
|
|
@@ -278,7 +296,19 @@ module Fluent::Plugin
|
|
|
278
296
|
|
|
279
297
|
def parse_endpoint(chunk)
|
|
280
298
|
endpoint = extract_placeholders(@endpoint, chunk)
|
|
281
|
-
URI.parse(endpoint)
|
|
299
|
+
uri = URI.parse(endpoint)
|
|
300
|
+
|
|
301
|
+
if @endpoint_host != uri.host
|
|
302
|
+
if @allowed_hosts.empty?
|
|
303
|
+
raise Fluent::UnrecoverableError, "allowed_hosts is strictly required when using placeholders in the endpoint host"
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
unless @allowed_hosts.include?(uri.host)
|
|
307
|
+
raise Fluent::UnrecoverableError, "Not allowed host: #{uri.host}"
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
uri
|
|
282
312
|
end
|
|
283
313
|
|
|
284
314
|
def set_headers(req, uri, chunk)
|
data/lib/fluent/plugin/output.rb
CHANGED
|
@@ -28,6 +28,7 @@ require 'fluent/unique_id'
|
|
|
28
28
|
require 'fluent/clock'
|
|
29
29
|
require 'fluent/ext_monitor_require'
|
|
30
30
|
|
|
31
|
+
require 'json'
|
|
31
32
|
require 'time'
|
|
32
33
|
|
|
33
34
|
module Fluent
|
|
@@ -45,6 +46,21 @@ module Fluent
|
|
|
45
46
|
CHUNK_TAG_PLACEHOLDER_PATTERN = /\$\{(tag(?:\[-?\d+\])?)\}/
|
|
46
47
|
CHUNK_ID_PLACEHOLDER_PATTERN = /\$\{chunk_id\}/
|
|
47
48
|
|
|
49
|
+
# Matches absolute paths, including the POSIX root, Windows drive roots, and UNC paths (e.g., \\host\share).
|
|
50
|
+
# It also accounts for forward slashes used as directory separators in Windows.
|
|
51
|
+
ABSOLUTE_PATH_PATTERN = %r{\A[/\\]}
|
|
52
|
+
# Matches Windows drive specifications.
|
|
53
|
+
# A trailing separator after the colon is not required, because a drive-relative path like C:Windows can still escape a relative path template.
|
|
54
|
+
WINDOWS_DRIVE_PATTERN = %r{\A[a-zA-Z]:}
|
|
55
|
+
# Matches .. only when it acts as an independent path component (e.g., ../etc or foo/..),
|
|
56
|
+
# ignoring dots embedded within strings like app..web or a..b/c.
|
|
57
|
+
# It uses zero-width negative lookarounds to avoid consuming characters.
|
|
58
|
+
# This ensures that adjacent components like /a/../../b are accurately detected and counted without missing any.
|
|
59
|
+
PARENT_DIRECTORY_PATTERN = %r{(?<![^/\\])\.\.(?![^/\\])}
|
|
60
|
+
|
|
61
|
+
INVALID_PATH_COMPONENT_PATTERN =
|
|
62
|
+
Regexp.union(ABSOLUTE_PATH_PATTERN, WINDOWS_DRIVE_PATTERN, PARENT_DIRECTORY_PATTERN)
|
|
63
|
+
|
|
48
64
|
CHUNKING_FIELD_WARN_NUM = 4
|
|
49
65
|
|
|
50
66
|
config_param :time_as_integer, :bool, default: false
|
|
@@ -372,6 +388,13 @@ module Fluent
|
|
|
372
388
|
buf_type = Plugin.lookup_type_from_class(@buffer.class)
|
|
373
389
|
log.warn "'flush_at_shutdown' is false, and buffer plugin '#{buf_type}' is not persistent buffer."
|
|
374
390
|
log.warn "your configuration will lose buffered data at shutdown. please confirm your configuration again."
|
|
391
|
+
else
|
|
392
|
+
if Fluent.windows? && @buffer.persistent?
|
|
393
|
+
service_timeout = read_wait_to_kill_service_timeout
|
|
394
|
+
if service_timeout && service_timeout <= 5000 # default value might varies on windows client/server
|
|
395
|
+
log.warn "your WaitToKillServiceTimeout=#{service_timeout} registry configuration seems too short. Recommend to extend the value of 'HKLM\\SYSTEM\\CurrentControlSet\\Control\\WaitToKillServiceTimeout' to prevent buffer corruption from a forced shutdown"
|
|
396
|
+
end
|
|
397
|
+
end
|
|
375
398
|
end
|
|
376
399
|
|
|
377
400
|
if (@flush_mode != :interval) && buffer_conf.has_key?('flush_interval')
|
|
@@ -418,6 +441,22 @@ module Fluent
|
|
|
418
441
|
self
|
|
419
442
|
end
|
|
420
443
|
|
|
444
|
+
def read_wait_to_kill_service_timeout
|
|
445
|
+
if Fluent.windows?
|
|
446
|
+
begin
|
|
447
|
+
require "win32/registry"
|
|
448
|
+
Win32::Registry::HKEY_LOCAL_MACHINE.open("SYSTEM\\CurrentControlSet\\Control",
|
|
449
|
+
Win32::Registry::KEY_READ) do |reg|
|
|
450
|
+
reg["WaitToKillServiceTimeout"].to_i
|
|
451
|
+
end
|
|
452
|
+
rescue => e
|
|
453
|
+
log.warn "'flush_at_shutdown' is true, but can't check WaitToKillServiceTimeout registry configuration", error: e
|
|
454
|
+
end
|
|
455
|
+
else
|
|
456
|
+
nil # not supported
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
|
|
421
460
|
def keep_buffer_config_compat
|
|
422
461
|
# Need this to call `@buffer_config.disable_chunk_backup` just as before,
|
|
423
462
|
# since some plugins may use this option in this way.
|
|
@@ -802,9 +841,17 @@ module Fluent
|
|
|
802
841
|
# ${tag}, ${tag[0]}, ${tag[1]}, ... , ${tag[-2]}, ${tag[-1]}
|
|
803
842
|
if @chunk_key_tag
|
|
804
843
|
if str.include?('${tag}')
|
|
844
|
+
if metadata.tag.match?(INVALID_PATH_COMPONENT_PATTERN)
|
|
845
|
+
raise Fluent::UnrecoverableError, "Invalid path component detected in tag: #{metadata.tag}"
|
|
846
|
+
end
|
|
847
|
+
|
|
805
848
|
rvalue = rvalue.gsub('${tag}', metadata.tag)
|
|
806
849
|
end
|
|
807
850
|
if CHUNK_TAG_PLACEHOLDER_PATTERN.match?(str)
|
|
851
|
+
if metadata.tag.match?(INVALID_PATH_COMPONENT_PATTERN)
|
|
852
|
+
raise Fluent::UnrecoverableError, "Invalid path component detected in tag: #{metadata.tag}"
|
|
853
|
+
end
|
|
854
|
+
|
|
808
855
|
hash = {}
|
|
809
856
|
tag_parts = metadata.tag.split('.')
|
|
810
857
|
tag_parts.each_with_index do |part, i|
|
|
@@ -835,13 +882,25 @@ module Fluent
|
|
|
835
882
|
end
|
|
836
883
|
|
|
837
884
|
rvalue = rvalue.gsub(CHUNK_KEY_PLACEHOLDER_PATTERN) do |matched|
|
|
838
|
-
hash.fetch(matched) do
|
|
885
|
+
replace = hash.fetch(matched) do
|
|
839
886
|
log.warn "chunk key placeholder '#{matched[2..-2]}' not replaced. template:#{str}"
|
|
840
887
|
''
|
|
841
888
|
end
|
|
889
|
+
if replace.to_s.match?(INVALID_PATH_COMPONENT_PATTERN)
|
|
890
|
+
raise Fluent::UnrecoverableError, "Invalid path component detected in #{matched}: #{replace}"
|
|
891
|
+
end
|
|
892
|
+
|
|
893
|
+
replace
|
|
842
894
|
end
|
|
843
895
|
end
|
|
844
896
|
|
|
897
|
+
# Verifies that the number of parent directory traversals (..) has not increased after variable substitution.
|
|
898
|
+
# While each replaced value is validated individually, this step prevents harmless values from concatenating into a dangerous path (e.g., ${tag}${key}/ becoming ../ if both tag and key are .).
|
|
899
|
+
if rvalue.match?(PARENT_DIRECTORY_PATTERN) &&
|
|
900
|
+
rvalue.scan(PARENT_DIRECTORY_PATTERN).size > str.scan(PARENT_DIRECTORY_PATTERN).size
|
|
901
|
+
raise Fluent::UnrecoverableError, "Invalid path component detected, replaced to: #{rvalue}"
|
|
902
|
+
end
|
|
903
|
+
|
|
845
904
|
if rvalue =~ CHUNK_KEY_PLACEHOLDER_PATTERN
|
|
846
905
|
log.warn "chunk key placeholder '#{$1}' not replaced. template:#{str}"
|
|
847
906
|
end
|
|
@@ -1168,7 +1227,7 @@ module Fluent
|
|
|
1168
1227
|
end
|
|
1169
1228
|
end
|
|
1170
1229
|
|
|
1171
|
-
UNRECOVERABLE_ERRORS = [Fluent::UnrecoverableError, TypeError, ArgumentError, NoMethodError, MessagePack::UnpackError, EncodingError]
|
|
1230
|
+
UNRECOVERABLE_ERRORS = [Fluent::UnrecoverableError, TypeError, ArgumentError, NoMethodError, MessagePack::UnpackError, EncodingError, JSON::GeneratorError]
|
|
1172
1231
|
|
|
1173
1232
|
def try_flush
|
|
1174
1233
|
chunk = @buffer.dequeue_chunk
|
|
@@ -1275,9 +1334,14 @@ module Fluent
|
|
|
1275
1334
|
if @buffer.disable_chunk_backup
|
|
1276
1335
|
log.warn "disable_chunk_backup is true. #{dump_unique_id_hex(chunk.unique_id)} chunk is thrown away"
|
|
1277
1336
|
else
|
|
1278
|
-
|
|
1279
|
-
chunk.
|
|
1280
|
-
|
|
1337
|
+
begin
|
|
1338
|
+
@buffer.backup(chunk.unique_id) { |f|
|
|
1339
|
+
chunk.write_to(f)
|
|
1340
|
+
}
|
|
1341
|
+
rescue => e
|
|
1342
|
+
log.warn "failed to back up #{dump_unique_id_hex(chunk.unique_id)} chunk. it is thrown away", error: e
|
|
1343
|
+
log.warn_backtrace
|
|
1344
|
+
end
|
|
1281
1345
|
end
|
|
1282
1346
|
commit_write(chunk.unique_id, secondary: using_secondary, delayed: delayed_commit)
|
|
1283
1347
|
end
|
|
@@ -47,6 +47,11 @@ module Fluent
|
|
|
47
47
|
|
|
48
48
|
def parse(text, &block)
|
|
49
49
|
values = CSV.parse_line(text, col_sep: @delimiter)
|
|
50
|
+
unless values
|
|
51
|
+
yield nil, nil
|
|
52
|
+
return
|
|
53
|
+
end
|
|
54
|
+
|
|
50
55
|
r = Hash[@keys.zip(values)]
|
|
51
56
|
time, record = convert_values(parse_time(r), r)
|
|
52
57
|
yield time, record
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
#
|
|
16
16
|
|
|
17
|
+
require 'fluent/env'
|
|
17
18
|
require 'fluent/plugin/parser'
|
|
18
19
|
require 'fluent/time'
|
|
19
20
|
require 'fluent/oj_options'
|
|
@@ -38,6 +39,10 @@ module Fluent
|
|
|
38
39
|
|
|
39
40
|
config_set_default :time_type, :float
|
|
40
41
|
|
|
42
|
+
# Use a shared proc rather than a per-call lambda so that
|
|
43
|
+
# configure_json_parser returns the same object every time.
|
|
44
|
+
JSON_PARSE_PROC = ->(text) { JSON.parse(text, **Fluent::DEFAULT_JSON_PARSE_OPTIONS) }
|
|
45
|
+
|
|
41
46
|
def configure(conf)
|
|
42
47
|
if conf.has_key?('time_format')
|
|
43
48
|
conf['time_type'] ||= 'string'
|
|
@@ -54,7 +59,7 @@ module Fluent
|
|
|
54
59
|
|
|
55
60
|
log&.info "Oj is not installed, and failing back to JSON for json parser"
|
|
56
61
|
configure_json_parser(:json)
|
|
57
|
-
when :json then [
|
|
62
|
+
when :json then [JSON_PARSE_PROC, JSON::ParserError]
|
|
58
63
|
when :yajl then [Yajl.method(:load), Yajl::ParseError]
|
|
59
64
|
else
|
|
60
65
|
raise "BUG: unknown json parser specified: #{name}"
|
|
@@ -44,7 +44,7 @@ module Fluent
|
|
|
44
44
|
RFC3164_CAPTURES = RFC3164_WITHOUT_TIME_AND_PRI_REGEXP.names.freeze
|
|
45
45
|
RFC3164_PRI_REGEXP = /^<(?<pri>[0-9]{1,3})>/
|
|
46
46
|
|
|
47
|
-
RFC5424_WITHOUT_TIME_AND_PRI_REGEXP = /(?<host>[!-~]{1,255}) (?<ident>[!-~]{1,48}) (?<pid>[!-~]{1,128}) (?<msgid>[!-~]{1,32}) (?<extradata>(?:\-|(?:\[.*?(?<!\\)\])
|
|
47
|
+
RFC5424_WITHOUT_TIME_AND_PRI_REGEXP = /(?<host>[!-~]{1,255}) (?<ident>[!-~]{1,48}) (?<pid>[!-~]{1,128}) (?<msgid>[!-~]{1,32}) (?<extradata>(?:\-|(?:\[.*?(?<!\\)\])))(?: (?<message>.+))?\z/m
|
|
48
48
|
RFC5424_CAPTURES = RFC5424_WITHOUT_TIME_AND_PRI_REGEXP.names.freeze
|
|
49
49
|
RFC5424_PRI_REGEXP = /^<(?<pri>\d{1,3})>\d\d{0,2}\s/
|
|
50
50
|
|
|
@@ -314,7 +314,7 @@ module Fluent
|
|
|
314
314
|
i = text.index(SPLIT_CHAR, i + 1)
|
|
315
315
|
end
|
|
316
316
|
|
|
317
|
-
time_str = sq ? text.slice(
|
|
317
|
+
time_str = sq ? text.slice(cursor, i - cursor).squeeze(SPLIT_CHAR) : text.slice(cursor, i - cursor)
|
|
318
318
|
cursor = i + 1
|
|
319
319
|
end
|
|
320
320
|
|
|
@@ -406,7 +406,7 @@ module Fluent
|
|
|
406
406
|
i = text.index(SPLIT_CHAR, i + 1)
|
|
407
407
|
end
|
|
408
408
|
|
|
409
|
-
time_str = sq ? text.slice(
|
|
409
|
+
time_str = sq ? text.slice(cursor, i - cursor).squeeze(SPLIT_CHAR) : text.slice(cursor, i - cursor)
|
|
410
410
|
cursor = i + 1
|
|
411
411
|
end
|
|
412
412
|
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
require 'cool.io'
|
|
18
18
|
|
|
19
|
+
require 'fluent/env'
|
|
19
20
|
require 'fluent/plugin_helper'
|
|
20
21
|
require 'fluent/plugin/service_discovery'
|
|
21
22
|
|
|
@@ -75,7 +76,7 @@ module Fluent
|
|
|
75
76
|
-> (v) { YAML.safe_load(v).map }
|
|
76
77
|
when :json
|
|
77
78
|
require 'json'
|
|
78
|
-
-> (v) { JSON.parse(v) }
|
|
79
|
+
-> (v) { JSON.parse(v, **Fluent::DEFAULT_JSON_PARSE_OPTIONS) }
|
|
79
80
|
end
|
|
80
81
|
end
|
|
81
82
|
|
|
@@ -85,12 +85,12 @@ module Fluent
|
|
|
85
85
|
if File.exist?(@path)
|
|
86
86
|
raise Fluent::ConfigError, "Plugin storage path '#{@path}' is not readable/writable" unless File.readable?(@path) && File.writable?(@path)
|
|
87
87
|
begin
|
|
88
|
-
data = File.open(@path, 'r:utf-8') { |io| io.read }
|
|
88
|
+
data = File.open(@path, 'r:utf-8:utf-8') { |io| io.read }
|
|
89
89
|
if data.empty?
|
|
90
90
|
log.warn "detect empty plugin storage file during startup. Ignored: #{@path}"
|
|
91
91
|
return
|
|
92
92
|
end
|
|
93
|
-
data = JSON.parse(data)
|
|
93
|
+
data = JSON.parse(data, **Fluent::DEFAULT_JSON_PARSE_OPTIONS)
|
|
94
94
|
raise Fluent::ConfigError, "Invalid contents (not object) in plugin storage file: '#{@path}'" unless data.is_a?(Hash)
|
|
95
95
|
rescue => e
|
|
96
96
|
log.error "failed to read data from plugin storage file", path: @path, error: e
|
|
@@ -113,8 +113,8 @@ module Fluent
|
|
|
113
113
|
return if @on_memory
|
|
114
114
|
return unless File.exist?(@path)
|
|
115
115
|
begin
|
|
116
|
-
json_string = File.open(@path, 'r:utf-8'){ |io| io.read }
|
|
117
|
-
json = JSON.parse(json_string)
|
|
116
|
+
json_string = File.open(@path, 'r:utf-8:utf-8'){ |io| io.read }
|
|
117
|
+
json = JSON.parse(json_string, **Fluent::DEFAULT_JSON_PARSE_OPTIONS)
|
|
118
118
|
unless json.is_a?(Hash)
|
|
119
119
|
log.error "broken content for plugin storage (Hash required: ignored)", type: json.class
|
|
120
120
|
log.debug "broken content", content: json_string
|
data/lib/fluent/supervisor.rb
CHANGED
|
@@ -100,7 +100,14 @@ module Fluent
|
|
|
100
100
|
end
|
|
101
101
|
|
|
102
102
|
def cleanup_lock_dir
|
|
103
|
-
|
|
103
|
+
begin
|
|
104
|
+
Dir.each_child(@fluentd_lock_dir) do |name|
|
|
105
|
+
FileUtils.rm_f(File.join(@fluentd_lock_dir, name)) if File.fnmatch?("fluentd-*.lock", name)
|
|
106
|
+
end
|
|
107
|
+
rescue Errno::ENOENT
|
|
108
|
+
# Directory is already missing. Fall through and let rmdir below
|
|
109
|
+
# fail in the same way as the current implementation.
|
|
110
|
+
end
|
|
104
111
|
FileUtils.rmdir(@fluentd_lock_dir)
|
|
105
112
|
end
|
|
106
113
|
|
|
@@ -814,6 +821,20 @@ module Fluent
|
|
|
814
821
|
@conf += additional_conf
|
|
815
822
|
end
|
|
816
823
|
|
|
824
|
+
if Fluent.windows?
|
|
825
|
+
@conf.elements.each do |element|
|
|
826
|
+
next unless element.name == 'source'
|
|
827
|
+
if element['@type'] == 'tail' && element['pos_file']
|
|
828
|
+
$log.warn("Recommend adding #{File.dirname(element['pos_file'])} to the exclusion path of your antivirus software on Windows")
|
|
829
|
+
else
|
|
830
|
+
storage = element.elements.find { |v| v.name == 'storage' and v['@type'] == 'local' }
|
|
831
|
+
if storage
|
|
832
|
+
$log.warn("Recommend adding #{File.dirname(storage['path'])} to the exclusion path of your antivirus software on Windows")
|
|
833
|
+
end
|
|
834
|
+
end
|
|
835
|
+
end
|
|
836
|
+
end
|
|
837
|
+
|
|
817
838
|
@libs.each do |lib|
|
|
818
839
|
require lib
|
|
819
840
|
end
|
data/lib/fluent/test/base.rb
CHANGED
data/lib/fluent/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fluentd
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.19.
|
|
4
|
+
version: 1.19.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sadayuki Furuhashi
|
|
@@ -531,7 +531,6 @@ executables:
|
|
|
531
531
|
extensions: []
|
|
532
532
|
extra_rdoc_files: []
|
|
533
533
|
files:
|
|
534
|
-
- ".deepsource.toml"
|
|
535
534
|
- ".rubocop.yml"
|
|
536
535
|
- ADOPTERS.md
|
|
537
536
|
- AUTHORS
|
|
@@ -691,6 +690,7 @@ files:
|
|
|
691
690
|
- lib/fluent/plugin/buffer/memory_chunk.rb
|
|
692
691
|
- lib/fluent/plugin/compressable.rb
|
|
693
692
|
- lib/fluent/plugin/exec_util.rb
|
|
693
|
+
- lib/fluent/plugin/extractor.rb
|
|
694
694
|
- lib/fluent/plugin/file_util.rb
|
|
695
695
|
- lib/fluent/plugin/filter.rb
|
|
696
696
|
- lib/fluent/plugin/filter_grep.rb
|
|
@@ -883,7 +883,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
883
883
|
- !ruby/object:Gem::Version
|
|
884
884
|
version: '0'
|
|
885
885
|
requirements: []
|
|
886
|
-
rubygems_version:
|
|
886
|
+
rubygems_version: 4.0.20
|
|
887
887
|
specification_version: 4
|
|
888
888
|
summary: Fluentd event collector
|
|
889
889
|
test_files: []
|