Skip to content

Commit c48ca04

Browse files
authored
Merge pull request #3987 from fluent/console-logger-adapter
Adapt Console::Logger to Fluent::Log
2 parents 8df759b + fb97f56 commit c48ca04

4 files changed

Lines changed: 179 additions & 2 deletions

File tree

lib/fluent/log/console_adapter.rb

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#
2+
# Fluentd
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
17+
require 'console/terminal/logger'
18+
19+
module Fluent
20+
class Log
21+
# Async gem which is used by http_server helper switched logger mechanism to
22+
# Console gem which isn't complatible with Ruby's standard Logger (since
23+
# v1.17). This class adapts it to Fluentd's logger mechanism.
24+
class ConsoleAdapter < Console::Terminal::Logger
25+
def self.wrap(logger)
26+
_, level = Console::Logger::LEVELS.find { |key, value|
27+
if logger.level <= 0
28+
key == :debug
29+
else
30+
value == logger.level - 1
31+
end
32+
}
33+
Console::Logger.new(ConsoleAdapter.new(logger), level: level)
34+
end
35+
36+
def initialize(logger)
37+
@logger = logger
38+
# When `verbose` is `true`, following items will be added as a prefix or
39+
# suffix of the subject:
40+
# * Severity
41+
# * Object ID
42+
# * PID
43+
# * Time
44+
# Severity and Time are added by Fluentd::Log too so they are redundant.
45+
# PID is the worker's PID so it's also redundant.
46+
# Object ID will be too verbose in usual cases.
47+
# So set it as `false` here to suppress redundant items.
48+
super(StringIO.new, verbose: false)
49+
end
50+
51+
def call(subject = nil, *arguments, name: nil, severity: 'info', **options, &block)
52+
if LEVEL_TEXT.include?(severity.to_s)
53+
level = severity
54+
else
55+
@logger.warn("Unknown severity: #{severity}")
56+
level = 'warn'
57+
end
58+
59+
@io.seek(0)
60+
@io.truncate(0)
61+
super
62+
@logger.send(level, @io.string.chomp)
63+
end
64+
end
65+
end
66+
end

lib/fluent/plugin_helper/http_server/server.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
require 'fluent/plugin_helper/http_server/app'
2222
require 'fluent/plugin_helper/http_server/router'
2323
require 'fluent/plugin_helper/http_server/methods'
24+
require 'fluent/log/console_adapter'
2425

2526
module Fluent
2627
module PluginHelper
@@ -38,7 +39,7 @@ def initialize(addr:, port:, logger:, default_app: nil, tls_context: nil)
3839
scheme = tls_context ? 'https' : 'http'
3940
@uri = URI("#{scheme}://#{@addr}:#{@port}").to_s
4041
@router = Router.new(default_app)
41-
@reactor = Async::Reactor.new(nil, logger: @logger)
42+
@reactor = Async::Reactor.new(nil, logger: Fluent::Log::ConsoleAdapter.wrap(@logger))
4243

4344
opts = if tls_context
4445
{ ssl_context: tls_context }

test/log/test_console_adapter.rb

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

test/plugin_helper/test_http_server_helper.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ def start_https_request(addr, port, verify: true, cert_path: nil, selfsigned: tr
127127
end
128128

129129
client = Async::HTTP::Client.new(Async::HTTP::Endpoint.parse("https://#{addr}:#{port}", ssl_context: context))
130-
reactor = Async::Reactor.new(nil, logger: NULL_LOGGER)
130+
reactor = Async::Reactor.new(nil, logger: Fluent::Log::ConsoleAdapter.wrap(NULL_LOGGER))
131131

132132
resp = nil
133133
error = nil

0 commit comments

Comments
 (0)