fluent-plugin-tail-ex-rotate 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a77ea0c7caa116f06886673d73d83d9b822b1b5b
4
+ data.tar.gz: 12e56f4a6dd248b086b35b73db277f1400b6a8a7
5
+ SHA512:
6
+ metadata.gz: 6209fbe36cde82650e465dc817a5fafa81614163f2d35ee7912e5329fbad818a1eac96b29a8cc769ccc6f68f5fdb66e78b438cdedbff707ceea0b71a10006f16
7
+ data.tar.gz: dda0d444b1744ff0fc49185526e2d39ed880bd37b1250d7094a36f22afdb39981eee4e9b5cea9c24bf360fd795eb7f62e955db391018010c067a1468c04d207f
data/COPYING ADDED
@@ -0,0 +1,14 @@
1
+ Copyright (C) 2015 DWANGO Co., Ltd.
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
14
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org/'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,40 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ fluent-plugin-tail-ex-rotate (0.0.1)
5
+ fluentd
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ cool.io (1.2.4)
11
+ fluentd (0.12.2)
12
+ cool.io (>= 1.2.2, < 2.0.0)
13
+ http_parser.rb (>= 0.5.1, < 0.7.0)
14
+ json (>= 1.4.3)
15
+ msgpack (>= 0.5.4, < 0.6.0)
16
+ sigdump (~> 0.2.2)
17
+ string-scrub (>= 0.0.3)
18
+ tzinfo (>= 1.0.0)
19
+ tzinfo-data (>= 1.0.0)
20
+ yajl-ruby (~> 1.0)
21
+ http_parser.rb (0.6.0)
22
+ json (1.8.1)
23
+ msgpack (0.5.9)
24
+ rake (10.4.2)
25
+ sigdump (0.2.2)
26
+ string-scrub (0.0.5)
27
+ thread_safe (0.3.4)
28
+ tzinfo (1.2.2)
29
+ thread_safe (~> 0.1)
30
+ tzinfo-data (1.2014.10)
31
+ tzinfo (>= 1.0.0)
32
+ yajl-ruby (1.2.1)
33
+
34
+ PLATFORMS
35
+ ruby
36
+
37
+ DEPENDENCIES
38
+ bundler (~> 1.3)
39
+ fluent-plugin-tail-ex-rotate!
40
+ rake (>= 0.9.2)
data/NOTICE ADDED
@@ -0,0 +1,5 @@
1
+ This product contains a part of fluentd source code:
2
+ * LICENSE:
3
+ * https://github.com/fluent/fluentd/blob/master/COPYING
4
+ * HOMEPAGE:
5
+ * https://github.com/fluent/fluentd
data/README.md ADDED
@@ -0,0 +1,30 @@
1
+ # fluent-plugin-tail-ex-rotate
2
+ ===================================
3
+
4
+ fluent-plugin-tail-ex-rotate is a fluentd plugin to extend file lotation time.
5
+
6
+ ## Install
7
+
8
+ ```sh
9
+ gem install fluent-plugin-tail-ex-rotate
10
+ ```
11
+
12
+ ## Setting
13
+
14
+ The setting of fluent-plugin-tail-ex-rotate is roughly the same with in_tail built-in plugin.
15
+ A defference between fluent-plugin-tail-ex-rotate and in_tail built-in plugin setting is "expand_rotate_time" parameter
16
+
17
+ "expand_rotate_time" parameter should be set number of second.
18
+
19
+ For example,
20
+ ```xml
21
+ <source>
22
+ type tail_ex_rotate
23
+ path /var/log/apache2/access_log
24
+ tag internal.eapi_nicolive_process_time
25
+ pos_file /var/log/td-agent/httpd-access.log.pos
26
+ time_format %d/%b/%Y:%H:%M:%S %z
27
+ expand_rotate_time 18000
28
+ types process_time:integer
29
+ </source>
30
+ ```
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'fileutils'
5
+ require 'rake/testtask'
6
+ require 'rake/clean'
7
+
8
+ task :test => [:base_test]
9
+
10
+ desc 'Run test_unit based test'
11
+ Rake::TestTask.new(:base_test) do |t|
12
+ # To run test for only one file (or file path pattern)
13
+ # $ bundle exec rake base_test TEST=test/test_specified_path.rb
14
+ # $ bundle exec rake base_test TEST=test/test_*.rb
15
+ t.libs << "test"
16
+ t.test_files = Dir["test/**/test_*.rb"].sort
17
+ t.verbose = true
18
+ #t.warning = true
19
+ end
20
+
21
+ task :parallel_test do
22
+ FileUtils.rm_rf('./test/tmp')
23
+ sh("parallel_test ./test/*.rb ./test/plugin/*.rb")
24
+ FileUtils.rm_rf('./test/tmp')
25
+ end
26
+
27
+ desc 'Run test with simplecov'
28
+ task :coverage do |t|
29
+ ENV['SIMPLE_COV'] = '1'
30
+ Rake::Task["test"].invoke
31
+ end
32
+
33
+ task :default => [:test, :build]
@@ -0,0 +1,25 @@
1
+ require File.expand_path('../lib/fluent/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "fluent-plugin-tail-ex-rotate"
5
+ gem.version = "0.0.1"
6
+
7
+ gem.authors = ["Yuta Mizushima"]
8
+ gem.email = ["yuta_mizushima@dwango.co.jp"]
9
+ gem.description = %q{Extension of in_tail plugin to customize log rotate timing.}
10
+ gem.summary = %q{customize log rotate timing}
11
+ gem.homepage = "http://github.o-in.dwango.co.jp/Yuta-Mizushima/namasasy_setup/tree/master/node/fluent-plugin-tail-ex-rotate"
12
+
13
+ gem.files = `git ls-files`.split($\)
14
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
15
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
+ gem.require_paths = ["lib"]
17
+ gem.has_rdoc = false
18
+
19
+ gem.required_ruby_version = '>= 1.9.3'
20
+
21
+ gem.add_runtime_dependency("fluentd")
22
+
23
+ gem.add_development_dependency("bundler", "~> 1.3")
24
+ gem.add_development_dependency("rake", [">= 0.9.2"])
25
+ end
@@ -0,0 +1,23 @@
1
+ require 'fluent/plugin/in_tail'
2
+
3
+ module Fluent
4
+ class TailExRotateInput < Fluent::NewTailInput
5
+ Fluent::Plugin.register_input('tail_ex_rotate', self)
6
+ config_param :expand_rotate_time, :time, :default => 0
7
+
8
+ def expand_paths
9
+ date = Time.now - @expand_rotate_time
10
+ paths = []
11
+ @paths.each { |path|
12
+ path = date.strftime(path)
13
+ if path.include?('*')
14
+ paths += Dir.glob(path)
15
+ else
16
+ # When file is not created yet, Dir.glob returns an empty array. So just add when path is static.
17
+ paths << path
18
+ end
19
+ }
20
+ paths
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
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
+ module Fluent
18
+
19
+ VERSION = '0.12.2'
20
+
21
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,56 @@
1
+ # simplecov must be loaded before any of target code
2
+ if ENV['SIMPLE_COV']
3
+ require 'simplecov'
4
+ if defined?(SimpleCov::SourceFile)
5
+ mod = SimpleCov::SourceFile
6
+ def mod.new(*args, &block)
7
+ m = allocate
8
+ m.instance_eval do
9
+ begin
10
+ initialize(*args, &block)
11
+ rescue Encoding::UndefinedConversionError
12
+ @src = "".force_encoding('UTF-8')
13
+ end
14
+ end
15
+ m
16
+ end
17
+ end
18
+ unless SimpleCov.running
19
+ SimpleCov.start do
20
+ add_filter '/test/'
21
+ add_filter '/gems/'
22
+ end
23
+ end
24
+ end
25
+
26
+ require 'rr'
27
+ require 'test/unit'
28
+ require 'test/unit/rr'
29
+ require 'fileutils'
30
+ require 'fluent/log'
31
+ require 'fluent/test'
32
+
33
+ unless defined?(Test::Unit::AssertionFailedError)
34
+ class Test::Unit::AssertionFailedError < StandardError
35
+ end
36
+ end
37
+
38
+ def unused_port
39
+ s = TCPServer.open(0)
40
+ port = s.addr[1]
41
+ s.close
42
+ port
43
+ end
44
+
45
+ def ipv6_enabled?
46
+ require 'socket'
47
+
48
+ begin
49
+ TCPServer.open("::1", 0)
50
+ true
51
+ rescue
52
+ false
53
+ end
54
+ end
55
+
56
+ $log = Fluent::Log.new(Fluent::Test::DummyLogDevice.new, Fluent::Log::LEVEL_WARN)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,560 @@
1
+ require_relative '../helper'
2
+ require 'fluent/test'
3
+ require 'net/http'
4
+ require 'flexmock'
5
+ require 'fluent/plugin/in_tail_ex_rotate'
6
+
7
+ class TailExRotateInputTest < Test::Unit::TestCase
8
+ include FlexMock::TestCase
9
+
10
+ def setup
11
+ Fluent::Test.setup
12
+ FileUtils.rm_rf(TMP_DIR)
13
+ FileUtils.mkdir_p(TMP_DIR)
14
+ end
15
+
16
+ TMP_DIR = File.dirname(__FILE__) + "/../tmp/tail#{ENV['TEST_ENV_NUMBER']}"
17
+
18
+ CONFIG = %[
19
+ path #{TMP_DIR}/tail.txt
20
+ tag t1
21
+ rotate_wait 2s
22
+ expand_rotate_time 18000s
23
+ ]
24
+ COMMON_CONFIG = CONFIG + %[
25
+ pos_file #{TMP_DIR}/tail.pos
26
+ ]
27
+ CONFIG_READ_FROM_HEAD = %[
28
+ read_from_head true
29
+ ]
30
+ SINGLE_LINE_CONFIG = %[
31
+ format /(?<message>.*)/
32
+ ]
33
+
34
+ def create_driver(conf = SINGLE_LINE_CONFIG, use_common_conf = true)
35
+ config = use_common_conf ? COMMON_CONFIG + conf : conf
36
+ Fluent::Test::InputTestDriver.new(Fluent::TailExRotateInput).configure(config)
37
+ end
38
+
39
+ def test_configure
40
+ d = create_driver
41
+ assert_equal ["#{TMP_DIR}/tail.txt"], d.instance.paths
42
+ assert_equal "t1", d.instance.tag
43
+ assert_equal 2, d.instance.rotate_wait
44
+ assert_equal "#{TMP_DIR}/tail.pos", d.instance.pos_file
45
+ assert_equal 18000, d.instance.expand_rotate_time
46
+ end
47
+
48
+ # TODO: Should using more better approach instead of sleep wait
49
+
50
+ def test_emit
51
+ File.open("#{TMP_DIR}/tail.txt", "w") {|f|
52
+ f.puts "test1"
53
+ f.puts "test2"
54
+ }
55
+
56
+ d = create_driver
57
+
58
+ d.run do
59
+ sleep 1
60
+
61
+ File.open("#{TMP_DIR}/tail.txt", "a") {|f|
62
+ f.puts "test3"
63
+ f.puts "test4"
64
+ }
65
+ sleep 1
66
+ end
67
+
68
+ emits = d.emits
69
+ assert_equal(true, emits.length > 0)
70
+ assert_equal({"message" => "test3"}, emits[0][2])
71
+ assert_equal({"message" => "test4"}, emits[1][2])
72
+ end
73
+
74
+ def test_emit_with_read_from_head
75
+ File.open("#{TMP_DIR}/tail.txt", "w") {|f|
76
+ f.puts "test1"
77
+ f.puts "test2"
78
+ }
79
+
80
+ d = create_driver(CONFIG_READ_FROM_HEAD + SINGLE_LINE_CONFIG)
81
+
82
+ d.run do
83
+ sleep 1
84
+
85
+ File.open("#{TMP_DIR}/tail.txt", "a") {|f|
86
+ f.puts "test3"
87
+ f.puts "test4"
88
+ }
89
+ sleep 1
90
+ end
91
+
92
+ emits = d.emits
93
+ assert(emits.length > 0)
94
+ assert_equal({"message" => "test1"}, emits[0][2])
95
+ assert_equal({"message" => "test2"}, emits[1][2])
96
+ assert_equal({"message" => "test3"}, emits[2][2])
97
+ assert_equal({"message" => "test4"}, emits[3][2])
98
+ end
99
+
100
+ def test_rotate_file
101
+ emits = sub_test_rotate_file(SINGLE_LINE_CONFIG)
102
+ assert_equal(4, emits.length)
103
+ assert_equal({"message" => "test3"}, emits[0][2])
104
+ assert_equal({"message" => "test4"}, emits[1][2])
105
+ assert_equal({"message" => "test5"}, emits[2][2])
106
+ assert_equal({"message" => "test6"}, emits[3][2])
107
+ end
108
+
109
+ def test_rotate_file_with_read_from_head
110
+ emits = sub_test_rotate_file(CONFIG_READ_FROM_HEAD + SINGLE_LINE_CONFIG)
111
+ assert_equal(6, emits.length)
112
+ assert_equal({"message" => "test1"}, emits[0][2])
113
+ assert_equal({"message" => "test2"}, emits[1][2])
114
+ assert_equal({"message" => "test3"}, emits[2][2])
115
+ assert_equal({"message" => "test4"}, emits[3][2])
116
+ assert_equal({"message" => "test5"}, emits[4][2])
117
+ assert_equal({"message" => "test6"}, emits[5][2])
118
+ end
119
+
120
+ def test_rotate_file_with_write_old
121
+ emits = sub_test_rotate_file(SINGLE_LINE_CONFIG) { |rotated_file|
122
+ File.open("#{TMP_DIR}/tail.txt", "w") { |f| }
123
+ rotated_file.puts "test7"
124
+ rotated_file.puts "test8"
125
+ rotated_file.flush
126
+
127
+ sleep 1
128
+ File.open("#{TMP_DIR}/tail.txt", "a") { |f|
129
+ f.puts "test5"
130
+ f.puts "test6"
131
+ }
132
+ }
133
+ assert_equal(6, emits.length)
134
+ assert_equal({"message" => "test3"}, emits[0][2])
135
+ assert_equal({"message" => "test4"}, emits[1][2])
136
+ assert_equal({"message" => "test7"}, emits[2][2])
137
+ assert_equal({"message" => "test8"}, emits[3][2])
138
+ assert_equal({"message" => "test5"}, emits[4][2])
139
+ assert_equal({"message" => "test6"}, emits[5][2])
140
+ end
141
+
142
+ def test_rotate_file_with_write_old_and_no_new_file
143
+ emits = sub_test_rotate_file(SINGLE_LINE_CONFIG) { |rotated_file|
144
+ rotated_file.puts "test7"
145
+ rotated_file.puts "test8"
146
+ rotated_file.flush
147
+ }
148
+ assert_equal(4, emits.length)
149
+ assert_equal({"message" => "test3"}, emits[0][2])
150
+ assert_equal({"message" => "test4"}, emits[1][2])
151
+ assert_equal({"message" => "test7"}, emits[2][2])
152
+ assert_equal({"message" => "test8"}, emits[3][2])
153
+ end
154
+
155
+ def sub_test_rotate_file(config = nil)
156
+ file = File.open("#{TMP_DIR}/tail.txt", "w")
157
+ file.puts "test1"
158
+ file.puts "test2"
159
+ file.flush
160
+
161
+ d = create_driver(config)
162
+ d.run do
163
+ sleep 1
164
+
165
+ file.puts "test3"
166
+ file.puts "test4"
167
+ file.flush
168
+ sleep 1
169
+
170
+ FileUtils.mv("#{TMP_DIR}/tail.txt", "#{TMP_DIR}/tail2.txt")
171
+ if block_given?
172
+ yield file
173
+ sleep 1
174
+ else
175
+ sleep 1
176
+ File.open("#{TMP_DIR}/tail.txt", "w") { |f| }
177
+ sleep 1
178
+
179
+ File.open("#{TMP_DIR}/tail.txt", "a") { |f|
180
+ f.puts "test5"
181
+ f.puts "test6"
182
+ }
183
+ sleep 1
184
+ end
185
+ end
186
+
187
+ d.run do
188
+ sleep 1
189
+ end
190
+
191
+ d.emits
192
+ ensure
193
+ file.close
194
+ end
195
+
196
+ def test_lf
197
+ File.open("#{TMP_DIR}/tail.txt", "w") {|f| }
198
+
199
+ d = create_driver
200
+
201
+ d.run do
202
+ File.open("#{TMP_DIR}/tail.txt", "a") {|f|
203
+ f.print "test3"
204
+ }
205
+ sleep 1
206
+
207
+ File.open("#{TMP_DIR}/tail.txt", "a") {|f|
208
+ f.puts "test4"
209
+ }
210
+ sleep 1
211
+ end
212
+
213
+ emits = d.emits
214
+ assert_equal(true, emits.length > 0)
215
+ assert_equal({"message" => "test3test4"}, emits[0][2])
216
+ end
217
+
218
+ def test_whitespace
219
+ File.open("#{TMP_DIR}/tail.txt", "w") {|f| }
220
+
221
+ d = create_driver
222
+
223
+ d.run do
224
+ sleep 1
225
+
226
+ File.open("#{TMP_DIR}/tail.txt", "a") {|f|
227
+ f.puts " " # 4 spaces
228
+ f.puts " 4 spaces"
229
+ f.puts "4 spaces "
230
+ f.puts " " # tab
231
+ f.puts " tab"
232
+ f.puts "tab "
233
+ }
234
+ sleep 1
235
+ end
236
+
237
+ emits = d.emits
238
+ assert_equal(true, emits.length > 0)
239
+ assert_equal({"message" => " "}, emits[0][2])
240
+ assert_equal({"message" => " 4 spaces"}, emits[1][2])
241
+ assert_equal({"message" => "4 spaces "}, emits[2][2])
242
+ assert_equal({"message" => " "}, emits[3][2])
243
+ assert_equal({"message" => " tab"}, emits[4][2])
244
+ assert_equal({"message" => "tab "}, emits[5][2])
245
+ end
246
+
247
+ # multiline mode test
248
+
249
+ def test_multiline
250
+ File.open("#{TMP_DIR}/tail.txt", "w") { |f| }
251
+
252
+ d = create_driver %[
253
+ format multiline
254
+ format1 /^s (?<message1>[^\\n]+)(\\nf (?<message2>[^\\n]+))?(\\nf (?<message3>.*))?/
255
+ format_firstline /^[s]/
256
+ ]
257
+ d.run do
258
+ File.open("#{TMP_DIR}/tail.txt", "a") { |f|
259
+ f.puts "f test1"
260
+ f.puts "s test2"
261
+ f.puts "f test3"
262
+ f.puts "f test4"
263
+ f.puts "s test5"
264
+ f.puts "s test6"
265
+ f.puts "f test7"
266
+ f.puts "s test8"
267
+ }
268
+ sleep 1
269
+ end
270
+
271
+ emits = d.emits
272
+ assert(emits.length > 0)
273
+ assert_equal({"message1" => "test2", "message2" => "test3", "message3" => "test4"}, emits[0][2])
274
+ assert_equal({"message1" => "test5"}, emits[1][2])
275
+ assert_equal({"message1" => "test6", "message2" => "test7"}, emits[2][2])
276
+ assert_equal({"message1" => "test8"}, emits[3][2])
277
+ end
278
+
279
+ def test_multiline_with_multiple_formats
280
+ File.open("#{TMP_DIR}/tail.txt", "w") { |f| }
281
+
282
+ d = create_driver %[
283
+ format multiline
284
+ format1 /^s (?<message1>[^\\n]+)\\n?/
285
+ format2 /(f (?<message2>[^\\n]+)\\n?)?/
286
+ format3 /(f (?<message3>.*))?/
287
+ format_firstline /^[s]/
288
+ ]
289
+ d.run do
290
+ File.open("#{TMP_DIR}/tail.txt", "a") { |f|
291
+ f.puts "f test1"
292
+ f.puts "s test2"
293
+ f.puts "f test3"
294
+ f.puts "f test4"
295
+ f.puts "s test5"
296
+ f.puts "s test6"
297
+ f.puts "f test7"
298
+ f.puts "s test8"
299
+ }
300
+ sleep 1
301
+ end
302
+
303
+ emits = d.emits
304
+ assert(emits.length > 0)
305
+ assert_equal({"message1" => "test2", "message2" => "test3", "message3" => "test4"}, emits[0][2])
306
+ assert_equal({"message1" => "test5"}, emits[1][2])
307
+ assert_equal({"message1" => "test6", "message2" => "test7"}, emits[2][2])
308
+ assert_equal({"message1" => "test8"}, emits[3][2])
309
+ end
310
+
311
+ def test_multilinelog_with_multiple_paths
312
+ files = ["#{TMP_DIR}/tail1.txt", "#{TMP_DIR}/tail2.txt"]
313
+ files.each { |file| File.open(file, "w") { |f| } }
314
+
315
+ d = create_driver(%[
316
+ path #{files[0]},#{files[1]}
317
+ tag t1
318
+ format multiline
319
+ format1 /^[s|f] (?<message>.*)/
320
+ format_firstline /^[s]/
321
+ ], false)
322
+ d.run do
323
+ files.each do |file|
324
+ File.open(file, 'a') { |f|
325
+ f.puts "f #{file} line should be ignored"
326
+ f.puts "s test1"
327
+ f.puts "f test2"
328
+ f.puts "f test3"
329
+ f.puts "s test4"
330
+ }
331
+ end
332
+ sleep 1
333
+ end
334
+
335
+ emits = d.emits
336
+ assert_equal({"message" => "test1\nf test2\nf test3"}, emits[0][2])
337
+ assert_equal({"message" => "test1\nf test2\nf test3"}, emits[1][2])
338
+ # "test4" events are here because these events are flushed at shutdown phase
339
+ assert_equal({"message" => "test4"}, emits[2][2])
340
+ assert_equal({"message" => "test4"}, emits[3][2])
341
+ end
342
+
343
+ def test_multiline_without_firstline
344
+ File.open("#{TMP_DIR}/tail.txt", "w") { |f| }
345
+
346
+ d = create_driver %[
347
+ format multiline
348
+ format1 /(?<var1>foo \\d)\\n/
349
+ format2 /(?<var2>bar \\d)\\n/
350
+ format3 /(?<var3>baz \\d)/
351
+ ]
352
+ d.run do
353
+ File.open("#{TMP_DIR}/tail.txt", "a") { |f|
354
+ f.puts "foo 1"
355
+ f.puts "bar 1"
356
+ f.puts "baz 1"
357
+ f.puts "foo 2"
358
+ f.puts "bar 2"
359
+ f.puts "baz 2"
360
+ }
361
+ sleep 1
362
+ end
363
+
364
+ emits = d.emits
365
+ assert_equal(2, emits.length)
366
+ assert_equal({"var1" => "foo 1", "var2" => "bar 1", "var3" => "baz 1"}, emits[0][2])
367
+ assert_equal({"var1" => "foo 2", "var2" => "bar 2", "var3" => "baz 2"}, emits[1][2])
368
+ end
369
+
370
+ # * path test
371
+ # TODO: Clean up tests
372
+ EX_RORATE_WAIT = 0
373
+
374
+ EX_CONFIG = %[
375
+ tag tail
376
+ path test/plugin/*/%Y/%m/%Y%m%d-%H%M%S.log,test/plugin/data/log/**/*.log
377
+ format none
378
+ pos_file #{TMP_DIR}/tail.pos
379
+ read_from_head true
380
+ refresh_interval 30
381
+ rotate_wait #{EX_RORATE_WAIT}s
382
+ ]
383
+ EX_PATHS = [
384
+ 'test/plugin/data/2010/01/20100102-030405.log',
385
+ 'test/plugin/data/log/foo/bar.log',
386
+ 'test/plugin/data/log/test.log'
387
+ ]
388
+
389
+ EX_CONFIG_FOR_ROTATE = %[
390
+ tag tail
391
+ path test/plugin/*/%Y/%m/%Y%m%d-%H%M%S.log,test/plugin/data/log/**/*.log
392
+ format none
393
+ pos_file #{TMP_DIR}/tail.pos
394
+ read_from_head true
395
+ refresh_interval 30
396
+ rotate_wait #{EX_RORATE_WAIT}s
397
+ expand_rotate_time 18000s
398
+ ]
399
+
400
+ EX_PATHS_FOR_ROATE = [
401
+ 'test/plugin/data/2014/12/20141224-000000.log',
402
+ 'test/plugin/data/log/foo/bar.log',
403
+ 'test/plugin/data/log/test.log'
404
+ ]
405
+
406
+ def test_expand_paths
407
+ plugin = create_driver(EX_CONFIG, false).instance
408
+ flexstub(Time) do |timeclass|
409
+ timeclass.should_receive(:now).with_no_args.and_return(Time.new(2010, 1, 2, 3, 4, 5))
410
+ assert_equal EX_PATHS, plugin.expand_paths.sort
411
+ end
412
+ end
413
+
414
+ def test_expand_paths_for_ex_rotate
415
+ plugin = create_driver(EX_CONFIG_FOR_ROTATE, false).instance
416
+ flexstub(Time) do |timeclass|
417
+ timeclass.should_receive(:now).with_no_args.and_return(Time.new(2014, 12, 24, 5, 0, 0))
418
+ assert_equal EX_PATHS_FOR_ROATE, plugin.expand_paths.sort
419
+ end
420
+ end
421
+
422
+ def test_refresh_watchers
423
+ plugin = create_driver(EX_CONFIG, false).instance
424
+ sio = StringIO.new
425
+ plugin.instance_eval do
426
+ @pf = Fluent::TailExRotateInput::PositionFile.parse(sio)
427
+ @loop = Coolio::Loop.new
428
+ end
429
+
430
+ flexstub(Time) do |timeclass|
431
+ 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))
432
+
433
+ flexstub(Fluent::TailExRotateInput::TailWatcher) do |watcherclass|
434
+ EX_PATHS.each do |path|
435
+ watcherclass.should_receive(:new).with(path, EX_RORATE_WAIT, Fluent::TailExRotateInput::FilePositionEntry, any, true, any, any).once.and_return do
436
+ flexmock('TailWatcher') { |watcher|
437
+ watcher.should_receive(:attach).once
438
+ watcher.should_receive(:unwatched=).zero_or_more_times
439
+ watcher.should_receive(:line_buffer).zero_or_more_times
440
+ }
441
+ end
442
+ end
443
+ plugin.refresh_watchers
444
+ end
445
+
446
+ plugin.instance_eval do
447
+ @tails['test/plugin/data/2010/01/20100102-030405.log'].should_receive(:close).zero_or_more_times
448
+ end
449
+
450
+ flexstub(Fluent::TailExRotateInput::TailWatcher) do |watcherclass|
451
+ watcherclass.should_receive(:new).with('test/plugin/data/2010/01/20100102-030406.log', EX_RORATE_WAIT, Fluent::TailExRotateInput::FilePositionEntry, any, true, any, any).once.and_return do
452
+ flexmock('TailWatcher') do |watcher|
453
+ watcher.should_receive(:attach).once
454
+ watcher.should_receive(:unwatched=).zero_or_more_times
455
+ watcher.should_receive(:line_buffer).zero_or_more_times
456
+ end
457
+ end
458
+ plugin.refresh_watchers
459
+ end
460
+
461
+ flexstub(Fluent::TailExRotateInput::TailWatcher) do |watcherclass|
462
+ watcherclass.should_receive(:new).never
463
+ plugin.refresh_watchers
464
+ end
465
+ end
466
+ end
467
+
468
+ DummyWatcher = Struct.new("DummyWatcher", :tag)
469
+
470
+ def test_receive_lines
471
+ plugin = create_driver(EX_CONFIG, false).instance
472
+ flexstub(plugin.router) do |engineclass|
473
+ engineclass.should_receive(:emit_stream).with('tail', any).once
474
+ plugin.receive_lines(['foo', 'bar'], DummyWatcher.new('foo.bar.log'))
475
+ end
476
+
477
+ config = %[
478
+ tag pre.*
479
+ path test/plugin/*/%Y/%m/%Y%m%d-%H%M%S.log,test/plugin/data/log/**/*.log
480
+ format none
481
+ read_from_head true
482
+ ]
483
+ plugin = create_driver(config, false).instance
484
+ flexstub(plugin.router) do |engineclass|
485
+ engineclass.should_receive(:emit_stream).with('pre.foo.bar.log', any).once
486
+ plugin.receive_lines(['foo', 'bar'], DummyWatcher.new('foo.bar.log'))
487
+ end
488
+
489
+ config = %[
490
+ tag *.post
491
+ path test/plugin/*/%Y/%m/%Y%m%d-%H%M%S.log,test/plugin/data/log/**/*.log
492
+ format none
493
+ read_from_head true
494
+ ]
495
+ plugin = create_driver(config, false).instance
496
+ flexstub(plugin.router) do |engineclass|
497
+ engineclass.should_receive(:emit_stream).with('foo.bar.log.post', any).once
498
+ plugin.receive_lines(['foo', 'bar'], DummyWatcher.new('foo.bar.log'))
499
+ end
500
+
501
+ config = %[
502
+ tag pre.*.post
503
+ path test/plugin/*/%Y/%m/%Y%m%d-%H%M%S.log,test/plugin/data/log/**/*.log
504
+ format none
505
+ read_from_head true
506
+ ]
507
+ plugin = create_driver(config, false).instance
508
+ flexstub(plugin.router) do |engineclass|
509
+ engineclass.should_receive(:emit_stream).with('pre.foo.bar.log.post', any).once
510
+ plugin.receive_lines(['foo', 'bar'], DummyWatcher.new('foo.bar.log'))
511
+ end
512
+
513
+ config = %[
514
+ tag pre.*.post*ignore
515
+ path test/plugin/*/%Y/%m/%Y%m%d-%H%M%S.log,test/plugin/data/log/**/*.log
516
+ format none
517
+ read_from_head true
518
+ ]
519
+ plugin = create_driver(config, false).instance
520
+ flexstub(plugin.router) do |engineclass|
521
+ engineclass.should_receive(:emit_stream).with('pre.foo.bar.log.post', any).once
522
+ plugin.receive_lines(['foo', 'bar'], DummyWatcher.new('foo.bar.log'))
523
+ end
524
+ end
525
+
526
+ # Ensure that no fatal exception is raised when a file is missing and that
527
+ # files that do exist are still tailed as expected.
528
+ def test_missing_file
529
+ File.open("#{TMP_DIR}/tail.txt", "w") {|f|
530
+ f.puts "test1"
531
+ f.puts "test2"
532
+ }
533
+
534
+ # Try two different configs - one with read_from_head and one without,
535
+ # since their interactions with the filesystem differ.
536
+ config1 = %[
537
+ tag t1
538
+ path #{TMP_DIR}/non_existent_file.txt,#{TMP_DIR}/tail.txt
539
+ format none
540
+ rotate_wait 2s
541
+ pos_file #{TMP_DIR}/tail.pos
542
+ ]
543
+ config2 = config1 + ' read_from_head true'
544
+ [config1, config2].each do |config|
545
+ d = create_driver(config, false)
546
+ d.run do
547
+ sleep 1
548
+ File.open("#{TMP_DIR}/tail.txt", "a") {|f|
549
+ f.puts "test3"
550
+ f.puts "test4"
551
+ }
552
+ sleep 1
553
+ end
554
+ emits = d.emits
555
+ assert_equal(2, emits.length)
556
+ assert_equal({"message" => "test3"}, emits[0][2])
557
+ assert_equal({"message" => "test4"}, emits[1][2])
558
+ end
559
+ end
560
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-tail-ex-rotate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Yuta Mizushima
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fluentd
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 0.9.2
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 0.9.2
55
+ description: Extension of in_tail plugin to customize log rotate timing.
56
+ email:
57
+ - yuta_mizushima@dwango.co.jp
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - COPYING
63
+ - Gemfile
64
+ - Gemfile.lock
65
+ - NOTICE
66
+ - README.md
67
+ - Rakefile
68
+ - fluent-plugin-tail-ex-rotate.gemspec
69
+ - lib/fluent/plugin/in_tail_ex_rotate.rb
70
+ - lib/fluent/version.rb
71
+ - pkg/fluent-plugin-tail-ex-rotate-0.0.1.gem
72
+ - test/helper.rb
73
+ - test/plugin/data/2010/01/20100102-030405.log
74
+ - test/plugin/data/2010/01/20100102-030406.log
75
+ - test/plugin/data/2014/12/20141224-000000.log
76
+ - test/plugin/data/log/bar
77
+ - test/plugin/data/log/foo/bar.log
78
+ - test/plugin/data/log/test.log
79
+ - test/plugin/test_in_tail_ex_rotate.rb
80
+ homepage: http://github.o-in.dwango.co.jp/Yuta-Mizushima/namasasy_setup/tree/master/node/fluent-plugin-tail-ex-rotate
81
+ licenses: []
82
+ metadata: {}
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: 1.9.3
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 2.2.2
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: customize log rotate timing
103
+ test_files:
104
+ - test/helper.rb
105
+ - test/plugin/data/2010/01/20100102-030405.log
106
+ - test/plugin/data/2010/01/20100102-030406.log
107
+ - test/plugin/data/2014/12/20141224-000000.log
108
+ - test/plugin/data/log/bar
109
+ - test/plugin/data/log/foo/bar.log
110
+ - test/plugin/data/log/test.log
111
+ - test/plugin/test_in_tail_ex_rotate.rb
112
+ has_rdoc: false