fluentd 0.14.7-x86-mingw32 → 0.14.10-x86-mingw32
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/.gitignore +2 -0
- data/.travis.yml +2 -0
- data/CONTRIBUTING.md +6 -1
- data/ChangeLog +95 -0
- data/Rakefile +21 -0
- data/appveyor.yml +1 -0
- data/code-of-conduct.md +3 -0
- data/example/out_exec_filter.conf +42 -0
- data/fluentd.gemspec +1 -1
- data/lib/fluent/agent.rb +2 -2
- data/lib/fluent/command/binlog_reader.rb +1 -1
- data/lib/fluent/command/cat.rb +15 -4
- data/lib/fluent/compat/output.rb +14 -9
- data/lib/fluent/compat/parser.rb +141 -11
- data/lib/fluent/config/configure_proxy.rb +2 -11
- data/lib/fluent/config/section.rb +8 -1
- data/lib/fluent/configurable.rb +1 -3
- data/lib/fluent/env.rb +1 -1
- data/lib/fluent/log.rb +1 -1
- data/lib/fluent/plugin/base.rb +17 -0
- data/lib/fluent/plugin/filter_parser.rb +108 -0
- data/lib/fluent/plugin/filter_record_transformer.rb +14 -35
- data/lib/fluent/plugin/filter_stdout.rb +1 -1
- data/lib/fluent/plugin/formatter.rb +5 -0
- data/lib/fluent/plugin/formatter_msgpack.rb +4 -0
- data/lib/fluent/plugin/formatter_stdout.rb +3 -2
- data/lib/fluent/plugin/formatter_tsv.rb +34 -0
- data/lib/fluent/plugin/in_exec.rb +48 -93
- data/lib/fluent/plugin/in_forward.rb +66 -265
- data/lib/fluent/plugin/in_http.rb +68 -65
- data/lib/fluent/plugin/in_monitor_agent.rb +8 -4
- data/lib/fluent/plugin/in_syslog.rb +42 -58
- 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/multi_output.rb +1 -3
- data/lib/fluent/plugin/out_exec.rb +58 -71
- data/lib/fluent/plugin/out_exec_filter.rb +199 -279
- data/lib/fluent/plugin/out_file.rb +172 -81
- data/lib/fluent/plugin/out_forward.rb +229 -206
- data/lib/fluent/plugin/out_stdout.rb +6 -21
- data/lib/fluent/plugin/output.rb +90 -59
- data/lib/fluent/plugin/parser.rb +121 -61
- data/lib/fluent/plugin/parser_csv.rb +9 -3
- data/lib/fluent/plugin/parser_json.rb +37 -35
- data/lib/fluent/plugin/parser_ltsv.rb +11 -19
- data/lib/fluent/plugin/parser_msgpack.rb +50 -0
- data/lib/fluent/plugin/parser_regexp.rb +15 -42
- data/lib/fluent/plugin/parser_tsv.rb +8 -3
- data/lib/fluent/plugin_helper.rb +10 -1
- data/lib/fluent/plugin_helper/child_process.rb +139 -73
- data/lib/fluent/plugin_helper/compat_parameters.rb +93 -4
- data/lib/fluent/plugin_helper/event_emitter.rb +14 -1
- data/lib/fluent/plugin_helper/event_loop.rb +24 -6
- data/lib/fluent/plugin_helper/extract.rb +16 -4
- data/lib/fluent/plugin_helper/formatter.rb +9 -11
- data/lib/fluent/plugin_helper/inject.rb +16 -1
- data/lib/fluent/plugin_helper/parser.rb +3 -3
- 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/root_agent.rb +1 -1
- data/lib/fluent/test/driver/base.rb +95 -49
- data/lib/fluent/test/driver/base_owner.rb +18 -8
- data/lib/fluent/test/driver/multi_output.rb +2 -1
- data/lib/fluent/test/driver/output.rb +29 -6
- data/lib/fluent/test/helpers.rb +3 -1
- data/lib/fluent/test/log.rb +4 -0
- data/lib/fluent/test/startup_shutdown.rb +13 -0
- data/lib/fluent/time.rb +14 -8
- data/lib/fluent/version.rb +1 -1
- data/lib/fluent/winsvc.rb +1 -1
- data/test/command/test_binlog_reader.rb +5 -1
- data/test/compat/test_parser.rb +10 -0
- data/test/config/test_configurable.rb +193 -0
- data/test/config/test_configure_proxy.rb +0 -43
- data/test/helper.rb +36 -1
- data/test/plugin/test_base.rb +16 -0
- data/test/plugin/test_filter_parser.rb +665 -0
- data/test/plugin/test_filter_record_transformer.rb +36 -100
- data/test/plugin/test_filter_stdout.rb +18 -27
- data/test/plugin/test_in_dummy.rb +1 -1
- data/test/plugin/test_in_exec.rb +206 -94
- data/test/plugin/test_in_forward.rb +268 -347
- data/test/plugin/test_in_http.rb +310 -186
- 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_exec.rb +223 -68
- data/test/plugin/test_out_exec_filter.rb +520 -169
- data/test/plugin/test_out_file.rb +637 -177
- data/test/plugin/test_out_forward.rb +242 -234
- data/test/plugin/test_out_null.rb +1 -1
- data/test/plugin/test_out_secondary_file.rb +4 -2
- data/test/plugin/test_out_stdout.rb +14 -35
- data/test/plugin/test_output_as_buffered.rb +60 -2
- data/test/plugin/test_parser.rb +359 -0
- data/test/plugin/test_parser_csv.rb +1 -2
- data/test/plugin/test_parser_json.rb +3 -4
- data/test/plugin/test_parser_labeled_tsv.rb +1 -2
- data/test/plugin/test_parser_none.rb +1 -2
- data/test/plugin/test_parser_regexp.rb +8 -4
- data/test/plugin/test_parser_tsv.rb +4 -3
- data/test/plugin_helper/test_child_process.rb +184 -0
- data/test/plugin_helper/test_compat_parameters.rb +88 -1
- data/test/plugin_helper/test_extract.rb +0 -1
- data/test/plugin_helper/test_formatter.rb +5 -2
- data/test/plugin_helper/test_inject.rb +21 -0
- data/test/plugin_helper/test_parser.rb +6 -5
- data/test/plugin_helper/test_server.rb +905 -0
- data/test/test_event_time.rb +3 -1
- data/test/test_output.rb +53 -2
- data/test/test_plugin_classes.rb +20 -0
- data/test/test_root_agent.rb +139 -0
- data/test/test_test_drivers.rb +135 -0
- metadata +28 -8
- data/test/plugin/test_parser_base.rb +0 -32
@@ -184,49 +184,6 @@ module Fluent::Config
|
|
184
184
|
end
|
185
185
|
end
|
186
186
|
|
187
|
-
sub_test_case '#config_param without default values cause error if section is configured as init:true' do
|
188
|
-
setup do
|
189
|
-
@proxy = Fluent::Config::ConfigureProxy.new(:section, type_lookup: @type_lookup)
|
190
|
-
end
|
191
|
-
|
192
|
-
test 'with simple config_param with default value' do
|
193
|
-
assert_nothing_raised do
|
194
|
-
@proxy.config_section :subsection, init: true do
|
195
|
-
config_param :param1, :integer, default: 1
|
196
|
-
end
|
197
|
-
end
|
198
|
-
end
|
199
|
-
test 'with simple config_param without default value' do
|
200
|
-
assert_raise ArgumentError do
|
201
|
-
@proxy.config_section :subsection, init: true do
|
202
|
-
config_param :param1, :integer
|
203
|
-
end
|
204
|
-
end
|
205
|
-
end
|
206
|
-
test 'with config_param with config_set_default' do
|
207
|
-
assert_nothing_raised do
|
208
|
-
@proxy.config_section :subsection, init: true do
|
209
|
-
config_param :param1, :integer
|
210
|
-
config_set_default :param1, 1
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
|
-
test 'with config_argument' do
|
215
|
-
assert_raise ArgumentError do
|
216
|
-
@proxy.config_section :subsection, init: true do
|
217
|
-
config_argument :param0, :string
|
218
|
-
end
|
219
|
-
end
|
220
|
-
end
|
221
|
-
test 'with config_argument with default value' do
|
222
|
-
assert_nothing_raised do
|
223
|
-
@proxy.config_section :subsection, init: true do
|
224
|
-
config_argument :param0, :string, default: ''
|
225
|
-
end
|
226
|
-
end
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
187
|
sub_test_case '#config_set_desc' do
|
231
188
|
setup do
|
232
189
|
@proxy = Fluent::Config::ConfigureProxy.new(:section, type_lookup: @type_lookup)
|
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
|
data/test/plugin/test_base.rb
CHANGED
@@ -72,4 +72,20 @@ class BaseTest < Test::Unit::TestCase
|
|
72
72
|
assert_equal 'myvalue1', p2.myparam1
|
73
73
|
assert_equal 99, p2.mysection.myparam2
|
74
74
|
end
|
75
|
+
|
76
|
+
test 'provides #string_safe_encoding to scrub invalid sequence string with info logging' do
|
77
|
+
logger = Fluent::Test::TestLogger.new
|
78
|
+
m = Module.new do
|
79
|
+
define_method(:log) do
|
80
|
+
logger
|
81
|
+
end
|
82
|
+
end
|
83
|
+
@p.extend m
|
84
|
+
assert_equal [], logger.logs
|
85
|
+
|
86
|
+
ret = @p.string_safe_encoding("abc\xff.\x01f"){|s| s.split(/\./) }
|
87
|
+
assert_equal ['abc?', "\u0001f"], ret
|
88
|
+
assert_equal 1, logger.logs.size
|
89
|
+
assert{ logger.logs.first.include?("invalid byte sequence is replaced in ") }
|
90
|
+
end
|
75
91
|
end
|
@@ -0,0 +1,665 @@
|
|
1
|
+
require_relative '../helper'
|
2
|
+
require 'timecop'
|
3
|
+
require 'fluent/test/driver/filter'
|
4
|
+
require 'fluent/plugin/filter_parser'
|
5
|
+
require 'flexmock/test_unit'
|
6
|
+
|
7
|
+
class ParserFilterTest < Test::Unit::TestCase
|
8
|
+
include FlexMock::TestCase
|
9
|
+
|
10
|
+
def setup
|
11
|
+
Fluent::Test.setup
|
12
|
+
@tag = 'test'
|
13
|
+
@default_time = Time.parse('2010-05-04 03:02:01 UTC')
|
14
|
+
Timecop.freeze(@default_time)
|
15
|
+
end
|
16
|
+
|
17
|
+
def teardown
|
18
|
+
super
|
19
|
+
Timecop.return
|
20
|
+
end
|
21
|
+
|
22
|
+
def assert_equal_parsed_time(expected, actual)
|
23
|
+
if expected.is_a?(Integer)
|
24
|
+
assert_equal(expected, actual.to_i)
|
25
|
+
else
|
26
|
+
assert_equal_event_time(expected, actual)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
ParserError = Fluent::Plugin::Parser::ParserError
|
31
|
+
CONFIG = %[
|
32
|
+
key_name message
|
33
|
+
reserve_data true
|
34
|
+
<parse>
|
35
|
+
@type regexp
|
36
|
+
expression /^(?<x>.)(?<y>.) (?<time>.+)$/
|
37
|
+
time_format %Y%m%d%H%M%S
|
38
|
+
</parse>
|
39
|
+
]
|
40
|
+
|
41
|
+
def create_driver(conf=CONFIG)
|
42
|
+
Fluent::Test::Driver::Filter.new(Fluent::Plugin::ParserFilter).configure(conf)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_configure
|
46
|
+
assert_raise(Fluent::ConfigError) {
|
47
|
+
create_driver('')
|
48
|
+
}
|
49
|
+
assert_raise(Fluent::ConfigError) {
|
50
|
+
create_driver %[
|
51
|
+
key_name foo
|
52
|
+
<parse>
|
53
|
+
@type unknown_format_that_will_never_be_implemented
|
54
|
+
</parse>
|
55
|
+
]
|
56
|
+
}
|
57
|
+
assert_nothing_raised {
|
58
|
+
create_driver %[
|
59
|
+
key_name foo
|
60
|
+
<parse>
|
61
|
+
@type regexp
|
62
|
+
expression /(?<x>.)/
|
63
|
+
</parse>
|
64
|
+
]
|
65
|
+
}
|
66
|
+
assert_nothing_raised {
|
67
|
+
create_driver %[
|
68
|
+
key_name foo
|
69
|
+
<parse>
|
70
|
+
@type json
|
71
|
+
</parse>
|
72
|
+
]
|
73
|
+
}
|
74
|
+
assert_nothing_raised {
|
75
|
+
create_driver %[
|
76
|
+
key_name foo
|
77
|
+
format json
|
78
|
+
]
|
79
|
+
}
|
80
|
+
assert_nothing_raised {
|
81
|
+
create_driver %[
|
82
|
+
key_name foo
|
83
|
+
<parse>
|
84
|
+
@type ltsv
|
85
|
+
</parse>
|
86
|
+
]
|
87
|
+
}
|
88
|
+
assert_nothing_raised {
|
89
|
+
create_driver %[
|
90
|
+
key_name message
|
91
|
+
<parse>
|
92
|
+
@type regexp
|
93
|
+
expression /^col1=(?<col1>.+) col2=(?<col2>.+)$/
|
94
|
+
</parse>
|
95
|
+
]
|
96
|
+
}
|
97
|
+
d = create_driver %[
|
98
|
+
key_name foo
|
99
|
+
<parse>
|
100
|
+
@type regexp
|
101
|
+
expression /(?<x>.)/
|
102
|
+
</parse>
|
103
|
+
]
|
104
|
+
assert_false d.instance.reserve_data
|
105
|
+
end
|
106
|
+
|
107
|
+
# CONFIG = %[
|
108
|
+
# remove_prefix test
|
109
|
+
# add_prefix parsed
|
110
|
+
# key_name message
|
111
|
+
# format /^(?<x>.)(?<y>.) (?<time>.+)$/
|
112
|
+
# time_format %Y%m%d%H%M%S
|
113
|
+
# reserve_data true
|
114
|
+
# ]
|
115
|
+
def test_filter
|
116
|
+
d1 = create_driver(CONFIG)
|
117
|
+
time = event_time("2012-01-02 13:14:15")
|
118
|
+
d1.run(default_tag: @tag) do
|
119
|
+
d1.feed(time, {'message' => '12 20120402182059'})
|
120
|
+
d1.feed(time, {'message' => '34 20120402182100'})
|
121
|
+
d1.feed(time, {'message' => '56 20120402182100'})
|
122
|
+
d1.feed(time, {'message' => '78 20120402182101'})
|
123
|
+
d1.feed(time, {'message' => '90 20120402182100'})
|
124
|
+
end
|
125
|
+
filtered = d1.filtered
|
126
|
+
assert_equal 5, filtered.length
|
127
|
+
|
128
|
+
first = filtered[0]
|
129
|
+
assert_equal_event_time event_time("2012-04-02 18:20:59"), first[0]
|
130
|
+
assert_equal '1', first[1]['x']
|
131
|
+
assert_equal '2', first[1]['y']
|
132
|
+
assert_equal '12 20120402182059', first[1]['message']
|
133
|
+
|
134
|
+
second = filtered[1]
|
135
|
+
assert_equal_event_time event_time("2012-04-02 18:21:00"), second[0]
|
136
|
+
assert_equal '3', second[1]['x']
|
137
|
+
assert_equal '4', second[1]['y']
|
138
|
+
|
139
|
+
third = filtered[2]
|
140
|
+
assert_equal_event_time event_time("2012-04-02 18:21:00"), third[0]
|
141
|
+
assert_equal '5', third[1]['x']
|
142
|
+
assert_equal '6', third[1]['y']
|
143
|
+
|
144
|
+
fourth = filtered[3]
|
145
|
+
assert_equal_event_time event_time("2012-04-02 18:21:01"), fourth[0]
|
146
|
+
assert_equal '7', fourth[1]['x']
|
147
|
+
assert_equal '8', fourth[1]['y']
|
148
|
+
|
149
|
+
fifth = filtered[4]
|
150
|
+
assert_equal_event_time event_time("2012-04-02 18:21:00"), fifth[0]
|
151
|
+
assert_equal '9', fifth[1]['x']
|
152
|
+
assert_equal '0', fifth[1]['y']
|
153
|
+
|
154
|
+
d2 = create_driver(%[
|
155
|
+
key_name data
|
156
|
+
format /^(?<x>.)(?<y>.) (?<t>.+)$/
|
157
|
+
])
|
158
|
+
time = Fluent::EventTime.from_time(@default_time) # EventTime emit test
|
159
|
+
d2.run(default_tag: @tag) do
|
160
|
+
d2.feed(time, {'data' => '12 20120402182059'})
|
161
|
+
d2.feed(time, {'data' => '34 20120402182100'})
|
162
|
+
end
|
163
|
+
filtered = d2.filtered
|
164
|
+
assert_equal 2, filtered.length
|
165
|
+
|
166
|
+
first = filtered[0]
|
167
|
+
assert_equal_event_time time, first[0]
|
168
|
+
assert_nil first[1]['data']
|
169
|
+
assert_equal '1', first[1]['x']
|
170
|
+
assert_equal '2', first[1]['y']
|
171
|
+
assert_equal '20120402182059', first[1]['t']
|
172
|
+
|
173
|
+
second = filtered[1]
|
174
|
+
assert_equal_event_time time, second[0]
|
175
|
+
assert_nil second[1]['data']
|
176
|
+
assert_equal '3', second[1]['x']
|
177
|
+
assert_equal '4', second[1]['y']
|
178
|
+
assert_equal '20120402182100', second[1]['t']
|
179
|
+
|
180
|
+
d3 = create_driver(%[
|
181
|
+
key_name data
|
182
|
+
<parse>
|
183
|
+
@type regexp
|
184
|
+
expression /^(?<x>[0-9])(?<y>[0-9]) (?<t>.+)$/
|
185
|
+
</parse>
|
186
|
+
])
|
187
|
+
time = Time.parse("2012-04-02 18:20:59").to_i
|
188
|
+
d3.run(default_tag: @tag) do
|
189
|
+
d3.feed(time, {'data' => '12 20120402182059'})
|
190
|
+
d3.feed(time, {'data' => '34 20120402182100'})
|
191
|
+
d3.feed(time, {'data' => 'xy 20120402182101'})
|
192
|
+
end
|
193
|
+
filtered = d3.filtered
|
194
|
+
assert_equal 2, filtered.length
|
195
|
+
|
196
|
+
d4 = create_driver(%[
|
197
|
+
key_name data
|
198
|
+
<parse>
|
199
|
+
@type json
|
200
|
+
</parse>
|
201
|
+
])
|
202
|
+
time = Time.parse("2012-04-02 18:20:59").to_i
|
203
|
+
d4.run(default_tag: @tag) do
|
204
|
+
d4.feed(time, {'data' => '{"xxx":"first","yyy":"second"}', 'xxx' => 'x', 'yyy' => 'y'})
|
205
|
+
d4.feed(time, {'data' => 'foobar', 'xxx' => 'x', 'yyy' => 'y'})
|
206
|
+
end
|
207
|
+
filtered = d4.filtered
|
208
|
+
assert_equal 1, filtered.length
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_filter_with_reserved_data
|
213
|
+
d1 = create_driver(%[
|
214
|
+
key_name data
|
215
|
+
reserve_data yes
|
216
|
+
<parse>
|
217
|
+
@type regexp
|
218
|
+
expression /^(?<x>\\d)(?<y>\\d) (?<t>.+)$/
|
219
|
+
</parse>
|
220
|
+
])
|
221
|
+
time = event_time("2012-04-02 18:20:59")
|
222
|
+
d1.run(default_tag: @tag) do
|
223
|
+
d1.feed(time, {'data' => '12 20120402182059'})
|
224
|
+
d1.feed(time, {'data' => '34 20120402182100'})
|
225
|
+
d1.feed(time, {'data' => 'xy 20120402182101'})
|
226
|
+
end
|
227
|
+
filtered = d1.filtered
|
228
|
+
assert_equal 3, filtered.length
|
229
|
+
|
230
|
+
d2 = create_driver(%[
|
231
|
+
key_name data
|
232
|
+
reserve_data yes
|
233
|
+
<parse>
|
234
|
+
@type json
|
235
|
+
</parse>
|
236
|
+
])
|
237
|
+
time = Fluent::EventTime.from_time(@default_time)
|
238
|
+
d2.run(default_tag: @tag) do
|
239
|
+
d2.feed(time, {'data' => '{"xxx":"first","yyy":"second"}', 'xxx' => 'x', 'yyy' => 'y'})
|
240
|
+
d2.feed(time, {'data' => 'foobar', 'xxx' => 'x', 'yyy' => 'y'})
|
241
|
+
end
|
242
|
+
filtered = d2.filtered
|
243
|
+
assert_equal 2, filtered.length
|
244
|
+
|
245
|
+
first = filtered[0]
|
246
|
+
assert_equal_event_time time, first[0]
|
247
|
+
assert_equal '{"xxx":"first","yyy":"second"}', first[1]['data']
|
248
|
+
assert_equal 'first', first[1]['xxx']
|
249
|
+
assert_equal 'second', first[1]['yyy']
|
250
|
+
|
251
|
+
second = filtered[1]
|
252
|
+
assert_equal_event_time time, second[0]
|
253
|
+
assert_equal 'foobar', second[1]['data']
|
254
|
+
assert_equal 'x', second[1]['xxx']
|
255
|
+
assert_equal 'y', second[1]['yyy']
|
256
|
+
end
|
257
|
+
|
258
|
+
|
259
|
+
CONFIG_LTSV = %[
|
260
|
+
key_name data
|
261
|
+
<parse>
|
262
|
+
@type ltsv
|
263
|
+
</parse>
|
264
|
+
]
|
265
|
+
CONFIG_LTSV_WITH_TYPES = %[
|
266
|
+
key_name data
|
267
|
+
<parse>
|
268
|
+
@type ltsv
|
269
|
+
types i:integer,s:string,f:float,b:bool
|
270
|
+
</parse>
|
271
|
+
]
|
272
|
+
data(:event_time => lambda { |time| Fluent::EventTime.from_time(time) },
|
273
|
+
:int_time => lambda { |time| time.to_i })
|
274
|
+
def test_filter_ltsv(time_parse)
|
275
|
+
d = create_driver(CONFIG_LTSV)
|
276
|
+
time = time_parse.call(@default_time)
|
277
|
+
d.run(default_tag: @tag) do
|
278
|
+
d.feed(time, {'data' => "xxx:first\tyyy:second", 'xxx' => 'x', 'yyy' => 'y'})
|
279
|
+
d.feed(time, {'data' => "xxx:first\tyyy:second2", 'xxx' => 'x', 'yyy' => 'y'})
|
280
|
+
end
|
281
|
+
filtered = d.filtered
|
282
|
+
assert_equal 2, filtered.length
|
283
|
+
|
284
|
+
first = filtered[0]
|
285
|
+
assert_equal_parsed_time time, first[0]
|
286
|
+
assert_nil first[1]['data']
|
287
|
+
assert_equal 'first', first[1]['xxx']
|
288
|
+
assert_equal 'second', first[1]['yyy']
|
289
|
+
|
290
|
+
second = filtered[1]
|
291
|
+
assert_equal_parsed_time time, second[0]
|
292
|
+
assert_nil first[1]['data']
|
293
|
+
assert_equal 'first', second[1]['xxx']
|
294
|
+
assert_equal 'second2', second[1]['yyy']
|
295
|
+
|
296
|
+
d = create_driver(CONFIG_LTSV + %[reserve_data yes])
|
297
|
+
time = @default_time.to_i
|
298
|
+
d.run(default_tag: @tag) do
|
299
|
+
d.feed(time, {'data' => "xxx:first\tyyy:second", 'xxx' => 'x', 'yyy' => 'y'})
|
300
|
+
d.feed(time, {'data' => "xxx:first\tyyy:second2", 'xxx' => 'x', 'yyy' => 'y'})
|
301
|
+
end
|
302
|
+
filtered = d.filtered
|
303
|
+
assert_equal 2, filtered.length
|
304
|
+
|
305
|
+
first = filtered[0]
|
306
|
+
assert_equal_parsed_time time, first[0]
|
307
|
+
assert_equal "xxx:first\tyyy:second", first[1]['data']
|
308
|
+
assert_equal 'first', first[1]['xxx']
|
309
|
+
assert_equal 'second', first[1]['yyy']
|
310
|
+
|
311
|
+
second = filtered[1]
|
312
|
+
assert_equal_parsed_time time, second[0]
|
313
|
+
assert_equal "xxx:first\tyyy:second", first[1]['data']
|
314
|
+
assert_equal 'first', second[1]['xxx']
|
315
|
+
assert_equal 'second2', second[1]['yyy']
|
316
|
+
|
317
|
+
# convert types
|
318
|
+
#d = create_driver(CONFIG_LTSV + %[
|
319
|
+
d = create_driver(CONFIG_LTSV_WITH_TYPES)
|
320
|
+
time = @default_time.to_i
|
321
|
+
d.run do
|
322
|
+
d.feed(@tag, time, {'data' => "i:1\ts:2\tf:3\tb:true\tx:123"})
|
323
|
+
end
|
324
|
+
filtered = d.filtered
|
325
|
+
assert_equal 1, filtered.length
|
326
|
+
|
327
|
+
first = filtered[0]
|
328
|
+
assert_equal_parsed_time time, first[0]
|
329
|
+
assert_equal 1, first[1]['i']
|
330
|
+
assert_equal '2', first[1]['s']
|
331
|
+
assert_equal 3.0, first[1]['f']
|
332
|
+
assert_equal true, first[1]['b']
|
333
|
+
assert_equal '123', first[1]['x']
|
334
|
+
end
|
335
|
+
|
336
|
+
CONFIG_TSV = %[
|
337
|
+
key_name data
|
338
|
+
<parse>
|
339
|
+
@type tsv
|
340
|
+
keys key1,key2,key3
|
341
|
+
</parse>
|
342
|
+
]
|
343
|
+
data(:event_time => lambda { |time| Fluent::EventTime.from_time(time) },
|
344
|
+
:int_time => lambda { |time| time.to_i })
|
345
|
+
def test_filter_tsv(time_parse)
|
346
|
+
d = create_driver(CONFIG_TSV)
|
347
|
+
time = time_parse.call(@default_time)
|
348
|
+
d.run do
|
349
|
+
d.feed(@tag, time, {'data' => "value1\tvalue2\tvalueThree", 'xxx' => 'x', 'yyy' => 'y'})
|
350
|
+
end
|
351
|
+
filtered = d.filtered
|
352
|
+
assert_equal 1, filtered.length
|
353
|
+
|
354
|
+
first = filtered[0]
|
355
|
+
assert_equal_parsed_time time, first[0]
|
356
|
+
assert_nil first[1]['data']
|
357
|
+
assert_equal 'value1', first[1]['key1']
|
358
|
+
assert_equal 'value2', first[1]['key2']
|
359
|
+
assert_equal 'valueThree', first[1]['key3']
|
360
|
+
end
|
361
|
+
|
362
|
+
CONFIG_CSV = %[
|
363
|
+
key_name data
|
364
|
+
<parse>
|
365
|
+
@type csv
|
366
|
+
keys key1,key2,key3
|
367
|
+
</parse>
|
368
|
+
]
|
369
|
+
CONFIG_CSV_COMPAT = %[
|
370
|
+
key_name data
|
371
|
+
format csv
|
372
|
+
keys key1,key2,key3
|
373
|
+
]
|
374
|
+
data(new_conf: CONFIG_CSV,
|
375
|
+
compat_conf: CONFIG_CSV_COMPAT)
|
376
|
+
def test_filter_csv(conf)
|
377
|
+
d = create_driver(conf)
|
378
|
+
time = @default_time.to_i
|
379
|
+
d.run do
|
380
|
+
d.feed(@tag, time, {'data' => 'value1,"value2","value""ThreeYes!"', 'xxx' => 'x', 'yyy' => 'y'})
|
381
|
+
end
|
382
|
+
filtered = d.filtered
|
383
|
+
assert_equal 1, filtered.length
|
384
|
+
|
385
|
+
first = filtered[0]
|
386
|
+
assert_equal time, first[0]
|
387
|
+
assert_nil first[1]['data']
|
388
|
+
assert_equal 'value1', first[1]['key1']
|
389
|
+
assert_equal 'value2', first[1]['key2']
|
390
|
+
assert_equal 'value"ThreeYes!', first[1]['key3']
|
391
|
+
end
|
392
|
+
|
393
|
+
CONFIG_HASH_VALUE_FIELD = %[
|
394
|
+
key_name data
|
395
|
+
hash_value_field parsed
|
396
|
+
<parse>
|
397
|
+
@type json
|
398
|
+
</parse>
|
399
|
+
]
|
400
|
+
CONFIG_HASH_VALUE_FIELD_RESERVE_DATA = %[
|
401
|
+
key_name data
|
402
|
+
reserve_data yes
|
403
|
+
hash_value_field parsed
|
404
|
+
<parse>
|
405
|
+
@type json
|
406
|
+
</parse>
|
407
|
+
]
|
408
|
+
CONFIG_HASH_VALUE_FIELD_WITH_INJECT_KEY_PREFIX = %[
|
409
|
+
key_name data
|
410
|
+
hash_value_field parsed
|
411
|
+
inject_key_prefix data.
|
412
|
+
<parse>
|
413
|
+
@type json
|
414
|
+
</parse>
|
415
|
+
]
|
416
|
+
data(:event_time => lambda { |time| Fluent::EventTime.from_time(time) },
|
417
|
+
:int_time => lambda { |time| time.to_i })
|
418
|
+
def test_filter_inject_hash_value_field(time_parse)
|
419
|
+
original = {'data' => '{"xxx":"first","yyy":"second"}', 'xxx' => 'x', 'yyy' => 'y'}
|
420
|
+
|
421
|
+
d = create_driver(CONFIG_HASH_VALUE_FIELD)
|
422
|
+
time = time_parse.call(@default_time)
|
423
|
+
d.run do
|
424
|
+
d.feed(@tag, time, original)
|
425
|
+
end
|
426
|
+
filtered = d.filtered
|
427
|
+
assert_equal 1, filtered.length
|
428
|
+
|
429
|
+
first = filtered[0]
|
430
|
+
assert_equal_parsed_time time, first[0]
|
431
|
+
|
432
|
+
record = first[1]
|
433
|
+
assert_equal 1, record.keys.size
|
434
|
+
assert_equal({"xxx"=>"first","yyy"=>"second"}, record['parsed'])
|
435
|
+
|
436
|
+
d = create_driver(CONFIG_HASH_VALUE_FIELD_RESERVE_DATA)
|
437
|
+
time = @default_time.to_i
|
438
|
+
d.run do
|
439
|
+
d.feed(@tag, time, original)
|
440
|
+
end
|
441
|
+
filtered = d.filtered
|
442
|
+
assert_equal 1, filtered.length
|
443
|
+
|
444
|
+
first = filtered[0]
|
445
|
+
assert_equal_parsed_time time, first[0]
|
446
|
+
|
447
|
+
record = first[1]
|
448
|
+
assert_equal 4, record.keys.size
|
449
|
+
assert_equal original['data'], record['data']
|
450
|
+
assert_equal original['xxx'], record['xxx']
|
451
|
+
assert_equal original['yyy'], record['yyy']
|
452
|
+
assert_equal({"xxx"=>"first","yyy"=>"second"}, record['parsed'])
|
453
|
+
|
454
|
+
d = create_driver(CONFIG_HASH_VALUE_FIELD_WITH_INJECT_KEY_PREFIX)
|
455
|
+
time = @default_time.to_i
|
456
|
+
d.run do
|
457
|
+
d.feed(@tag, time, original)
|
458
|
+
end
|
459
|
+
filtered = d.filtered
|
460
|
+
assert_equal 1, filtered.length
|
461
|
+
|
462
|
+
first = filtered[0]
|
463
|
+
assert_equal_parsed_time time, first[0]
|
464
|
+
|
465
|
+
record = first[1]
|
466
|
+
assert_equal 1, record.keys.size
|
467
|
+
assert_equal({"data.xxx"=>"first","data.yyy"=>"second"}, record['parsed'])
|
468
|
+
end
|
469
|
+
|
470
|
+
CONFIG_DONT_PARSE_TIME = %[
|
471
|
+
key_name data
|
472
|
+
reserve_time true
|
473
|
+
<parse>
|
474
|
+
@type json
|
475
|
+
keep_time_key true
|
476
|
+
</parse>
|
477
|
+
]
|
478
|
+
CONFIG_DONT_PARSE_TIME_COMPAT = %[
|
479
|
+
key_name data
|
480
|
+
reserve_time true
|
481
|
+
format json
|
482
|
+
keep_time_key true
|
483
|
+
]
|
484
|
+
data(new_conf: CONFIG_DONT_PARSE_TIME,
|
485
|
+
compat_conf: CONFIG_DONT_PARSE_TIME_COMPAT)
|
486
|
+
def test_time_should_be_reserved(conf)
|
487
|
+
t = Time.now.to_i
|
488
|
+
d = create_driver(conf)
|
489
|
+
d.run(default_tag: @tag) do
|
490
|
+
d.feed(t, {'data' => '{"time":1383190430, "f1":"v1"}'})
|
491
|
+
d.feed(t, {'data' => '{"time":"1383190430", "f1":"v1"}'})
|
492
|
+
d.feed(t, {'data' => '{"time":"2013-10-31 12:34:03 +0900", "f1":"v1"}'})
|
493
|
+
end
|
494
|
+
filtered = d.filtered
|
495
|
+
assert_equal 3, filtered.length
|
496
|
+
|
497
|
+
assert_equal 'v1', filtered[0][1]['f1']
|
498
|
+
assert_equal 1383190430, filtered[0][1]['time']
|
499
|
+
assert_equal t, filtered[0][0]
|
500
|
+
|
501
|
+
assert_equal 'v1', filtered[1][1]['f1']
|
502
|
+
assert_equal "1383190430", filtered[1][1]['time']
|
503
|
+
assert_equal t, filtered[1][0]
|
504
|
+
|
505
|
+
assert_equal 'v1', filtered[2][1]['f1']
|
506
|
+
assert_equal '2013-10-31 12:34:03 +0900', filtered[2][1]['time']
|
507
|
+
assert_equal t, filtered[2][0]
|
508
|
+
end
|
509
|
+
|
510
|
+
CONFIG_INVALID_TIME_VALUE = %[
|
511
|
+
key_name data
|
512
|
+
<parse>
|
513
|
+
@type json
|
514
|
+
</parse>
|
515
|
+
] # 'time' is implicit @time_key
|
516
|
+
def test_filter_invalid_time_data
|
517
|
+
# should not raise errors
|
518
|
+
time = Time.now.to_i
|
519
|
+
d = create_driver(CONFIG_INVALID_TIME_VALUE)
|
520
|
+
assert_nothing_raised {
|
521
|
+
d.run(default_tag: @tag) do
|
522
|
+
d.feed(time, {'data' => '{"time":[], "f1":"v1"}'})
|
523
|
+
d.feed(time, {'data' => '{"time":"thisisnottime", "f1":"v1"}'})
|
524
|
+
end
|
525
|
+
}
|
526
|
+
filtered = d.filtered
|
527
|
+
assert_equal 1, filtered.length
|
528
|
+
|
529
|
+
assert_equal 0, filtered[0][0].to_i
|
530
|
+
assert_equal 'v1', filtered[0][1]['f1']
|
531
|
+
assert_equal nil, filtered[0][1]['time']
|
532
|
+
end
|
533
|
+
|
534
|
+
# REGEXP = /^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$/
|
535
|
+
|
536
|
+
CONFIG_NOT_REPLACE = %[
|
537
|
+
key_name data
|
538
|
+
<parse>
|
539
|
+
@type regexp
|
540
|
+
expression /^(?<message>.*)$/
|
541
|
+
</parse>
|
542
|
+
]
|
543
|
+
CONFIG_INVALID_BYTE = CONFIG_NOT_REPLACE + %[
|
544
|
+
replace_invalid_sequence true
|
545
|
+
]
|
546
|
+
def test_filter_invalid_byte
|
547
|
+
invalid_utf8 = "\xff".force_encoding('UTF-8')
|
548
|
+
|
549
|
+
d = create_driver(CONFIG_NOT_REPLACE)
|
550
|
+
d.run do
|
551
|
+
d.feed(@tag, Fluent::EventTime.now.to_i, {'data' => invalid_utf8})
|
552
|
+
end
|
553
|
+
error_event = d.error_events.first
|
554
|
+
assert_equal "test", error_event[0]
|
555
|
+
assert_instance_of ArgumentError, error_event[3]
|
556
|
+
|
557
|
+
d = create_driver(CONFIG_INVALID_BYTE)
|
558
|
+
assert_nothing_raised {
|
559
|
+
d.run do
|
560
|
+
d.feed(@tag, Fluent::EventTime.now.to_i, {'data' => invalid_utf8})
|
561
|
+
end
|
562
|
+
}
|
563
|
+
filtered = d.filtered
|
564
|
+
assert_equal 1, filtered.length
|
565
|
+
assert_nil filtered[0][1]['data']
|
566
|
+
assert_equal '?'.force_encoding('UTF-8'), filtered[0][1]['message']
|
567
|
+
|
568
|
+
d = create_driver(CONFIG_INVALID_BYTE + %[reserve_data yes])
|
569
|
+
assert_nothing_raised {
|
570
|
+
d.run do
|
571
|
+
d.feed(@tag, Fluent::EventTime.now.to_i, {'data' => invalid_utf8})
|
572
|
+
end
|
573
|
+
}
|
574
|
+
filtered = d.filtered
|
575
|
+
assert_equal 1, filtered.length
|
576
|
+
assert_equal invalid_utf8, filtered[0][1]['data']
|
577
|
+
assert_equal '?'.force_encoding('UTF-8'), filtered[0][1]['message']
|
578
|
+
|
579
|
+
invalid_ascii = "\xff".force_encoding('US-ASCII')
|
580
|
+
d = create_driver(CONFIG_INVALID_BYTE)
|
581
|
+
assert_nothing_raised {
|
582
|
+
d.run do
|
583
|
+
d.feed(@tag, Fluent::EventTime.now.to_i, {'data' => invalid_ascii})
|
584
|
+
end
|
585
|
+
}
|
586
|
+
filtered = d.filtered
|
587
|
+
assert_equal 1, filtered.length
|
588
|
+
assert_nil filtered[0][1]['data']
|
589
|
+
assert_equal '?'.force_encoding('US-ASCII'), filtered[0][1]['message']
|
590
|
+
end
|
591
|
+
|
592
|
+
CONFIG_NOT_IGNORE = %[
|
593
|
+
key_name data
|
594
|
+
hash_value_field parsed
|
595
|
+
<parse>
|
596
|
+
@type json
|
597
|
+
</parse>
|
598
|
+
]
|
599
|
+
CONFIG_PASS_SAME_RECORD = CONFIG_NOT_IGNORE + %[
|
600
|
+
reserve_data true
|
601
|
+
]
|
602
|
+
def test_filter_key_not_exist
|
603
|
+
d = create_driver(CONFIG_NOT_IGNORE)
|
604
|
+
flexmock(d.instance.router).should_receive(:emit_error_event).
|
605
|
+
with(String, Integer, Hash, ArgumentError.new("data does not exist")).once
|
606
|
+
assert_nothing_raised {
|
607
|
+
d.run do
|
608
|
+
d.feed(@tag, Fluent::EventTime.now.to_i, {'foo' => 'bar'})
|
609
|
+
end
|
610
|
+
}
|
611
|
+
|
612
|
+
d = create_driver(CONFIG_PASS_SAME_RECORD)
|
613
|
+
assert_nothing_raised {
|
614
|
+
d.run do
|
615
|
+
d.feed(@tag, Fluent::EventTime.now.to_i, {'foo' => 'bar'})
|
616
|
+
end
|
617
|
+
}
|
618
|
+
filtered = d.filtered
|
619
|
+
assert_equal 1, filtered.length
|
620
|
+
assert_nil filtered[0][1]['data']
|
621
|
+
assert_equal 'bar', filtered[0][1]['foo']
|
622
|
+
end
|
623
|
+
|
624
|
+
# emit_error_event test
|
625
|
+
INVALID_MESSAGE = 'foo bar'
|
626
|
+
VALID_MESSAGE = 'col1=foo col2=bar'
|
627
|
+
|
628
|
+
def test_call_emit_error_event_when_parser_error
|
629
|
+
d = create_driver(CONFIG_INVALID_TIME_VALUE)
|
630
|
+
flexmock(d.instance.router).should_receive(:emit_error_event).
|
631
|
+
with(String, Integer, Hash, ParserError).once
|
632
|
+
d.run do
|
633
|
+
d.feed(@tag, Fluent::EventTime.now.to_i, {'data' => '{"time":[], "f1":"v1"}'})
|
634
|
+
end
|
635
|
+
end
|
636
|
+
|
637
|
+
CONFIG_UNMATCHED_PATTERN_LOG = %[
|
638
|
+
key_name message
|
639
|
+
<parse>
|
640
|
+
@type regexp
|
641
|
+
expression /^col1=(?<col1>.+) col2=(?<col2>.+)$/
|
642
|
+
</parse>
|
643
|
+
]
|
644
|
+
|
645
|
+
class UnmatchedPatternLogTest < self
|
646
|
+
setup do
|
647
|
+
@d = create_driver(CONFIG_UNMATCHED_PATTERN_LOG)
|
648
|
+
end
|
649
|
+
|
650
|
+
def test_call_emit_error_event_when_pattern_is_mismached
|
651
|
+
flexmock(@d.instance.router).should_receive(:emit_error_event).
|
652
|
+
with(String, Integer, Hash, ParserError.new("pattern not match with data '#{INVALID_MESSAGE}'")).once
|
653
|
+
@d.run do
|
654
|
+
@d.feed(@tag, Fluent::EventTime.now.to_i, {'message' => INVALID_MESSAGE})
|
655
|
+
end
|
656
|
+
end
|
657
|
+
|
658
|
+
def test_not_call_emit_error_event_when_pattern_is_mached
|
659
|
+
flexmock(@d.instance.router).should_receive(:emit_error_event).never
|
660
|
+
@d.run do
|
661
|
+
@d.feed(@tag, Fluent::EventTime.now.to_i, {'message' => VALID_MESSAGE})
|
662
|
+
end
|
663
|
+
end
|
664
|
+
end
|
665
|
+
end
|