fluentd 0.14.9 → 0.14.10
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/.travis.yml +2 -0
- data/ChangeLog +44 -0
- data/appveyor.yml +1 -0
- data/code-of-conduct.md +3 -0
- data/fluentd.gemspec +1 -1
- data/lib/fluent/command/cat.rb +11 -3
- data/lib/fluent/compat/output.rb +6 -3
- data/lib/fluent/compat/parser.rb +2 -0
- data/lib/fluent/config/section.rb +1 -1
- data/lib/fluent/env.rb +1 -1
- data/lib/fluent/plugin/filter_record_transformer.rb +12 -30
- data/lib/fluent/plugin/in_forward.rb +50 -169
- data/lib/fluent/plugin/in_monitor_agent.rb +8 -4
- data/lib/fluent/plugin/in_syslog.rb +13 -7
- data/lib/fluent/plugin/in_tail.rb +29 -14
- data/lib/fluent/plugin/in_tcp.rb +54 -14
- data/lib/fluent/plugin/in_udp.rb +49 -13
- data/lib/fluent/plugin/out_file.rb +30 -14
- data/lib/fluent/plugin/out_forward.rb +199 -173
- data/lib/fluent/plugin/output.rb +71 -46
- data/lib/fluent/plugin/parser_json.rb +1 -1
- data/lib/fluent/plugin_helper.rb +2 -0
- data/lib/fluent/plugin_helper/event_loop.rb +24 -6
- data/lib/fluent/plugin_helper/inject.rb +12 -1
- data/lib/fluent/plugin_helper/server.rb +494 -0
- data/lib/fluent/plugin_helper/socket.rb +101 -0
- data/lib/fluent/plugin_helper/socket_option.rb +84 -0
- data/lib/fluent/plugin_helper/timer.rb +1 -0
- data/lib/fluent/test/driver/base.rb +45 -13
- data/lib/fluent/version.rb +1 -1
- data/lib/fluent/winsvc.rb +1 -1
- data/test/compat/test_parser.rb +10 -0
- data/test/config/test_configurable.rb +20 -0
- data/test/helper.rb +36 -1
- data/test/plugin/test_filter_record_transformer.rb +31 -103
- data/test/plugin/test_in_forward.rb +13 -75
- data/test/plugin/test_in_monitor_agent.rb +65 -35
- data/test/plugin/test_in_syslog.rb +39 -3
- data/test/plugin/test_in_tcp.rb +78 -62
- data/test/plugin/test_in_udp.rb +101 -80
- data/test/plugin/test_out_file.rb +17 -0
- data/test/plugin/test_out_forward.rb +155 -125
- data/test/plugin/test_output_as_buffered.rb +4 -2
- data/test/plugin_helper/test_inject.rb +21 -0
- data/test/plugin_helper/test_server.rb +905 -0
- data/test/test_event_time.rb +3 -1
- data/test/test_output.rb +30 -1
- data/test/test_test_drivers.rb +5 -2
- metadata +19 -6
@@ -0,0 +1,101 @@
|
|
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 'socket'
|
18
|
+
require 'ipaddr'
|
19
|
+
|
20
|
+
require_relative 'socket_option'
|
21
|
+
|
22
|
+
module Fluent
|
23
|
+
module PluginHelper
|
24
|
+
module Socket
|
25
|
+
# stop : [-]
|
26
|
+
# shutdown : [-]
|
27
|
+
# close : [-]
|
28
|
+
# terminate: [-]
|
29
|
+
|
30
|
+
include Fluent::PluginHelper::SocketOption
|
31
|
+
|
32
|
+
attr_reader :_sockets # for tests
|
33
|
+
|
34
|
+
# TODO: implement connection pool for specified host
|
35
|
+
|
36
|
+
def socket_create(proto, host, port, **kwargs, &block)
|
37
|
+
case proto
|
38
|
+
when :tcp
|
39
|
+
socket_create_tcp(host, port, **kwargs, &block)
|
40
|
+
when :udp
|
41
|
+
socket_create_udp(host, port, **kwargs, &block)
|
42
|
+
when :tls
|
43
|
+
socket_create_tls(host, port, **kwargs, &block)
|
44
|
+
when :unix
|
45
|
+
raise "not implemented yet"
|
46
|
+
else
|
47
|
+
raise ArgumentError, "invalid protocol: #{proto}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def socket_create_tcp(host, port, resolve_name: false, **kwargs, &block)
|
52
|
+
sock = TCPSocket.new(host, port)
|
53
|
+
socket_option_set(sock, resolve_name: resolve_name, **kwargs)
|
54
|
+
if block
|
55
|
+
begin
|
56
|
+
block.call(sock)
|
57
|
+
ensure
|
58
|
+
sock.close_write rescue nil
|
59
|
+
sock.close rescue nil
|
60
|
+
end
|
61
|
+
else
|
62
|
+
sock
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def socket_create_udp(host, port, resolve_name: false, connect: false, **kwargs, &block)
|
67
|
+
family = IPAddr.new(IPSocket.getaddress(host)).ipv4? ? ::Socket::AF_INET : ::Socket::AF_INET6
|
68
|
+
sock = UDPSocket.new(family)
|
69
|
+
socket_option_set(sock, resolve_name: resolve_name, **kwargs)
|
70
|
+
sock.connect(host, port) if connect
|
71
|
+
if block
|
72
|
+
begin
|
73
|
+
block.call(sock)
|
74
|
+
ensure
|
75
|
+
sock.close rescue nil
|
76
|
+
end
|
77
|
+
else
|
78
|
+
sock
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def socket_create_tls(host, port, resolve_name: false, certopts: {}, &block)
|
83
|
+
raise "not implemented yet"
|
84
|
+
end
|
85
|
+
|
86
|
+
# socket_create_socks ?
|
87
|
+
|
88
|
+
def initialize
|
89
|
+
super
|
90
|
+
# @_sockets = [] # for keepalived sockets / connection pool
|
91
|
+
end
|
92
|
+
|
93
|
+
# def close
|
94
|
+
# @_sockets.each do |sock|
|
95
|
+
# sock.close
|
96
|
+
# end
|
97
|
+
# super
|
98
|
+
# end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,84 @@
|
|
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 'socket'
|
18
|
+
require 'fcntl'
|
19
|
+
|
20
|
+
# this module is only for Socket/Server plugin helpers
|
21
|
+
module Fluent
|
22
|
+
module PluginHelper
|
23
|
+
module SocketOption
|
24
|
+
FORMAT_STRUCT_LINGER = 'I!I!' # { int l_onoff; int l_linger; }
|
25
|
+
FORMAT_STRUCT_TIMEVAL = 'L!L!' # { time_t tv_sec; suseconds_t tv_usec; }
|
26
|
+
|
27
|
+
def socket_option_validate!(protocol, resolve_name: nil, linger_timeout: nil, recv_timeout: nil, send_timeout: nil, certopts: nil)
|
28
|
+
unless resolve_name.nil?
|
29
|
+
if protocol != :tcp && protocol != :udp && protocol != :tls
|
30
|
+
raise ArgumentError, "BUG: resolve_name in available for tcp/udp/tls"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
if linger_timeout
|
34
|
+
if protocol != :tcp && protocol != :tls
|
35
|
+
raise ArgumentError, "BUG: linger_timeout is available for tcp/tls"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
if certopts
|
39
|
+
if protocol != :tls
|
40
|
+
raise ArgumentError, "BUG: certopts is available only for tls"
|
41
|
+
end
|
42
|
+
else
|
43
|
+
if protocol == :tls
|
44
|
+
raise ArgumentError, "BUG: certopts (certificate options) not specified for TLS"
|
45
|
+
socket_option_certopts_validate!(certopts)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def socket_option_certopts_validate!(certopts)
|
51
|
+
raise "not implemented yet"
|
52
|
+
end
|
53
|
+
|
54
|
+
def socket_option_set(sock, resolve_name: nil, nonblock: false, linger_timeout: nil, recv_timeout: nil, send_timeout: nil, certopts: nil)
|
55
|
+
unless resolve_name.nil?
|
56
|
+
sock.do_not_reverse_lookup = !resolve_name
|
57
|
+
end
|
58
|
+
if nonblock
|
59
|
+
sock.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
|
60
|
+
end
|
61
|
+
if linger_timeout
|
62
|
+
optval = [1, linger_timeout.to_i].pack(FORMAT_STRUCT_LINGER)
|
63
|
+
socket_option_set_one(sock, :SO_LINGER, optval)
|
64
|
+
end
|
65
|
+
if recv_timeout
|
66
|
+
optval = [recv_timeout.to_i, 0].pack(FORMAT_STRUCT_TIMEVAL)
|
67
|
+
socket_option_set_one(sock, :SO_RCVTIMEO, optval)
|
68
|
+
end
|
69
|
+
if send_timeout
|
70
|
+
optval = [send_timeout.to_i, 0].pack(FORMAT_STRUCT_TIMEVAL)
|
71
|
+
socket_option_set_one(sock, :SO_SNDTIMEO, optval)
|
72
|
+
end
|
73
|
+
# TODO: certopts for TLS
|
74
|
+
sock
|
75
|
+
end
|
76
|
+
|
77
|
+
def socket_option_set_one(sock, option, value)
|
78
|
+
sock.setsockopt(::Socket::SOL_SOCKET, option, value)
|
79
|
+
rescue => e
|
80
|
+
log.warn "failed to set socket option", sock: sock.class, option: option, value: value, error: e
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -18,6 +18,8 @@ require 'fluent/config'
|
|
18
18
|
require 'fluent/config/element'
|
19
19
|
require 'fluent/log'
|
20
20
|
|
21
|
+
require 'serverengine/socket_manager'
|
22
|
+
require 'fileutils'
|
21
23
|
require 'timeout'
|
22
24
|
|
23
25
|
module Fluent
|
@@ -32,20 +34,18 @@ module Fluent
|
|
32
34
|
|
33
35
|
def initialize(klass, opts: {}, &block)
|
34
36
|
if klass.is_a?(Class)
|
37
|
+
@instance = klass.new
|
35
38
|
if block
|
36
|
-
|
37
|
-
|
38
|
-
klass_name = klass.name
|
39
|
-
klass = Class.new(klass)
|
40
|
-
klass.define_singleton_method("name") { klass_name }
|
41
|
-
klass.module_eval(&block)
|
39
|
+
@instance.singleton_class.module_eval(&block)
|
40
|
+
@instance.send(:initialize)
|
42
41
|
end
|
43
|
-
@instance = klass.new
|
44
42
|
else
|
45
43
|
@instance = klass
|
46
44
|
end
|
47
45
|
@instance.under_plugin_development = true
|
48
46
|
|
47
|
+
@socket_manager_server = nil
|
48
|
+
|
49
49
|
@logs = []
|
50
50
|
|
51
51
|
@test_clock_id = Process::CLOCK_MONOTONIC_RAW rescue Process::CLOCK_MONOTONIC
|
@@ -101,6 +101,15 @@ module Fluent
|
|
101
101
|
end
|
102
102
|
|
103
103
|
def instance_start
|
104
|
+
if @instance.respond_to?(:server_wait_until_start)
|
105
|
+
@socket_manager_path = ServerEngine::SocketManager::Server.generate_path
|
106
|
+
if @socket_manager_path.is_a?(String) && File.exist?(@socket_manager_path)
|
107
|
+
FileUtils.rm_f @socket_manager_path
|
108
|
+
end
|
109
|
+
@socket_manager_server = ServerEngine::SocketManager::Server.open(@socket_manager_path)
|
110
|
+
ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = @socket_manager_path.to_s
|
111
|
+
end
|
112
|
+
|
104
113
|
unless @instance.started?
|
105
114
|
@instance.start
|
106
115
|
end
|
@@ -130,22 +139,45 @@ module Fluent
|
|
130
139
|
def instance_shutdown
|
131
140
|
instance_hook_before_stopped
|
132
141
|
|
133
|
-
|
134
|
-
|
135
|
-
|
142
|
+
unless @instance.stopped?
|
143
|
+
@instance.stop rescue nil
|
144
|
+
end
|
145
|
+
unless @instance.before_shutdown?
|
146
|
+
@instance.before_shutdown rescue nil
|
147
|
+
end
|
148
|
+
unless @instance.shutdown?
|
149
|
+
@instance.shutdown rescue nil
|
150
|
+
end
|
136
151
|
|
137
152
|
if @instance.respond_to?(:event_loop_wait_until_stop)
|
138
153
|
@instance.event_loop_wait_until_stop
|
139
154
|
end
|
140
155
|
|
141
|
-
|
142
|
-
|
156
|
+
unless @instance.after_shutdown?
|
157
|
+
@instance.after_shutdown rescue nil
|
158
|
+
end
|
159
|
+
unless @instance.closed?
|
160
|
+
@instance.close rescue nil
|
161
|
+
end
|
143
162
|
|
144
163
|
if @instance.respond_to?(:thread_wait_until_stop)
|
145
164
|
@instance.thread_wait_until_stop
|
146
165
|
end
|
147
166
|
|
148
|
-
|
167
|
+
if @instance.respond_to?(:server_wait_until_stop)
|
168
|
+
@instance.server_wait_until_stop
|
169
|
+
end
|
170
|
+
|
171
|
+
unless @instance.terminated?
|
172
|
+
@instance.terminate rescue nil
|
173
|
+
end
|
174
|
+
|
175
|
+
if @socket_manager_server
|
176
|
+
@socket_manager_server.close
|
177
|
+
if @socket_manager_server.is_a?(String) && File.exist?(@socket_manager_path)
|
178
|
+
FileUtils.rm_f @socket_manager_path
|
179
|
+
end
|
180
|
+
end
|
149
181
|
end
|
150
182
|
|
151
183
|
def run_actual(timeout: DEFAULT_TIMEOUT, &block)
|
data/lib/fluent/version.rb
CHANGED
data/lib/fluent/winsvc.rb
CHANGED
data/test/compat/test_parser.rb
CHANGED
@@ -79,4 +79,14 @@ class TextParserTest < ::Test::Unit::TestCase
|
|
79
79
|
p2.configure('format' => 'none')
|
80
80
|
assert_equal false, p2.parser.estimate_current_event
|
81
81
|
end
|
82
|
+
|
83
|
+
data(ignorecase: Regexp::IGNORECASE,
|
84
|
+
multiline: Regexp::MULTILINE,
|
85
|
+
both: Regexp::IGNORECASE & Regexp::MULTILINE)
|
86
|
+
def test_regexp_parser_config(options)
|
87
|
+
source = "a"
|
88
|
+
parser = Fluent::TextParser::RegexpParser.new(Regexp.new(source, options), { "dummy" => "dummy" })
|
89
|
+
regexp = parser.instance_variable_get("@regexp")
|
90
|
+
assert_equal(options, regexp.options)
|
91
|
+
end
|
82
92
|
end
|
@@ -1295,6 +1295,26 @@ module Fluent::Config
|
|
1295
1295
|
assert_raise Fluent::ObsoletedParameterError.new("'key2' parameter is already removed: key2 has been removed.") do
|
1296
1296
|
obj.configure(config_element('ROOT', '', {'key2' => 'yay'}, []))
|
1297
1297
|
end
|
1298
|
+
first_log = obj.log.logs.first
|
1299
|
+
assert{ first_log && first_log.include?("[error]") && first_log.include?("config error in:\n<ROOT>\n key2 yay\n</ROOT>") }
|
1300
|
+
end
|
1301
|
+
|
1302
|
+
sub_test_case 'logger is nil' do
|
1303
|
+
test 'nothing raised if deprecated parameter is configured' do
|
1304
|
+
obj = ConfigurableSpec::UnRecommended.new
|
1305
|
+
obj.log = nil
|
1306
|
+
obj.configure(config_element('ROOT', '', {'key1' => 'yay'}, []))
|
1307
|
+
assert_nil(obj.log)
|
1308
|
+
end
|
1309
|
+
|
1310
|
+
test 'NoMethodError is not raised if obsoleted parameter is configured' do
|
1311
|
+
obj = ConfigurableSpec::UnRecommended.new
|
1312
|
+
obj.log = nil
|
1313
|
+
assert_raise Fluent::ObsoletedParameterError.new("'key2' parameter is already removed: key2 has been removed.") do
|
1314
|
+
obj.configure(config_element('ROOT', '', {'key2' => 'yay'}, []))
|
1315
|
+
end
|
1316
|
+
assert_nil(obj.log)
|
1317
|
+
end
|
1298
1318
|
end
|
1299
1319
|
end
|
1300
1320
|
|
data/test/helper.rb
CHANGED
@@ -69,7 +69,18 @@ end
|
|
69
69
|
|
70
70
|
include Fluent::Test::Helpers
|
71
71
|
|
72
|
-
def unused_port(num = 1)
|
72
|
+
def unused_port(num = 1, protocol: :tcp, bind: "0.0.0.0")
|
73
|
+
case protocol
|
74
|
+
when :tcp
|
75
|
+
unused_port_tcp(num)
|
76
|
+
when :udp
|
77
|
+
unused_port_udp(num, bind: bind)
|
78
|
+
else
|
79
|
+
raise ArgumentError, "unknown protocol: #{protocol}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def unused_port_tcp(num = 1)
|
73
84
|
ports = []
|
74
85
|
sockets = []
|
75
86
|
num.times do
|
@@ -85,6 +96,30 @@ def unused_port(num = 1)
|
|
85
96
|
end
|
86
97
|
end
|
87
98
|
|
99
|
+
PORT_RANGE_AVAILABLE = (1024...65535)
|
100
|
+
|
101
|
+
def unused_port_udp(num = 1, bind: "0.0.0.0")
|
102
|
+
family = IPAddr.new(IPSocket.getaddress(bind)).ipv4? ? ::Socket::AF_INET : ::Socket::AF_INET6
|
103
|
+
ports = []
|
104
|
+
sockets = []
|
105
|
+
while ports.size < num
|
106
|
+
port = rand(PORT_RANGE_AVAILABLE)
|
107
|
+
u = UDPSocket.new(family)
|
108
|
+
if (u.bind(bind, port) rescue nil)
|
109
|
+
ports << port
|
110
|
+
sockets << u
|
111
|
+
else
|
112
|
+
u.close
|
113
|
+
end
|
114
|
+
end
|
115
|
+
sockets.each{|s| s.close }
|
116
|
+
if num == 1
|
117
|
+
return ports.first
|
118
|
+
else
|
119
|
+
return *ports
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
88
123
|
def waiting(seconds, logs: nil, plugin: nil)
|
89
124
|
begin
|
90
125
|
Timeout.timeout(seconds) do
|
@@ -2,9 +2,11 @@ require_relative '../helper'
|
|
2
2
|
require 'timecop'
|
3
3
|
require 'fluent/test/driver/filter'
|
4
4
|
require 'fluent/plugin/filter_record_transformer'
|
5
|
+
require 'flexmock/test_unit'
|
5
6
|
|
6
7
|
class RecordTransformerFilterTest < Test::Unit::TestCase
|
7
8
|
include Fluent
|
9
|
+
include FlexMock::TestCase
|
8
10
|
|
9
11
|
setup do
|
10
12
|
Test.setup
|
@@ -53,7 +55,7 @@ class RecordTransformerFilterTest < Test::Unit::TestCase
|
|
53
55
|
hostname ${hostname}
|
54
56
|
tag ${tag}
|
55
57
|
time ${time}
|
56
|
-
message ${hostname} ${tag_parts[-1]} ${message}
|
58
|
+
message ${hostname} ${tag_parts[-1]} ${record["message"]}
|
57
59
|
</record>
|
58
60
|
]
|
59
61
|
|
@@ -119,7 +121,7 @@ class RecordTransformerFilterTest < Test::Unit::TestCase
|
|
119
121
|
config = %[
|
120
122
|
enable_ruby yes
|
121
123
|
<record>
|
122
|
-
message ${hostname} ${tag_parts.last} ${"'" + message + "'"}
|
124
|
+
message ${hostname} ${tag_parts.last} ${"'" + record["message"] + "'"}
|
123
125
|
</record>
|
124
126
|
]
|
125
127
|
msgs = ['1', '2']
|
@@ -263,8 +265,8 @@ class RecordTransformerFilterTest < Test::Unit::TestCase
|
|
263
265
|
enable_ruby #{enable_ruby}
|
264
266
|
remove_keys eventType0
|
265
267
|
<record>
|
266
|
-
message bar ${message}
|
267
|
-
eventtype ${eventType0}
|
268
|
+
message bar ${record["message"]}
|
269
|
+
eventtype ${record["eventType0"]}
|
268
270
|
</record>
|
269
271
|
]
|
270
272
|
msgs = ['1', '2']
|
@@ -360,11 +362,11 @@ class RecordTransformerFilterTest < Test::Unit::TestCase
|
|
360
362
|
auto_typecast false
|
361
363
|
enable_ruby #{enable_ruby}
|
362
364
|
<record>
|
363
|
-
single ${source}
|
364
|
-
multiple ${source}${source}
|
365
|
-
with_prefix prefix-${source}
|
366
|
-
with_suffix ${source}-suffix
|
367
|
-
with_quote source[""]
|
365
|
+
single ${record["source"]}
|
366
|
+
multiple ${record["source"]}${record["source"]}
|
367
|
+
with_prefix prefix-${record["source"]}
|
368
|
+
with_suffix ${record["source"]}-suffix
|
369
|
+
with_quote record["source"][""]
|
368
370
|
</record>
|
369
371
|
]
|
370
372
|
msgs = [
|
@@ -379,27 +381,27 @@ class RecordTransformerFilterTest < Test::Unit::TestCase
|
|
379
381
|
multiple: "stringstring",
|
380
382
|
with_prefix: "prefix-string",
|
381
383
|
with_suffix: "string-suffix",
|
382
|
-
with_quote: %Q{source[""]} },
|
384
|
+
with_quote: %Q{record["source"][""]} },
|
383
385
|
{ single: 123.to_s,
|
384
386
|
multiple: "#{123.to_s}#{123.to_s}",
|
385
387
|
with_prefix: "prefix-#{123.to_s}",
|
386
388
|
with_suffix: "#{123.to_s}-suffix",
|
387
|
-
with_quote: %Q{source[""]} },
|
389
|
+
with_quote: %Q{record["source"][""]} },
|
388
390
|
{ single: [1, 2].to_s,
|
389
391
|
multiple: "#{[1, 2].to_s}#{[1, 2].to_s}",
|
390
392
|
with_prefix: "prefix-#{[1, 2].to_s}",
|
391
393
|
with_suffix: "#{[1, 2].to_s}-suffix",
|
392
|
-
with_quote: %Q{source[""]} },
|
394
|
+
with_quote: %Q{record["source"][""]} },
|
393
395
|
{ single: {a:1, b:2}.to_s,
|
394
396
|
multiple: "#{{a:1, b:2}.to_s}#{{a:1, b:2}.to_s}",
|
395
397
|
with_prefix: "prefix-#{{a:1, b:2}.to_s}",
|
396
398
|
with_suffix: "#{{a:1, b:2}.to_s}-suffix",
|
397
|
-
with_quote: %Q{source[""]} },
|
399
|
+
with_quote: %Q{record["source"][""]} },
|
398
400
|
{ single: nil.to_s,
|
399
401
|
multiple: "#{nil.to_s}#{nil.to_s}",
|
400
402
|
with_prefix: "prefix-#{nil.to_s}",
|
401
403
|
with_suffix: "#{nil.to_s}-suffix",
|
402
|
-
with_quote: %Q{source[""]} },
|
404
|
+
with_quote: %Q{record["source"][""]} },
|
403
405
|
]
|
404
406
|
actual_results = []
|
405
407
|
filtered = filter(config, msgs)
|
@@ -420,10 +422,10 @@ class RecordTransformerFilterTest < Test::Unit::TestCase
|
|
420
422
|
auto_typecast yes
|
421
423
|
enable_ruby #{enable_ruby}
|
422
424
|
<record>
|
423
|
-
single ${source}
|
424
|
-
multiple ${source}${source}
|
425
|
-
with_prefix prefix-${source}
|
426
|
-
with_suffix ${source}-suffix
|
425
|
+
single ${record["source"]}
|
426
|
+
multiple ${record["source"]}${record["source"]}
|
427
|
+
with_prefix prefix-${record["source"]}
|
428
|
+
with_suffix ${record["source"]}-suffix
|
427
429
|
</record>
|
428
430
|
]
|
429
431
|
msgs = [
|
@@ -467,28 +469,6 @@ class RecordTransformerFilterTest < Test::Unit::TestCase
|
|
467
469
|
end
|
468
470
|
assert_equal(expected_results, actual_results)
|
469
471
|
end
|
470
|
-
|
471
|
-
test %Q[record["key"] with enable_ruby #{enable_ruby}] do
|
472
|
-
config = %[
|
473
|
-
enable_ruby #{enable_ruby}
|
474
|
-
auto_typecast yes
|
475
|
-
<record>
|
476
|
-
_timestamp ${record["@timestamp"]}
|
477
|
-
_foo_bar ${record["foo.bar"]}
|
478
|
-
</record>
|
479
|
-
]
|
480
|
-
d = create_driver(config)
|
481
|
-
record = {
|
482
|
-
"foo.bar" => "foo.bar",
|
483
|
-
"@timestamp" => 10,
|
484
|
-
}
|
485
|
-
d.run { d.feed(@tag, @time, record) }
|
486
|
-
filtered = d.filtered
|
487
|
-
filtered.each do |t, r|
|
488
|
-
assert { r['_timestamp'] == record['@timestamp'] }
|
489
|
-
assert { r['_foo_bar'] == record['foo.bar'] }
|
490
|
-
end
|
491
|
-
end
|
492
472
|
end
|
493
473
|
|
494
474
|
test 'unknown placeholder (enable_ruby no)' do
|
@@ -503,30 +483,11 @@ class RecordTransformerFilterTest < Test::Unit::TestCase
|
|
503
483
|
}
|
504
484
|
end
|
505
485
|
|
506
|
-
data(auto_typecast_yes: ["yes", "unknown['bar']"],
|
507
|
-
auto_typecast_no: ["no", "%Q[\#{unknown['bar']}]"])
|
508
|
-
test 'failed to expand (enable_ruby yes)' do |(param, expected_log)|
|
509
|
-
|
510
|
-
config = %[
|
511
|
-
enable_ruby yes
|
512
|
-
auto_typecast #{param}
|
513
|
-
<record>
|
514
|
-
message ${unknown['bar']}
|
515
|
-
</record>
|
516
|
-
]
|
517
|
-
filtered = filter(config) { |d|
|
518
|
-
mock(d.instance.log).warn("failed to expand `#{expected_log}`", anything)
|
519
|
-
}
|
520
|
-
filtered.each do |t, r|
|
521
|
-
assert_nil(r['message'])
|
522
|
-
end
|
523
|
-
end
|
524
|
-
|
525
486
|
test 'expand fields starting with @ (enable_ruby no)' do
|
526
487
|
config = %[
|
527
488
|
enable_ruby no
|
528
489
|
<record>
|
529
|
-
foo ${@timestamp}
|
490
|
+
foo ${record["@timestamp"]}
|
530
491
|
</record>
|
531
492
|
]
|
532
493
|
d = create_driver(config)
|
@@ -555,54 +516,21 @@ class RecordTransformerFilterTest < Test::Unit::TestCase
|
|
555
516
|
assert_equal([message["@timestamp"]], r['foo'])
|
556
517
|
end
|
557
518
|
end
|
519
|
+
end # test placeholders
|
558
520
|
|
559
|
-
|
560
|
-
|
521
|
+
sub_test_case 'test error record' do
|
522
|
+
test 'invalid record for placeholders' do
|
523
|
+
d = create_driver(%[
|
561
524
|
enable_ruby yes
|
562
525
|
<record>
|
563
|
-
foo ${
|
526
|
+
foo ${record["unknown"]["key"]}
|
564
527
|
</record>
|
565
|
-
]
|
566
|
-
d
|
567
|
-
|
568
|
-
d.run
|
569
|
-
|
570
|
-
filtered.each do |t, r|
|
571
|
-
assert_equal(message["@timestamp"], r['foo'])
|
528
|
+
])
|
529
|
+
flexmock(d.instance.router).should_receive(:emit_error_event).
|
530
|
+
with(String, Fluent::EventTime, Hash, RuntimeError).once
|
531
|
+
d.run do
|
532
|
+
d.feed(@tag, Fluent::EventTime.now, {'key' => 'value'})
|
572
533
|
end
|
573
534
|
end
|
574
|
-
end # test placeholders
|
575
|
-
|
576
|
-
test "compatibility test (enable_ruby yes)" do
|
577
|
-
config = %[
|
578
|
-
enable_ruby yes
|
579
|
-
auto_typecast yes
|
580
|
-
<record>
|
581
|
-
_message prefix-${message}-suffix
|
582
|
-
_time ${Time.at(time)}
|
583
|
-
_number ${number == '-' ? 0 : number}
|
584
|
-
_match ${/0x[0-9a-f]+/.match(hex)[0]}
|
585
|
-
_timestamp ${__send__("@timestamp")}
|
586
|
-
_foo_bar ${__send__('foo.bar')}
|
587
|
-
</record>
|
588
|
-
]
|
589
|
-
d = create_driver(config)
|
590
|
-
record = {
|
591
|
-
"number" => "-",
|
592
|
-
"hex" => "0x10",
|
593
|
-
"foo.bar" => "foo.bar",
|
594
|
-
"@timestamp" => 10,
|
595
|
-
"message" => "10",
|
596
|
-
}
|
597
|
-
d.run { d.feed(@tag, @time, record) }
|
598
|
-
filtered = d.filtered
|
599
|
-
filtered.each do |t, r|
|
600
|
-
assert { r['_message'] == "prefix-#{record['message']}-suffix" }
|
601
|
-
assert { r['_time'] == Time.at(@time) }
|
602
|
-
assert { r['_number'] == 0 }
|
603
|
-
assert { r['_match'] == record['hex'] }
|
604
|
-
assert { r['_timestamp'] == record['@timestamp'] }
|
605
|
-
assert { r['_foo_bar'] == record['foo.bar'] }
|
606
|
-
end
|
607
535
|
end
|
608
536
|
end
|