fluentd 0.10.44 → 0.10.45
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 +7 -0
- data/ChangeLog +9 -0
- data/fluent.conf +9 -3
- data/fluentd.gemspec +1 -0
- data/lib/fluent/engine.rb +14 -5
- data/lib/fluent/load.rb +5 -1
- data/lib/fluent/log.rb +4 -4
- data/lib/fluent/parser.rb +80 -0
- data/lib/fluent/plugin/exec_util.rb +38 -2
- data/lib/fluent/plugin/in_forward.rb +5 -3
- data/lib/fluent/plugin/in_tail.rb +661 -1
- data/lib/fluent/plugin/out_exec.rb +29 -15
- data/lib/fluent/plugin/out_exec_filter.rb +8 -44
- data/lib/fluent/version.rb +1 -1
- data/test/parser.rb +81 -0
- data/test/plugin/data/2010/01/20100102-030405.log +0 -0
- data/test/plugin/data/2010/01/20100102-030406.log +0 -0
- data/test/plugin/data/2010/01/20100102.log +0 -0
- data/test/plugin/data/log/bar +0 -0
- data/test/plugin/data/log/foo/bar.log +0 -0
- data/test/plugin/data/log/test.log +0 -0
- data/test/plugin/in_tail.rb +236 -3
- data/test/plugin/out_exec.rb +44 -9
- metadata +70 -69
@@ -15,6 +15,9 @@
|
|
15
15
|
# See the License for the specific language governing permissions and
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
|
+
|
19
|
+
require 'fluent/plugin/exec_util'
|
20
|
+
|
18
21
|
module Fluent
|
19
22
|
class ExecOutput < TimeSlicedOutput
|
20
23
|
Plugin.register_output('exec', self)
|
@@ -26,41 +29,52 @@ module Fluent
|
|
26
29
|
end
|
27
30
|
|
28
31
|
config_param :command, :string
|
29
|
-
config_param :keys, :
|
32
|
+
config_param :keys, :default => [] do |val|
|
33
|
+
val.split(',')
|
34
|
+
end
|
30
35
|
config_param :tag_key, :string, :default => nil
|
31
36
|
config_param :time_key, :string, :default => nil
|
32
37
|
config_param :time_format, :string, :default => nil
|
38
|
+
config_param :format, :default => :tsv do |val|
|
39
|
+
f = ExecUtil::SUPPORTED_FORMAT[val]
|
40
|
+
raise ConfigError, "Unsupported format '#{val}'" unless f
|
41
|
+
f
|
42
|
+
end
|
33
43
|
|
34
44
|
def configure(conf)
|
35
45
|
super
|
36
46
|
|
37
|
-
@
|
47
|
+
@formatter = case @format
|
48
|
+
when :tsv
|
49
|
+
if @keys.empty?
|
50
|
+
raise ConfigError, "keys option is required on exec output for tsv format"
|
51
|
+
end
|
52
|
+
ExecUtil::TSVFormatter.new(@keys)
|
53
|
+
when :json
|
54
|
+
ExecUtil::JSONFormatter.new
|
55
|
+
when :msgpack
|
56
|
+
ExecUtil::MessagePackFormatter.new
|
57
|
+
end
|
38
58
|
|
39
59
|
if @time_key
|
40
60
|
if @time_format
|
41
61
|
tf = TimeFormatter.new(@time_format, @localtime)
|
42
62
|
@time_format_proc = tf.method(:format)
|
43
63
|
else
|
44
|
-
@time_format_proc = Proc.new {|time| time.to_s }
|
64
|
+
@time_format_proc = Proc.new { |time| time.to_s }
|
45
65
|
end
|
46
66
|
end
|
47
67
|
end
|
48
68
|
|
49
69
|
def format(tag, time, record)
|
50
70
|
out = ''
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
elsif key == @tag_key
|
57
|
-
out << tag
|
58
|
-
else
|
59
|
-
out << record[key].to_s
|
60
|
-
end
|
61
|
-
out << "\t" if i != last
|
71
|
+
if @time_key
|
72
|
+
record[@time_key] = @time_format_proc.call(time)
|
73
|
+
end
|
74
|
+
if @tag_key
|
75
|
+
record[@tag_key] = tag
|
62
76
|
end
|
63
|
-
out
|
77
|
+
@formatter.call(record, out)
|
64
78
|
out
|
65
79
|
end
|
66
80
|
|
@@ -15,28 +15,24 @@
|
|
15
15
|
# See the License for the specific language governing permissions and
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
|
+
|
19
|
+
require 'fluent/plugin/exec_util'
|
20
|
+
|
18
21
|
module Fluent
|
19
22
|
class ExecFilterOutput < BufferedOutput
|
20
23
|
Plugin.register_output('exec_filter', self)
|
21
24
|
|
22
25
|
def initialize
|
23
26
|
super
|
24
|
-
require 'fluent/plugin/exec_util'
|
25
27
|
end
|
26
28
|
|
27
|
-
SUPPORTED_FORMAT = {
|
28
|
-
'tsv' => :tsv,
|
29
|
-
'json' => :json,
|
30
|
-
'msgpack' => :msgpack,
|
31
|
-
}
|
32
|
-
|
33
29
|
config_param :command, :string
|
34
30
|
|
35
31
|
config_param :remove_prefix, :string, :default => nil
|
36
32
|
config_param :add_prefix, :string, :default => nil
|
37
33
|
|
38
34
|
config_param :in_format, :default => :tsv do |val|
|
39
|
-
f = SUPPORTED_FORMAT[val]
|
35
|
+
f = ExecUtil::SUPPORTED_FORMAT[val]
|
40
36
|
raise ConfigError, "Unsupported in_format '#{val}'" unless f
|
41
37
|
f
|
42
38
|
end
|
@@ -48,7 +44,7 @@ module Fluent
|
|
48
44
|
config_param :in_time_format, :default => nil
|
49
45
|
|
50
46
|
config_param :out_format, :default => :tsv do |val|
|
51
|
-
f = SUPPORTED_FORMAT[val]
|
47
|
+
f = ExecUtil::SUPPORTED_FORMAT[val]
|
52
48
|
raise ConfigError, "Unsupported out_format '#{val}'" unless f
|
53
49
|
f
|
54
50
|
end
|
@@ -140,11 +136,11 @@ module Fluent
|
|
140
136
|
if @in_keys.empty?
|
141
137
|
raise ConfigError, "in_keys option is required on exec_filter output for tsv in_format"
|
142
138
|
end
|
143
|
-
@formatter = TSVFormatter.new(@in_keys)
|
139
|
+
@formatter = ExecUtil::TSVFormatter.new(@in_keys)
|
144
140
|
when :json
|
145
|
-
@formatter = JSONFormatter.new
|
141
|
+
@formatter = ExecUtil::JSONFormatter.new
|
146
142
|
when :msgpack
|
147
|
-
@formatter = MessagePackFormatter.new
|
143
|
+
@formatter = ExecUtil::MessagePackFormatter.new
|
148
144
|
end
|
149
145
|
|
150
146
|
case @out_format
|
@@ -333,38 +329,6 @@ module Fluent
|
|
333
329
|
end
|
334
330
|
end
|
335
331
|
|
336
|
-
class Formatter
|
337
|
-
end
|
338
|
-
|
339
|
-
class TSVFormatter < Formatter
|
340
|
-
def initialize(in_keys)
|
341
|
-
@in_keys = in_keys
|
342
|
-
super()
|
343
|
-
end
|
344
|
-
|
345
|
-
def call(record, out)
|
346
|
-
last = @in_keys.length-1
|
347
|
-
for i in 0..last
|
348
|
-
key = @in_keys[i]
|
349
|
-
out << record[key].to_s
|
350
|
-
out << "\t" if i != last
|
351
|
-
end
|
352
|
-
out << "\n"
|
353
|
-
end
|
354
|
-
end
|
355
|
-
|
356
|
-
class JSONFormatter < Formatter
|
357
|
-
def call(record, out)
|
358
|
-
out << Yajl.dump(record) << "\n"
|
359
|
-
end
|
360
|
-
end
|
361
|
-
|
362
|
-
class MessagePackFormatter < Formatter
|
363
|
-
def call(record, out)
|
364
|
-
record.to_msgpack(out)
|
365
|
-
end
|
366
|
-
end
|
367
|
-
|
368
332
|
def on_message(record)
|
369
333
|
if val = record.delete(@out_time_key)
|
370
334
|
time = @time_parse_proc.call(val)
|
data/lib/fluent/version.rb
CHANGED
data/test/parser.rb
CHANGED
@@ -282,4 +282,85 @@ module ParserTest
|
|
282
282
|
end
|
283
283
|
end
|
284
284
|
|
285
|
+
class MultilineParserTest < ::Test::Unit::TestCase
|
286
|
+
include ParserTest
|
287
|
+
|
288
|
+
def create_parser(conf)
|
289
|
+
parser = TextParser::TEMPLATE_FACTORIES['multiline'].call
|
290
|
+
parser.configure(conf)
|
291
|
+
parser
|
292
|
+
end
|
293
|
+
|
294
|
+
def test_configure_with_invalid_params
|
295
|
+
[{'format100' => '/(?<msg>.*)/'}, {'format1' => '/(?<msg>.*)/', 'format3' => '/(?<msg>.*)/'}, 'format1' => '/(?<msg>.*)'].each { |config|
|
296
|
+
assert_raise(ConfigError) {
|
297
|
+
create_parser(config)
|
298
|
+
}
|
299
|
+
}
|
300
|
+
end
|
301
|
+
|
302
|
+
def test_call
|
303
|
+
parser = create_parser('format1' => '/^(?<time>\d{4}-\d{1,2}-\d{1,2} \d{1,2}:\d{1,2}:\d{1,2}) \[(?<thread>.*)\] (?<level>[^\s]+)(?<message>.*)/')
|
304
|
+
time, record = parser.call(<<EOS.chomp)
|
305
|
+
2013-3-03 14:27:33 [main] ERROR Main - Exception
|
306
|
+
javax.management.RuntimeErrorException: null
|
307
|
+
\tat Main.main(Main.java:16) ~[bin/:na]
|
308
|
+
EOS
|
309
|
+
|
310
|
+
assert_equal(str2time('2013-3-03 14:27:33').to_i, time)
|
311
|
+
assert_equal({
|
312
|
+
"thread" => "main",
|
313
|
+
"level" => "ERROR",
|
314
|
+
"message" => " Main - Exception\njavax.management.RuntimeErrorException: null\n\tat Main.main(Main.java:16) ~[bin/:na]"
|
315
|
+
}, record)
|
316
|
+
end
|
317
|
+
|
318
|
+
def test_call_with_firstline
|
319
|
+
parser = create_parser('format_firstline' => '/----/', 'format1' => '/time=(?<time>\d{4}-\d{1,2}-\d{1,2} \d{1,2}:\d{1,2}:\d{1,2}).*message=(?<message>.*)/')
|
320
|
+
time, record = parser.call(<<EOS.chomp)
|
321
|
+
----
|
322
|
+
time=2013-3-03 14:27:33
|
323
|
+
message=test1
|
324
|
+
EOS
|
325
|
+
|
326
|
+
assert(parser.firstline?('----'))
|
327
|
+
assert_equal(str2time('2013-3-03 14:27:33').to_i, time)
|
328
|
+
assert_equal({"message" => "test1"}, record)
|
329
|
+
end
|
330
|
+
|
331
|
+
def test_call_with_multiple_formats
|
332
|
+
parser = create_parser('format_firstline' => '/^Started/',
|
333
|
+
'format1' => '/Started (?<method>[^ ]+) "(?<path>[^"]+)" for (?<host>[^ ]+) at (?<time>[^ ]+ [^ ]+ [^ ]+)\n/',
|
334
|
+
'format2' => '/Processing by (?<controller>[^\u0023]+)\u0023(?<controller_method>[^ ]+) as (?<format>[^ ]+?)\n/',
|
335
|
+
'format3' => '/( Parameters: (?<parameters>[^ ]+)\n)?/',
|
336
|
+
'format4' => '/ Rendered (?<template>[^ ]+) within (?<layout>.+) \([\d\.]+ms\)\n/',
|
337
|
+
'format5' => '/Completed (?<code>[^ ]+) [^ ]+ in (?<runtime>[\d\.]+)ms \(Views: (?<view_runtime>[\d\.]+)ms \| ActiveRecord: (?<ar_runtime>[\d\.]+)ms\)/'
|
338
|
+
)
|
339
|
+
time, record = parser.call(<<EOS.chomp)
|
340
|
+
Started GET "/users/123/" for 127.0.0.1 at 2013-06-14 12:00:11 +0900
|
341
|
+
Processing by UsersController#show as HTML
|
342
|
+
Parameters: {"user_id"=>"123"}
|
343
|
+
Rendered users/show.html.erb within layouts/application (0.3ms)
|
344
|
+
Completed 200 OK in 4ms (Views: 3.2ms | ActiveRecord: 0.0ms)
|
345
|
+
EOS
|
346
|
+
|
347
|
+
assert(parser.firstline?('Started GET "/users/123/" for 127.0.0.1...'))
|
348
|
+
assert_equal(str2time('2013-06-14 12:00:11 +0900').to_i, time)
|
349
|
+
assert_equal({
|
350
|
+
"method" => "GET",
|
351
|
+
"path" => "/users/123/",
|
352
|
+
"host" => "127.0.0.1",
|
353
|
+
"controller" => "UsersController",
|
354
|
+
"controller_method" => "show",
|
355
|
+
"format" => "HTML",
|
356
|
+
"parameters" => "{\"user_id\"=>\"123\"}",
|
357
|
+
"template" => "users/show.html.erb",
|
358
|
+
"layout" => "layouts/application",
|
359
|
+
"code" => "200",
|
360
|
+
"runtime" => "4",
|
361
|
+
"view_runtime" => "3.2",
|
362
|
+
"ar_runtime" => "0.0"
|
363
|
+
}, record)
|
364
|
+
end
|
365
|
+
end
|
285
366
|
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/test/plugin/in_tail.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
require 'fluent/test'
|
2
2
|
require 'net/http'
|
3
|
+
require 'flexmock'
|
3
4
|
|
4
5
|
class TailInputTest < Test::Unit::TestCase
|
6
|
+
include FlexMock::TestCase
|
7
|
+
|
5
8
|
def setup
|
6
9
|
Fluent::Test.setup
|
7
10
|
FileUtils.rm_rf(TMP_DIR)
|
@@ -10,16 +13,19 @@ class TailInputTest < Test::Unit::TestCase
|
|
10
13
|
|
11
14
|
TMP_DIR = File.dirname(__FILE__) + "/../tmp/tail#{ENV['TEST_ENV_NUMBER']}"
|
12
15
|
|
13
|
-
|
16
|
+
COMMON_CONFIG = %[
|
14
17
|
path #{TMP_DIR}/tail.txt
|
15
18
|
tag t1
|
16
19
|
rotate_wait 2s
|
17
20
|
pos_file #{TMP_DIR}/tail.pos
|
21
|
+
]
|
22
|
+
SINGLE_LINE_CONFIG = %[
|
18
23
|
format /(?<message>.*)/
|
19
24
|
]
|
20
25
|
|
21
|
-
def create_driver(conf=
|
22
|
-
|
26
|
+
def create_driver(conf = SINGLE_LINE_CONFIG, use_common_conf = true)
|
27
|
+
config = use_common_conf ? COMMON_CONFIG + conf : conf
|
28
|
+
Fluent::Test::InputTestDriver.new(Fluent::NewTailInput).configure(config)
|
23
29
|
end
|
24
30
|
|
25
31
|
def test_configure
|
@@ -104,4 +110,231 @@ class TailInputTest < Test::Unit::TestCase
|
|
104
110
|
assert_equal({"message"=>" tab"}, emits[4][2])
|
105
111
|
assert_equal({"message"=>"tab "}, emits[5][2])
|
106
112
|
end
|
113
|
+
|
114
|
+
# multiline mode test
|
115
|
+
|
116
|
+
def test_multiline
|
117
|
+
File.open("#{TMP_DIR}/tail.txt", "w") { |f| }
|
118
|
+
|
119
|
+
d = create_driver %[
|
120
|
+
format multiline
|
121
|
+
format1 /^s (?<message1>[^\\n]+)(\\nf (?<message2>[^\\n]+))?(\\nf (?<message3>.*))?/
|
122
|
+
format_firstline /^[s]/
|
123
|
+
]
|
124
|
+
d.run do
|
125
|
+
File.open("#{TMP_DIR}/tail.txt", "a") { |f|
|
126
|
+
f.puts "f test1"
|
127
|
+
f.puts "s test2"
|
128
|
+
f.puts "f test3"
|
129
|
+
f.puts "f test4"
|
130
|
+
f.puts "s test5"
|
131
|
+
f.puts "s test6"
|
132
|
+
f.puts "f test7"
|
133
|
+
f.puts "s test8"
|
134
|
+
}
|
135
|
+
sleep 1
|
136
|
+
end
|
137
|
+
|
138
|
+
emits = d.emits
|
139
|
+
assert(emits.length > 0)
|
140
|
+
assert_equal({"message1" => "test2", "message2" => "test3", "message3" => "test4"}, emits[0][2])
|
141
|
+
assert_equal({"message1" => "test5"}, emits[1][2])
|
142
|
+
assert_equal({"message1" => "test6", "message2" => "test7"}, emits[2][2])
|
143
|
+
assert_equal({"message1" => "test8"}, emits[3][2])
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_multiline_with_multiple_formats
|
147
|
+
File.open("#{TMP_DIR}/tail.txt", "w") { |f| }
|
148
|
+
|
149
|
+
d = create_driver %[
|
150
|
+
format multiline
|
151
|
+
format1 /^s (?<message1>[^\\n]+)\\n?/
|
152
|
+
format2 /(f (?<message2>[^\\n]+)\\n?)?/
|
153
|
+
format3 /(f (?<message3>.*))?/
|
154
|
+
format_firstline /^[s]/
|
155
|
+
]
|
156
|
+
d.run do
|
157
|
+
File.open("#{TMP_DIR}/tail.txt", "a") { |f|
|
158
|
+
f.puts "f test1"
|
159
|
+
f.puts "s test2"
|
160
|
+
f.puts "f test3"
|
161
|
+
f.puts "f test4"
|
162
|
+
f.puts "s test5"
|
163
|
+
f.puts "s test6"
|
164
|
+
f.puts "f test7"
|
165
|
+
f.puts "s test8"
|
166
|
+
}
|
167
|
+
sleep 1
|
168
|
+
end
|
169
|
+
|
170
|
+
emits = d.emits
|
171
|
+
assert(emits.length > 0)
|
172
|
+
assert_equal({"message1" => "test2", "message2" => "test3", "message3" => "test4"}, emits[0][2])
|
173
|
+
assert_equal({"message1" => "test5"}, emits[1][2])
|
174
|
+
assert_equal({"message1" => "test6", "message2" => "test7"}, emits[2][2])
|
175
|
+
assert_equal({"message1" => "test8"}, emits[3][2])
|
176
|
+
end
|
177
|
+
|
178
|
+
def test_multilinelog_with_multiple_paths
|
179
|
+
files = ["#{TMP_DIR}/tail1.txt", "#{TMP_DIR}/tail2.txt"]
|
180
|
+
files.each { |file| File.open(file, "w") { |f| } }
|
181
|
+
|
182
|
+
d = create_driver(%[
|
183
|
+
path #{files[0]},#{files[1]}
|
184
|
+
tag t1
|
185
|
+
format multiline
|
186
|
+
format1 /^[s|f] (?<message>.*)/
|
187
|
+
format_firstline /^[s]/
|
188
|
+
], false)
|
189
|
+
d.run do
|
190
|
+
files.each do |file|
|
191
|
+
File.open(file, 'a') { |f|
|
192
|
+
f.puts "f #{file} line should be ignored"
|
193
|
+
f.puts "s test1"
|
194
|
+
f.puts "f test2"
|
195
|
+
f.puts "f test3"
|
196
|
+
f.puts "s test4"
|
197
|
+
}
|
198
|
+
end
|
199
|
+
sleep 1
|
200
|
+
end
|
201
|
+
|
202
|
+
emits = d.emits
|
203
|
+
assert_equal({"message" => "test1\nf test2\nf test3"}, emits[0][2])
|
204
|
+
assert_equal({"message" => "test1\nf test2\nf test3"}, emits[1][2])
|
205
|
+
# "test4" events are here because these events are flushed at shutdown phase
|
206
|
+
assert_equal({"message" => "test4"}, emits[2][2])
|
207
|
+
assert_equal({"message" => "test4"}, emits[3][2])
|
208
|
+
end
|
209
|
+
|
210
|
+
# * path test
|
211
|
+
# TODO: Clean up tests
|
212
|
+
EX_RORATE_WAIT = 0
|
213
|
+
|
214
|
+
EX_CONFIG = %[
|
215
|
+
tag tail
|
216
|
+
path test/plugin/*/%Y/%m/%Y%m%d-%H%M%S.log,test/plugin/data/log/**/*.log
|
217
|
+
format none
|
218
|
+
pos_file #{TMP_DIR}/tail.pos
|
219
|
+
read_from_head true
|
220
|
+
refresh_interval 30
|
221
|
+
rotate_wait #{EX_RORATE_WAIT}s
|
222
|
+
]
|
223
|
+
EX_PATHS = [
|
224
|
+
'test/plugin/data/2010/01/20100102-030405.log',
|
225
|
+
'test/plugin/data/log/foo/bar.log',
|
226
|
+
'test/plugin/data/log/test.log'
|
227
|
+
]
|
228
|
+
|
229
|
+
def test_expand_paths
|
230
|
+
plugin = create_driver(EX_CONFIG, false).instance
|
231
|
+
flexstub(Time) do |timeclass|
|
232
|
+
timeclass.should_receive(:now).with_no_args.and_return(Time.new(2010, 1, 2, 3, 4, 5))
|
233
|
+
assert_equal EX_PATHS, plugin.expand_paths.sort
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def test_refresh_watchers
|
238
|
+
plugin = create_driver(EX_CONFIG, false).instance
|
239
|
+
sio = StringIO.new
|
240
|
+
plugin.instance_eval do
|
241
|
+
@pf = Fluent::NewTailInput::PositionFile.parse(sio)
|
242
|
+
@loop = Coolio::Loop.new
|
243
|
+
end
|
244
|
+
|
245
|
+
flexstub(Time) do |timeclass|
|
246
|
+
timeclass.should_receive(:now).with_no_args.and_return(Time.new(2010, 1, 2, 3, 4, 5), Time.new(2010, 1, 2, 3, 4, 6), Time.new(2010, 1, 2, 3, 4, 7))
|
247
|
+
|
248
|
+
flexstub(Fluent::NewTailInput::TailWatcher) do |watcherclass|
|
249
|
+
EX_PATHS.each do |path|
|
250
|
+
watcherclass.should_receive(:new).with(path, EX_RORATE_WAIT, Fluent::NewTailInput::FilePositionEntry, any, any, any).once.and_return do
|
251
|
+
flexmock('TailWatcher') { |watcher|
|
252
|
+
watcher.should_receive(:attach).once
|
253
|
+
watcher.should_receive(:unwatched=).zero_or_more_times
|
254
|
+
watcher.should_receive(:line_buffer).zero_or_more_times
|
255
|
+
}
|
256
|
+
end
|
257
|
+
end
|
258
|
+
plugin.refresh_watchers
|
259
|
+
end
|
260
|
+
|
261
|
+
plugin.instance_eval do
|
262
|
+
@tails['test/plugin/data/2010/01/20100102-030405.log'].should_receive(:close).zero_or_more_times
|
263
|
+
end
|
264
|
+
|
265
|
+
flexstub(Fluent::NewTailInput::TailWatcher) do |watcherclass|
|
266
|
+
watcherclass.should_receive(:new).with('test/plugin/data/2010/01/20100102-030406.log', EX_RORATE_WAIT, Fluent::NewTailInput::FilePositionEntry, any, any, any).once.and_return do
|
267
|
+
flexmock('TailWatcher') do |watcher|
|
268
|
+
watcher.should_receive(:attach).once
|
269
|
+
watcher.should_receive(:unwatched=).zero_or_more_times
|
270
|
+
watcher.should_receive(:line_buffer).zero_or_more_times
|
271
|
+
end
|
272
|
+
end
|
273
|
+
plugin.refresh_watchers
|
274
|
+
end
|
275
|
+
|
276
|
+
flexstub(Fluent::NewTailInput::TailWatcher) do |watcherclass|
|
277
|
+
watcherclass.should_receive(:new).never
|
278
|
+
plugin.refresh_watchers
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
DummyWatcher = Struct.new("DummyWatcher", :tag)
|
284
|
+
|
285
|
+
def test_receive_lines
|
286
|
+
plugin = create_driver(EX_CONFIG, false).instance
|
287
|
+
flexstub(Fluent::Engine) do |engineclass|
|
288
|
+
engineclass.should_receive(:emit_stream).with('tail', any).once
|
289
|
+
plugin.receive_lines(['foo', 'bar'], DummyWatcher.new('foo.bar.log'))
|
290
|
+
end
|
291
|
+
|
292
|
+
config = %[
|
293
|
+
tag pre.*
|
294
|
+
path test/plugin/*/%Y/%m/%Y%m%d-%H%M%S.log,test/plugin/data/log/**/*.log
|
295
|
+
format none
|
296
|
+
read_from_head true
|
297
|
+
]
|
298
|
+
plugin = create_driver(config, false).instance
|
299
|
+
flexstub(Fluent::Engine) do |engineclass|
|
300
|
+
engineclass.should_receive(:emit_stream).with('pre.foo.bar.log', any).once
|
301
|
+
plugin.receive_lines(['foo', 'bar'], DummyWatcher.new('foo.bar.log'))
|
302
|
+
end
|
303
|
+
|
304
|
+
config = %[
|
305
|
+
tag *.post
|
306
|
+
path test/plugin/*/%Y/%m/%Y%m%d-%H%M%S.log,test/plugin/data/log/**/*.log
|
307
|
+
format none
|
308
|
+
read_from_head true
|
309
|
+
]
|
310
|
+
plugin = create_driver(config, false).instance
|
311
|
+
flexstub(Fluent::Engine) do |engineclass|
|
312
|
+
engineclass.should_receive(:emit_stream).with('foo.bar.log.post', any).once
|
313
|
+
plugin.receive_lines(['foo', 'bar'], DummyWatcher.new('foo.bar.log'))
|
314
|
+
end
|
315
|
+
|
316
|
+
config = %[
|
317
|
+
tag pre.*.post
|
318
|
+
path test/plugin/*/%Y/%m/%Y%m%d-%H%M%S.log,test/plugin/data/log/**/*.log
|
319
|
+
format none
|
320
|
+
read_from_head true
|
321
|
+
]
|
322
|
+
plugin = create_driver(config, false).instance
|
323
|
+
flexstub(Fluent::Engine) do |engineclass|
|
324
|
+
engineclass.should_receive(:emit_stream).with('pre.foo.bar.log.post', any).once
|
325
|
+
plugin.receive_lines(['foo', 'bar'], DummyWatcher.new('foo.bar.log'))
|
326
|
+
end
|
327
|
+
|
328
|
+
config = %[
|
329
|
+
tag pre.*.post*ignore
|
330
|
+
path test/plugin/*/%Y/%m/%Y%m%d-%H%M%S.log,test/plugin/data/log/**/*.log
|
331
|
+
format none
|
332
|
+
read_from_head true
|
333
|
+
]
|
334
|
+
plugin = create_driver(config, false).instance
|
335
|
+
flexstub(Fluent::Engine) do |engineclass|
|
336
|
+
engineclass.should_receive(:emit_stream).with('pre.foo.bar.log.post', any).once
|
337
|
+
plugin.receive_lines(['foo', 'bar'], DummyWatcher.new('foo.bar.log'))
|
338
|
+
end
|
339
|
+
end
|
107
340
|
end
|