fluentd 1.15.3-x86-mingw32 → 1.16.2-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.yaml +1 -0
- data/.github/ISSUE_TEMPLATE/feature_request.yaml +1 -0
- data/.github/workflows/linux-test.yaml +2 -2
- data/.github/workflows/macos-test.yaml +2 -2
- data/.github/workflows/stale-actions.yml +24 -0
- data/.github/workflows/windows-test.yaml +2 -2
- data/CHANGELOG.md +151 -0
- data/CONTRIBUTING.md +1 -1
- data/MAINTAINERS.md +5 -3
- data/README.md +0 -1
- data/SECURITY.md +5 -9
- data/fluentd.gemspec +3 -3
- data/lib/fluent/command/ctl.rb +2 -2
- data/lib/fluent/command/fluentd.rb +55 -53
- data/lib/fluent/command/plugin_config_formatter.rb +1 -1
- data/lib/fluent/config/dsl.rb +1 -1
- data/lib/fluent/config/v1_parser.rb +2 -2
- data/lib/fluent/counter/server.rb +1 -1
- data/lib/fluent/counter/validator.rb +3 -3
- data/lib/fluent/daemon.rb +2 -4
- data/lib/fluent/engine.rb +1 -1
- data/lib/fluent/event.rb +8 -4
- data/lib/fluent/log/console_adapter.rb +66 -0
- data/lib/fluent/log.rb +44 -5
- data/lib/fluent/match.rb +1 -1
- data/lib/fluent/msgpack_factory.rb +6 -1
- data/lib/fluent/plugin/base.rb +6 -8
- data/lib/fluent/plugin/buf_file.rb +32 -3
- data/lib/fluent/plugin/buf_file_single.rb +32 -3
- data/lib/fluent/plugin/buffer/file_chunk.rb +1 -1
- data/lib/fluent/plugin/buffer.rb +21 -0
- data/lib/fluent/plugin/filter_record_transformer.rb +1 -1
- data/lib/fluent/plugin/in_forward.rb +1 -1
- data/lib/fluent/plugin/in_http.rb +8 -8
- data/lib/fluent/plugin/in_sample.rb +1 -1
- data/lib/fluent/plugin/in_tail/position_file.rb +32 -18
- data/lib/fluent/plugin/in_tail.rb +58 -24
- data/lib/fluent/plugin/in_tcp.rb +47 -2
- data/lib/fluent/plugin/out_exec_filter.rb +2 -2
- data/lib/fluent/plugin/out_forward/ack_handler.rb +19 -4
- data/lib/fluent/plugin/out_forward.rb +2 -2
- data/lib/fluent/plugin/out_secondary_file.rb +39 -22
- data/lib/fluent/plugin/output.rb +50 -13
- data/lib/fluent/plugin/parser_json.rb +1 -1
- data/lib/fluent/plugin_helper/event_loop.rb +2 -2
- data/lib/fluent/plugin_helper/http_server/server.rb +2 -1
- data/lib/fluent/plugin_helper/record_accessor.rb +1 -1
- data/lib/fluent/plugin_helper/server.rb +8 -0
- data/lib/fluent/plugin_helper/thread.rb +3 -3
- data/lib/fluent/plugin_id.rb +1 -1
- data/lib/fluent/supervisor.rb +157 -251
- data/lib/fluent/test/driver/base.rb +11 -5
- data/lib/fluent/test/driver/filter.rb +4 -0
- data/lib/fluent/test/startup_shutdown.rb +6 -8
- data/lib/fluent/version.rb +1 -1
- data/templates/new_gem/test/helper.rb.erb +0 -1
- data/test/command/test_ctl.rb +1 -1
- data/test/command/test_fluentd.rb +137 -6
- data/test/command/test_plugin_config_formatter.rb +0 -1
- data/test/compat/test_parser.rb +5 -5
- data/test/config/test_system_config.rb +0 -8
- data/test/log/test_console_adapter.rb +110 -0
- data/test/plugin/in_tail/test_position_file.rb +31 -1
- data/test/plugin/out_forward/test_ack_handler.rb +39 -0
- data/test/plugin/test_base.rb +99 -1
- data/test/plugin/test_buf_file.rb +62 -23
- data/test/plugin/test_buf_file_single.rb +65 -0
- data/test/plugin/test_buffer_chunk.rb +11 -0
- data/test/plugin/test_in_forward.rb +9 -9
- data/test/plugin/test_in_http.rb +2 -3
- data/test/plugin/test_in_monitor_agent.rb +2 -3
- data/test/plugin/test_in_tail.rb +379 -0
- data/test/plugin/test_in_tcp.rb +87 -2
- data/test/plugin/test_in_udp.rb +28 -0
- data/test/plugin/test_in_unix.rb +2 -2
- data/test/plugin/test_multi_output.rb +1 -1
- data/test/plugin/test_out_exec_filter.rb +2 -2
- data/test/plugin/test_out_file.rb +2 -2
- data/test/plugin/test_out_forward.rb +14 -18
- data/test/plugin/test_out_http.rb +1 -0
- data/test/plugin/test_output.rb +281 -12
- data/test/plugin/test_output_as_buffered.rb +44 -44
- data/test/plugin/test_output_as_buffered_compress.rb +32 -18
- data/test/plugin/test_output_as_buffered_retries.rb +1 -1
- data/test/plugin/test_output_as_buffered_secondary.rb +2 -2
- data/test/plugin/test_parser_regexp.rb +1 -6
- data/test/plugin_helper/test_child_process.rb +2 -2
- data/test/plugin_helper/test_http_server_helper.rb +1 -1
- data/test/plugin_helper/test_server.rb +60 -6
- data/test/test_config.rb +0 -21
- data/test/test_formatter.rb +23 -20
- data/test/test_log.rb +108 -36
- data/test/test_msgpack_factory.rb +32 -0
- data/test/test_supervisor.rb +287 -279
- metadata +15 -21
- data/.drone.yml +0 -35
- data/.gitlab-ci.yml +0 -103
- data/test/test_logger_initializer.rb +0 -46
@@ -16,6 +16,7 @@
|
|
16
16
|
|
17
17
|
require 'fluent/config'
|
18
18
|
require 'fluent/config/element'
|
19
|
+
require 'fluent/env'
|
19
20
|
require 'fluent/log'
|
20
21
|
require 'fluent/clock'
|
21
22
|
|
@@ -102,11 +103,16 @@ module Fluent
|
|
102
103
|
|
103
104
|
def instance_start
|
104
105
|
if @instance.respond_to?(:server_wait_until_start)
|
105
|
-
|
106
|
-
|
107
|
-
|
106
|
+
if Fluent.windows?
|
107
|
+
@socket_manager_server = ServerEngine::SocketManager::Server.open
|
108
|
+
@socket_manager_path = @socket_manager_server.path
|
109
|
+
else
|
110
|
+
@socket_manager_path = ServerEngine::SocketManager::Server.generate_path
|
111
|
+
if @socket_manager_path.is_a?(String) && File.exist?(@socket_manager_path)
|
112
|
+
FileUtils.rm_f @socket_manager_path
|
113
|
+
end
|
114
|
+
@socket_manager_server = ServerEngine::SocketManager::Server.open(@socket_manager_path)
|
108
115
|
end
|
109
|
-
@socket_manager_server = ServerEngine::SocketManager::Server.open(@socket_manager_path)
|
110
116
|
ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = @socket_manager_path.to_s
|
111
117
|
end
|
112
118
|
|
@@ -173,7 +179,7 @@ module Fluent
|
|
173
179
|
|
174
180
|
if @socket_manager_server
|
175
181
|
@socket_manager_server.close
|
176
|
-
if @
|
182
|
+
if @socket_manager_path.is_a?(String) && File.exist?(@socket_manager_path)
|
177
183
|
FileUtils.rm_f @socket_manager_path
|
178
184
|
end
|
179
185
|
end
|
@@ -21,9 +21,8 @@ module Fluent
|
|
21
21
|
module Test
|
22
22
|
module StartupShutdown
|
23
23
|
def startup
|
24
|
-
|
25
|
-
|
26
|
-
ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = socket_manager_path.to_s
|
24
|
+
@server = ServerEngine::SocketManager::Server.open
|
25
|
+
ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = @server.path.to_s
|
27
26
|
end
|
28
27
|
|
29
28
|
def shutdown
|
@@ -31,15 +30,14 @@ module Fluent
|
|
31
30
|
end
|
32
31
|
|
33
32
|
def self.setup
|
34
|
-
@
|
35
|
-
|
36
|
-
ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = @socket_manager_path.to_s
|
33
|
+
@server = ServerEngine::SocketManager::Server.open
|
34
|
+
ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = @server.path.to_s
|
37
35
|
end
|
38
36
|
|
39
37
|
def self.teardown
|
40
38
|
@server.close
|
41
|
-
# on Windows,
|
42
|
-
FileUtils.rm_f @
|
39
|
+
# on Windows, the path is a TCP port number
|
40
|
+
FileUtils.rm_f @server.path unless Fluent.windows?
|
43
41
|
end
|
44
42
|
end
|
45
43
|
end
|
data/lib/fluent/version.rb
CHANGED
data/test/command/test_ctl.rb
CHANGED
@@ -71,6 +71,20 @@ class TestFluentdCommand < ::Test::Unit::TestCase
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
+
def process_kill(pid)
|
75
|
+
if Fluent.windows?
|
76
|
+
Process.kill(:KILL, pid) rescue nil
|
77
|
+
return
|
78
|
+
end
|
79
|
+
|
80
|
+
begin
|
81
|
+
Process.kill(:TERM, pid) rescue nil
|
82
|
+
Timeout.timeout(10){ sleep 0.1 while process_exist?(pid) }
|
83
|
+
rescue Timeout::Error
|
84
|
+
Process.kill(:KILL, pid) rescue nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
74
88
|
def execute_command(cmdline, chdir=@tmp_dir, env = {})
|
75
89
|
null_stream = Fluent::FileWrapper.open(File::NULL, 'w')
|
76
90
|
gemfile_path = File.expand_path(File.dirname(__FILE__) + "../../../Gemfile")
|
@@ -85,12 +99,12 @@ class TestFluentdCommand < ::Test::Unit::TestCase
|
|
85
99
|
yield pid, io
|
86
100
|
# p(here: "execute command", pid: pid, worker_pids: @worker_pids)
|
87
101
|
ensure
|
88
|
-
|
102
|
+
process_kill(pid)
|
89
103
|
if @supervisor_pid
|
90
|
-
|
104
|
+
process_kill(@supervisor_pid)
|
91
105
|
end
|
92
106
|
@worker_pids.each do |cpid|
|
93
|
-
|
107
|
+
process_kill(cpid)
|
94
108
|
end
|
95
109
|
# p(here: "execute command", pid: pid, exist: process_exist?(pid), worker_pids: @worker_pids, exists: @worker_pids.map{|i| process_exist?(i) })
|
96
110
|
Timeout.timeout(10){ sleep 0.1 while process_exist?(pid) }
|
@@ -112,7 +126,9 @@ class TestFluentdCommand < ::Test::Unit::TestCase
|
|
112
126
|
end
|
113
127
|
end
|
114
128
|
|
115
|
-
|
129
|
+
# ATTENTION: This stops taking logs when all `pattern_list` match or timeout,
|
130
|
+
# so `patterns_not_match` can test only logs up to that point.
|
131
|
+
def assert_log_matches(cmdline, *pattern_list, patterns_not_match: [], timeout: 20, env: {})
|
116
132
|
matched = false
|
117
133
|
matched_wrongly = false
|
118
134
|
assert_error_msg = ""
|
@@ -121,7 +137,7 @@ class TestFluentdCommand < ::Test::Unit::TestCase
|
|
121
137
|
execute_command(cmdline, @tmp_dir, env) do |pid, stdout|
|
122
138
|
begin
|
123
139
|
waiting(timeout) do
|
124
|
-
while process_exist?(pid)
|
140
|
+
while process_exist?(pid)
|
125
141
|
readables, _, _ = IO.select([stdout], nil, nil, 1)
|
126
142
|
next unless readables
|
127
143
|
break if readables.first.eof?
|
@@ -133,6 +149,18 @@ class TestFluentdCommand < ::Test::Unit::TestCase
|
|
133
149
|
if pattern_list.all?{|ptn| lines.any?{|line| ptn.is_a?(Regexp) ? ptn.match(line) : line.include?(ptn) } }
|
134
150
|
matched = true
|
135
151
|
end
|
152
|
+
|
153
|
+
if Fluent.windows?
|
154
|
+
# https://github.com/fluent/fluentd/issues/4095
|
155
|
+
# On Windows, the initial process is different from the supervisor process,
|
156
|
+
# so we need to wait until `SUPERVISOR_PID_PATTERN` appears in the logs to get the pid.
|
157
|
+
# (Worker processes will be killed by the supervisor process, so we don't need it-)
|
158
|
+
break if matched && SUPERVISOR_PID_PATTERN =~ stdio_buf
|
159
|
+
else
|
160
|
+
# On Non-Windows, the initial process is the supervisor process,
|
161
|
+
# so we don't need to wait `SUPERVISOR_PID_PATTERN`.
|
162
|
+
break if matched
|
163
|
+
end
|
136
164
|
end
|
137
165
|
end
|
138
166
|
ensure
|
@@ -146,6 +174,10 @@ class TestFluentdCommand < ::Test::Unit::TestCase
|
|
146
174
|
end
|
147
175
|
rescue Timeout::Error
|
148
176
|
assert_error_msg = "execution timeout"
|
177
|
+
# https://github.com/fluent/fluentd/issues/4095
|
178
|
+
# On Windows, timeout without `@supervisor_pid` means that the test is invalid,
|
179
|
+
# since the supervisor process will survive without being killed correctly.
|
180
|
+
flunk("Invalid test: The pid of supervisor could not be taken, which is necessary on Windows.") if Fluent.windows? && @supervisor_pid.nil?
|
149
181
|
rescue => e
|
150
182
|
assert_error_msg = "unexpected error in launching fluentd: #{e.inspect}"
|
151
183
|
else
|
@@ -177,7 +209,7 @@ class TestFluentdCommand < ::Test::Unit::TestCase
|
|
177
209
|
assert matched && !matched_wrongly, assert_error_msg
|
178
210
|
end
|
179
211
|
|
180
|
-
def assert_fluentd_fails_to_start(cmdline, *pattern_list, timeout:
|
212
|
+
def assert_fluentd_fails_to_start(cmdline, *pattern_list, timeout: 20)
|
181
213
|
# empty_list.all?{ ... } is always true
|
182
214
|
matched = false
|
183
215
|
running = false
|
@@ -213,6 +245,10 @@ class TestFluentdCommand < ::Test::Unit::TestCase
|
|
213
245
|
end
|
214
246
|
rescue Timeout::Error
|
215
247
|
assert_error_msg = "execution timeout with command out:\n" + stdio_buf
|
248
|
+
# https://github.com/fluent/fluentd/issues/4095
|
249
|
+
# On Windows, timeout without `@supervisor_pid` means that the test is invalid,
|
250
|
+
# since the supervisor process will survive without being killed correctly.
|
251
|
+
flunk("Invalid test: The pid of supervisor could not be taken, which is necessary on Windows.") if Fluent.windows? && @supervisor_pid.nil?
|
216
252
|
rescue => e
|
217
253
|
assert_error_msg = "unexpected error in launching fluentd: #{e.inspect}\n" + stdio_buf
|
218
254
|
assert false, assert_error_msg
|
@@ -1151,4 +1187,99 @@ CONF
|
|
1151
1187
|
"shared socket for multiple workers is disabled",)
|
1152
1188
|
end
|
1153
1189
|
end
|
1190
|
+
|
1191
|
+
# TODO: `patterns_not_match` can test only logs up to `pattern_list`,
|
1192
|
+
# so we need to fix some meaningless `patterns_not_match` conditions.
|
1193
|
+
sub_test_case 'log_level by command line option' do
|
1194
|
+
test 'info' do
|
1195
|
+
conf = ""
|
1196
|
+
conf_path = create_conf_file('empty.conf', conf)
|
1197
|
+
assert File.exist?(conf_path)
|
1198
|
+
assert_log_matches(create_cmdline(conf_path),
|
1199
|
+
"[info]",
|
1200
|
+
patterns_not_match: ["[debug]"])
|
1201
|
+
end
|
1202
|
+
|
1203
|
+
test 'debug' do
|
1204
|
+
conf = ""
|
1205
|
+
conf_path = create_conf_file('empty.conf', conf)
|
1206
|
+
assert File.exist?(conf_path)
|
1207
|
+
assert_log_matches(create_cmdline(conf_path, "-v"),
|
1208
|
+
"[debug]",
|
1209
|
+
patterns_not_match: ["[trace]"])
|
1210
|
+
end
|
1211
|
+
|
1212
|
+
data("Trace" => "-vv")
|
1213
|
+
data("Invalid low level should be treated as Trace level": "-vvv")
|
1214
|
+
test 'trace' do |option|
|
1215
|
+
conf = <<CONF
|
1216
|
+
<source>
|
1217
|
+
@type sample
|
1218
|
+
tag test
|
1219
|
+
</source>
|
1220
|
+
CONF
|
1221
|
+
conf_path = create_conf_file('sample.conf', conf)
|
1222
|
+
assert File.exist?(conf_path)
|
1223
|
+
assert_log_matches(create_cmdline(conf_path, option),
|
1224
|
+
"[trace]",)
|
1225
|
+
end
|
1226
|
+
|
1227
|
+
test 'warn' do
|
1228
|
+
omit "Can't run on Windows since there is no way to take pid of the supervisor." if Fluent.windows?
|
1229
|
+
conf = <<CONF
|
1230
|
+
<source>
|
1231
|
+
@type sample
|
1232
|
+
tag test
|
1233
|
+
</source>
|
1234
|
+
CONF
|
1235
|
+
conf_path = create_conf_file('sample.conf', conf)
|
1236
|
+
assert File.exist?(conf_path)
|
1237
|
+
assert_log_matches(create_cmdline(conf_path, "-q"),
|
1238
|
+
"[warn]",
|
1239
|
+
patterns_not_match: ["[info]"])
|
1240
|
+
end
|
1241
|
+
|
1242
|
+
data("Error" => "-qq")
|
1243
|
+
data("Fatal should be treated as Error level" => "-qqq")
|
1244
|
+
data("Invalid high level should be treated as Error level": "-qqqq")
|
1245
|
+
test 'error' do |option|
|
1246
|
+
# This test can run on Windows correctly,
|
1247
|
+
# since the process will stop automatically with an error.
|
1248
|
+
conf = <<CONF
|
1249
|
+
<source>
|
1250
|
+
@type plugin_not_found
|
1251
|
+
tag test
|
1252
|
+
</source>
|
1253
|
+
CONF
|
1254
|
+
conf_path = create_conf_file('plugin_not_found.conf', conf)
|
1255
|
+
assert File.exist?(conf_path)
|
1256
|
+
assert_log_matches(create_cmdline(conf_path, option),
|
1257
|
+
"[error]",
|
1258
|
+
patterns_not_match: ["[warn]"])
|
1259
|
+
end
|
1260
|
+
|
1261
|
+
test 'system config one should not be overwritten when cmd line one is not specified' do
|
1262
|
+
conf = <<CONF
|
1263
|
+
<system>
|
1264
|
+
log_level debug
|
1265
|
+
</system>
|
1266
|
+
CONF
|
1267
|
+
conf_path = create_conf_file('debug.conf', conf)
|
1268
|
+
assert File.exist?(conf_path)
|
1269
|
+
assert_log_matches(create_cmdline(conf_path),
|
1270
|
+
"[debug]")
|
1271
|
+
end
|
1272
|
+
end
|
1273
|
+
|
1274
|
+
sub_test_case "inline_config" do
|
1275
|
+
test "can change log_level by --inline-config" do
|
1276
|
+
# Since we can't define multiple `<system>` directives, this use-case is not recommended.
|
1277
|
+
# This is just for this test.
|
1278
|
+
inline_conf = '<system>\nlog_level debug\n</system>'
|
1279
|
+
conf_path = create_conf_file('test.conf', "")
|
1280
|
+
assert File.exist?(conf_path)
|
1281
|
+
assert_log_matches(create_cmdline(conf_path, "--inline-config", inline_conf),
|
1282
|
+
"[debug]")
|
1283
|
+
end
|
1284
|
+
end
|
1154
1285
|
end
|
@@ -188,7 +188,6 @@ slow_flush_log_threshold: float: (20.0)
|
|
188
188
|
retry_exponential_backoff_base: float: (2)
|
189
189
|
retry_max_interval: time: (nil)
|
190
190
|
retry_randomize: bool: (true)
|
191
|
-
disable_chunk_backup: bool: (false)
|
192
191
|
<secondary>: optional, single
|
193
192
|
@type: string: (nil)
|
194
193
|
<buffer>: optional, single
|
data/test/compat/test_parser.rb
CHANGED
@@ -38,14 +38,14 @@ class TextParserTest < ::Test::Unit::TestCase
|
|
38
38
|
|
39
39
|
def test_parse_with_return
|
40
40
|
parser = Fluent::TextParser.new
|
41
|
-
parser.configure('format' => 'none')
|
41
|
+
parser.configure(config_element('test', '', 'format' => 'none'))
|
42
42
|
_time, record = parser.parse('log message!')
|
43
43
|
assert_equal({'message' => 'log message!'}, record)
|
44
44
|
end
|
45
45
|
|
46
46
|
def test_parse_with_block
|
47
47
|
parser = Fluent::TextParser.new
|
48
|
-
parser.configure('format' => 'none')
|
48
|
+
parser.configure(config_element('test', '', 'format' => 'none'))
|
49
49
|
parser.parse('log message!') { |time, record|
|
50
50
|
assert_equal({'message' => 'log message!'}, record)
|
51
51
|
}
|
@@ -53,7 +53,7 @@ class TextParserTest < ::Test::Unit::TestCase
|
|
53
53
|
|
54
54
|
def test_multi_event_parser
|
55
55
|
parser = Fluent::TextParser.new
|
56
|
-
parser.configure('format' => 'multi_event_test')
|
56
|
+
parser.configure(config_element('test', '', 'format' => 'multi_event_test'))
|
57
57
|
i = 0
|
58
58
|
parser.parse('log message!') { |time, record|
|
59
59
|
assert_equal('log message!', record['message'])
|
@@ -67,7 +67,7 @@ class TextParserTest < ::Test::Unit::TestCase
|
|
67
67
|
assert_nil p1.estimate_current_event
|
68
68
|
assert_nil p1.parser
|
69
69
|
|
70
|
-
p1.configure('format' => 'none')
|
70
|
+
p1.configure(config_element('test', '', 'format' => 'none'))
|
71
71
|
assert_equal true, p1.parser.estimate_current_event
|
72
72
|
|
73
73
|
p2 = Fluent::TextParser.new
|
@@ -76,7 +76,7 @@ class TextParserTest < ::Test::Unit::TestCase
|
|
76
76
|
|
77
77
|
p2.estimate_current_event = false
|
78
78
|
|
79
|
-
p2.configure('format' => 'none')
|
79
|
+
p2.configure(config_element('test', '', 'format' => 'none'))
|
80
80
|
assert_equal false, p2.parser.estimate_current_event
|
81
81
|
end
|
82
82
|
|
@@ -5,13 +5,6 @@ require 'fluent/config/section'
|
|
5
5
|
require 'fluent/system_config'
|
6
6
|
|
7
7
|
module Fluent::Config
|
8
|
-
class FakeLoggerInitializer
|
9
|
-
attr_accessor :level
|
10
|
-
def initialize
|
11
|
-
@level = nil
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
8
|
class FakeSupervisor
|
16
9
|
attr_writer :log_level
|
17
10
|
|
@@ -21,7 +14,6 @@ module Fluent::Config
|
|
21
14
|
wokers: nil,
|
22
15
|
restart_worker_interval: nil,
|
23
16
|
root_dir: nil,
|
24
|
-
log: FakeLoggerInitializer.new,
|
25
17
|
log_level: Fluent::Log::LEVEL_INFO,
|
26
18
|
suppress_interval: nil,
|
27
19
|
suppress_config_dump: nil,
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require_relative '../helper'
|
2
|
+
|
3
|
+
require 'fluent/log'
|
4
|
+
require 'fluent/log/console_adapter'
|
5
|
+
|
6
|
+
class ConsoleAdapterTest < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
@timestamp = Time.parse("2023-01-01 15:32:41 +0000")
|
9
|
+
@timestamp_str = @timestamp.strftime("%Y-%m-%d %H:%M:%S %z")
|
10
|
+
Timecop.freeze(@timestamp)
|
11
|
+
|
12
|
+
@logdev = Fluent::Test::DummyLogDevice.new
|
13
|
+
@logger = ServerEngine::DaemonLogger.new(@logdev)
|
14
|
+
@fluent_log = Fluent::Log.new(@logger)
|
15
|
+
@console_logger = Fluent::Log::ConsoleAdapter.wrap(@fluent_log)
|
16
|
+
end
|
17
|
+
|
18
|
+
def teardown
|
19
|
+
Timecop.return
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_expected_log_levels
|
23
|
+
assert_equal({debug: 0, info: 1, warn: 2, error: 3, fatal: 4},
|
24
|
+
Console::Logger::LEVELS)
|
25
|
+
end
|
26
|
+
|
27
|
+
data(trace: [Fluent::Log::LEVEL_TRACE, :debug],
|
28
|
+
debug: [Fluent::Log::LEVEL_DEBUG, :debug],
|
29
|
+
info: [Fluent::Log::LEVEL_INFO, :info],
|
30
|
+
warn: [Fluent::Log::LEVEL_WARN, :warn],
|
31
|
+
error: [Fluent::Log::LEVEL_ERROR, :error],
|
32
|
+
fatal: [Fluent::Log::LEVEL_FATAL, :fatal])
|
33
|
+
def test_reflect_log_level(data)
|
34
|
+
level, expected = data
|
35
|
+
@fluent_log.level = level
|
36
|
+
console_logger = Fluent::Log::ConsoleAdapter.wrap(@fluent_log)
|
37
|
+
assert_equal(Console::Logger::LEVELS[expected],
|
38
|
+
console_logger.level)
|
39
|
+
end
|
40
|
+
|
41
|
+
data(debug: :debug,
|
42
|
+
info: :info,
|
43
|
+
warn: :warn,
|
44
|
+
error: :error,
|
45
|
+
fatal: :fatal)
|
46
|
+
def test_string_subject(level)
|
47
|
+
@console_logger.send(level, "subject")
|
48
|
+
assert_equal(["#{@timestamp_str} [#{level}]: 0.0s: subject\n"],
|
49
|
+
@logdev.logs)
|
50
|
+
end
|
51
|
+
|
52
|
+
data(debug: :debug,
|
53
|
+
info: :info,
|
54
|
+
warn: :warn,
|
55
|
+
error: :error,
|
56
|
+
fatal: :fatal)
|
57
|
+
def test_args(level)
|
58
|
+
@console_logger.send(level, "subject", 1, 2, 3)
|
59
|
+
assert_equal([
|
60
|
+
"#{@timestamp_str} [#{level}]: 0.0s: subject\n" +
|
61
|
+
" | 1\n" +
|
62
|
+
" | 2\n" +
|
63
|
+
" | 3\n"
|
64
|
+
],
|
65
|
+
@logdev.logs)
|
66
|
+
end
|
67
|
+
|
68
|
+
data(debug: :debug,
|
69
|
+
info: :info,
|
70
|
+
warn: :warn,
|
71
|
+
error: :error,
|
72
|
+
fatal: :fatal)
|
73
|
+
def test_options(level)
|
74
|
+
@console_logger.send(level, "subject", kwarg1: "opt1", kwarg2: "opt2")
|
75
|
+
assert_equal([
|
76
|
+
"#{@timestamp_str} [#{level}]: 0.0s: subject\n" +
|
77
|
+
" | {\"kwarg1\":\"opt1\",\"kwarg2\":\"opt2\"}\n"
|
78
|
+
],
|
79
|
+
@logdev.logs)
|
80
|
+
end
|
81
|
+
|
82
|
+
data(debug: :debug,
|
83
|
+
info: :info,
|
84
|
+
warn: :warn,
|
85
|
+
error: :error,
|
86
|
+
fatal: :fatal)
|
87
|
+
def test_block(level)
|
88
|
+
@console_logger.send(level, "subject") { "block message" }
|
89
|
+
assert_equal([
|
90
|
+
"#{@timestamp_str} [#{level}]: 0.0s: subject\n" +
|
91
|
+
" | block message\n"
|
92
|
+
],
|
93
|
+
@logdev.logs)
|
94
|
+
end
|
95
|
+
|
96
|
+
data(debug: :debug,
|
97
|
+
info: :info,
|
98
|
+
warn: :warn,
|
99
|
+
error: :error,
|
100
|
+
fatal: :fatal)
|
101
|
+
def test_multiple_entries(level)
|
102
|
+
@console_logger.send(level, "subject1")
|
103
|
+
@console_logger.send(level, "line2")
|
104
|
+
assert_equal([
|
105
|
+
"#{@timestamp_str} [#{level}]: 0.0s: subject1\n",
|
106
|
+
"#{@timestamp_str} [#{level}]: 0.0s: line2\n"
|
107
|
+
],
|
108
|
+
@logdev.logs)
|
109
|
+
end
|
110
|
+
end
|
@@ -26,6 +26,10 @@ class IntailPositionFileTest < Test::Unit::TestCase
|
|
26
26
|
"valid_path" => Fluent::Plugin::TailInput::TargetInfo.new("valid_path", 1),
|
27
27
|
"inode23bit" => Fluent::Plugin::TailInput::TargetInfo.new("inode23bit", 0),
|
28
28
|
}
|
29
|
+
TEST_CONTENT_INODES = {
|
30
|
+
1 => Fluent::Plugin::TailInput::TargetInfo.new("valid_path", 1),
|
31
|
+
0 => Fluent::Plugin::TailInput::TargetInfo.new("inode23bit", 0),
|
32
|
+
}
|
29
33
|
|
30
34
|
def write_data(f, content)
|
31
35
|
f.write(content)
|
@@ -221,7 +225,7 @@ class IntailPositionFileTest < Test::Unit::TestCase
|
|
221
225
|
end
|
222
226
|
|
223
227
|
sub_test_case '#unwatch' do
|
224
|
-
test '
|
228
|
+
test 'unwatch entry by path' do
|
225
229
|
write_data(@file, TEST_CONTENT)
|
226
230
|
pf = Fluent::Plugin::TailInput::PositionFile.load(@file, false, {}, logger: $log)
|
227
231
|
inode1 = File.stat(@file).ino
|
@@ -239,6 +243,32 @@ class IntailPositionFileTest < Test::Unit::TestCase
|
|
239
243
|
|
240
244
|
assert_not_equal p1, p2
|
241
245
|
end
|
246
|
+
|
247
|
+
test 'unwatch entries by inode' do
|
248
|
+
write_data(@file, TEST_CONTENT)
|
249
|
+
pf = Fluent::Plugin::TailInput::PositionFile.load(@file, true, TEST_CONTENT_INODES, logger: $log)
|
250
|
+
|
251
|
+
existing_targets = TEST_CONTENT_INODES.select do |inode, target_info|
|
252
|
+
inode == 1
|
253
|
+
end
|
254
|
+
pe_to_unwatch = pf[TEST_CONTENT_INODES[0]]
|
255
|
+
|
256
|
+
pf.unwatch_removed_targets(existing_targets)
|
257
|
+
|
258
|
+
assert_equal(
|
259
|
+
{
|
260
|
+
map_keys: [TEST_CONTENT_INODES[1].ino],
|
261
|
+
unwatched_pe_pos: Fluent::Plugin::TailInput::PositionFile::UNWATCHED_POSITION,
|
262
|
+
},
|
263
|
+
{
|
264
|
+
map_keys: pf.instance_variable_get(:@map).keys,
|
265
|
+
unwatched_pe_pos: pe_to_unwatch.read_pos,
|
266
|
+
}
|
267
|
+
)
|
268
|
+
|
269
|
+
unwatched_pe_retaken = pf[TEST_CONTENT_INODES[0]]
|
270
|
+
assert_not_equal pe_to_unwatch, unwatched_pe_retaken
|
271
|
+
end
|
242
272
|
end
|
243
273
|
|
244
274
|
sub_test_case 'FilePositionEntry' do
|
@@ -98,4 +98,43 @@ class AckHandlerTest < Test::Unit::TestCase
|
|
98
98
|
w.close rescue nil
|
99
99
|
end
|
100
100
|
end
|
101
|
+
|
102
|
+
# ForwardOutput uses AckHandler in multiple threads, so we need to assume this case.
|
103
|
+
# If exclusive control for this case is implemented, this test may not be necessary.
|
104
|
+
test 'raises no error when another thread closes a socket' do
|
105
|
+
ack_handler = Fluent::Plugin::ForwardOutput::AckHandler.new(timeout: 10, log: $log, read_length: 100)
|
106
|
+
|
107
|
+
node = flexmock('node', host: '127.0.0.1', port: '1000') # for log
|
108
|
+
chunk_id = 'chunk_id 111'
|
109
|
+
ack = ack_handler.create_ack(chunk_id, node)
|
110
|
+
|
111
|
+
r, w = IO.pipe
|
112
|
+
begin
|
113
|
+
w.write(chunk_id)
|
114
|
+
stub(r).recv { |_|
|
115
|
+
sleep(1) # To ensure that multiple threads select the socket before closing.
|
116
|
+
raise IOError, 'stream closed in another thread' if r.closed?
|
117
|
+
MessagePack.pack({ 'ack' => Base64.encode64('chunk_id 111') })
|
118
|
+
}
|
119
|
+
ack.enqueue(r)
|
120
|
+
|
121
|
+
threads = []
|
122
|
+
2.times do
|
123
|
+
threads << Thread.new do
|
124
|
+
ack_handler.collect_response(1) do |cid, n, s, ret|
|
125
|
+
s&.close
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
assert_true threads.map{ |t| t.join(10) }.all?
|
131
|
+
assert_false(
|
132
|
+
$log.out.logs.any? { |log| log.include?('[error]') },
|
133
|
+
$log.out.logs.select{ |log| log.include?('[error]') }.join('\n')
|
134
|
+
)
|
135
|
+
ensure
|
136
|
+
r.close rescue nil
|
137
|
+
w.close rescue nil
|
138
|
+
end
|
139
|
+
end
|
101
140
|
end
|