fluentd 0.10.38 → 0.10.39
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 +4 -0
- data/ChangeLog +10 -0
- data/Rakefile +7 -0
- data/fluentd.gemspec +1 -0
- data/lib/fluent/buffer.rb +8 -4
- data/lib/fluent/command/fluentd.rb +4 -0
- data/lib/fluent/config_dsl.rb +46 -33
- data/lib/fluent/engine.rb +10 -2
- data/lib/fluent/event.rb +17 -0
- data/lib/fluent/output.rb +12 -0
- data/lib/fluent/parser.rb +71 -12
- data/lib/fluent/plugin/buf_file.rb +5 -2
- data/lib/fluent/plugin/in_tail.rb +7 -5
- data/lib/fluent/plugin/out_copy.rb +9 -1
- data/lib/fluent/plugin/out_file.rb +2 -7
- data/lib/fluent/supervisor.rb +14 -1
- data/lib/fluent/version.rb +1 -1
- data/test/config.rb +1 -1
- data/test/configdsl.rb +32 -2
- data/test/helper.rb +5 -2
- data/test/parser.rb +58 -1
- data/test/plugin/in_forward.rb +5 -4
- data/test/plugin/in_http.rb +6 -4
- data/test/plugin/in_stream.rb +6 -6
- data/test/plugin/in_syslog.rb +6 -5
- data/test/plugin/in_tail.rb +1 -1
- data/test/plugin/out_copy.rb +78 -0
- data/test/plugin/out_exec.rb +1 -1
- data/test/plugin/out_file.rb +24 -12
- data/test/plugin/out_stream.rb +5 -4
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 14f93577d21ab248d08466b142442d503ba9ad55
|
4
|
+
data.tar.gz: 9036d89bf55c57a454120dc766c3da6fe445fbf8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5c4ae2365e4e3a59cc22e7089203ea57b3cf7bc89d759915e4f02b795312903116484dd65f43a7e07ed9e98a1da13f5e1aa6112a0448d03706e4171cd3dad63a
|
7
|
+
data.tar.gz: 806d690bccc9674f2bd45d693eb523a07e06d0aa4e2dc63e42396421d34ce8f27977bba119b0e5470d8844ee62c140cd1cf8c4bff1b8ce2aa16bd8d40e7fb419
|
data/.travis.yml
CHANGED
data/ChangeLog
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
Release 0.10.39 - 2013/09/18
|
2
|
+
|
3
|
+
* out_file: Improve symlink handling with buf_file
|
4
|
+
* out_copy: Add deep_copy parameter for actual record copy
|
5
|
+
* in_tail/parser: Add none format for supporting non-parse tailing like fluent-agent-lite
|
6
|
+
* in_tail/parser: Improve performance using parsed time caching
|
7
|
+
* Engine: Fix signal related exception in trap context at Ruby 2.0
|
8
|
+
* buffer: Fix race condition when remove flushed chunk
|
9
|
+
* add --suppress-config-dump option to disable dump configuration at start
|
10
|
+
|
1
11
|
Release 0.10.38 - 2013/08/29
|
2
12
|
|
3
13
|
* Fix require related problem in running test
|
data/Rakefile
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
2
|
require "bundler/gem_tasks"
|
3
3
|
|
4
|
+
require 'fileutils'
|
4
5
|
require 'rake/testtask'
|
5
6
|
require 'rake/clean'
|
6
7
|
|
@@ -13,4 +14,10 @@ Rake::TestTask.new(:base_test) do |t|
|
|
13
14
|
#t.warning = true
|
14
15
|
end
|
15
16
|
|
17
|
+
task :parallel_test do
|
18
|
+
FileUtils.rm_rf('./test/tmp')
|
19
|
+
sh("parallel_test ./test/*.rb ./test/plugin/*.rb")
|
20
|
+
FileUtils.rm_rf('./test/tmp')
|
21
|
+
end
|
22
|
+
|
16
23
|
task :default => [:test, :build]
|
data/fluentd.gemspec
CHANGED
@@ -25,6 +25,7 @@ Gem::Specification.new do |gem|
|
|
25
25
|
gem.add_runtime_dependency(%q<http_parser.rb>, ["~> 0.5.1"])
|
26
26
|
|
27
27
|
gem.add_development_dependency(%q<rake>, [">= 0.9.2"])
|
28
|
+
gem.add_development_dependency(%q<parallel_tests>, [">= 0.15.3"])
|
28
29
|
gem.add_development_dependency(%q<rr>, [">= 1.0.0"])
|
29
30
|
gem.add_development_dependency(%q<timecop>, [">= 0.3.0"])
|
30
31
|
end
|
data/lib/fluent/buffer.rb
CHANGED
@@ -272,13 +272,17 @@ module Fluent
|
|
272
272
|
write_chunk(chunk, out)
|
273
273
|
end
|
274
274
|
|
275
|
-
|
276
|
-
|
277
|
-
|
275
|
+
empty = false
|
276
|
+
@queue.synchronize do
|
277
|
+
@queue.delete_if {|c|
|
278
|
+
c.object_id == chunk.object_id
|
279
|
+
}
|
280
|
+
empty = @queue.empty?
|
281
|
+
end
|
278
282
|
|
279
283
|
chunk.purge
|
280
284
|
|
281
|
-
return
|
285
|
+
return !empty
|
282
286
|
ensure
|
283
287
|
chunk.mon_exit
|
284
288
|
end
|
@@ -98,6 +98,10 @@ op.on('-q', '--quiet', "decrease verbose level (-q: warn, -qq: error)", TrueClas
|
|
98
98
|
end
|
99
99
|
}
|
100
100
|
|
101
|
+
op.on('--suppress-config-dump', "suppress config dumping when fluentd starts", TrueClass) {|b|
|
102
|
+
opts[:suppress_config_dump] = b
|
103
|
+
}
|
104
|
+
|
101
105
|
(class<<self;self;end).module_eval do
|
102
106
|
define_method(:usage) do |msg|
|
103
107
|
puts op.to_s
|
data/lib/fluent/config_dsl.rb
CHANGED
@@ -3,7 +3,7 @@ require 'fluent/config'
|
|
3
3
|
module Fluent
|
4
4
|
module Config
|
5
5
|
module DSL
|
6
|
-
module
|
6
|
+
module Parser
|
7
7
|
def self.read(path)
|
8
8
|
path = File.expand_path(path)
|
9
9
|
data = File.read(path)
|
@@ -11,62 +11,75 @@ module Fluent
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def self.parse(source, source_path="config.rb")
|
14
|
-
|
14
|
+
Proxy.new('ROOT', nil).eval(source, source_path).to_config_element
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
class
|
18
|
+
class Proxy
|
19
19
|
def initialize(name, arg)
|
20
|
-
@
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
@element = Element.new(name, arg, self)
|
21
|
+
end
|
22
|
+
|
23
|
+
def element
|
24
|
+
@element
|
24
25
|
end
|
25
26
|
|
26
|
-
def
|
27
|
-
instance_eval(source, source_path)
|
27
|
+
def eval(source, source_path)
|
28
|
+
@element.instance_eval(source, source_path)
|
28
29
|
self
|
29
30
|
end
|
30
31
|
|
31
|
-
def
|
32
|
-
|
32
|
+
def to_config_element
|
33
|
+
@element.instance_eval do
|
34
|
+
Config::Element.new(@name, @arg, @attrs, @elements)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_element(name, arg, block)
|
39
|
+
::Kernel.raise ::ArgumentError, "#{name} block must be specified" if block.nil?
|
40
|
+
|
41
|
+
proxy = self.class.new(name.to_s, arg)
|
42
|
+
proxy.element.instance_exec(&block)
|
43
|
+
|
44
|
+
@element.instance_eval do
|
45
|
+
@elements.push(proxy.to_config_element)
|
46
|
+
end
|
47
|
+
|
48
|
+
self
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class Element < BasicObject
|
53
|
+
def initialize(name, arg, proxy)
|
54
|
+
@name = name
|
55
|
+
@arg = arg || ''
|
56
|
+
@attrs = {}
|
57
|
+
@elements = []
|
58
|
+
@proxy = proxy
|
33
59
|
end
|
34
60
|
|
35
61
|
def method_missing(name, *args, &block)
|
36
|
-
raise ArgumentError, "Configuration DSL Syntax Error: only one argument allowed" if args.size > 1
|
62
|
+
::Kernel.raise ::ArgumentError, "Configuration DSL Syntax Error: only one argument allowed" if args.size > 1
|
37
63
|
value = args.first
|
64
|
+
|
38
65
|
if block
|
39
|
-
|
40
|
-
element.instance_exec(&block)
|
41
|
-
@elements.push(
|
66
|
+
proxy = Proxy.new(name.to_s, value)
|
67
|
+
proxy.element.instance_exec(&block)
|
68
|
+
@elements.push(proxy.to_config_element)
|
42
69
|
else
|
43
|
-
# @attrs[name.to_s] = value.is_a?(::Symbol) ? value.to_s : value
|
44
70
|
@attrs[name.to_s] = value.to_s
|
45
71
|
end
|
72
|
+
|
46
73
|
self
|
47
74
|
end
|
48
75
|
|
49
76
|
def source(&block)
|
50
|
-
|
77
|
+
@proxy.add_element('source', nil, block)
|
51
78
|
end
|
52
79
|
|
53
80
|
def match(*args, &block)
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
|
-
def __element(name, arg, block)
|
60
|
-
raise ArgumentError, "#{name} block must be specified" if block.nil?
|
61
|
-
element = DSLElement.new(name.to_s, arg)
|
62
|
-
element.instance_exec(&block)
|
63
|
-
@elements.push(element.__to_config_element)
|
64
|
-
self
|
65
|
-
end
|
66
|
-
|
67
|
-
def __need_arg(name, args)
|
68
|
-
raise ArgumentError, "#{name} block requires arguments for match pattern" if args.nil? || args.size != 1
|
69
|
-
true
|
81
|
+
::Kernel.raise ::ArgumentError, "#{name} block requires arguments for match pattern" if args.nil? || args.size != 1
|
82
|
+
@proxy.add_element('match', args.first, block)
|
70
83
|
end
|
71
84
|
end
|
72
85
|
end
|
data/lib/fluent/engine.rb
CHANGED
@@ -31,6 +31,8 @@ module Fluent
|
|
31
31
|
|
32
32
|
@suppress_emit_error_log_interval = 0
|
33
33
|
@next_emit_error_log_time = nil
|
34
|
+
|
35
|
+
@suppress_config_dump = false
|
34
36
|
end
|
35
37
|
|
36
38
|
MATCH_CACHE_SIZE = 1024
|
@@ -54,6 +56,10 @@ module Fluent
|
|
54
56
|
@next_emit_error_log_time = Time.now.to_i
|
55
57
|
end
|
56
58
|
|
59
|
+
def suppress_config_dump=(flag)
|
60
|
+
@suppress_config_dump = flag
|
61
|
+
end
|
62
|
+
|
57
63
|
def read_config(path)
|
58
64
|
$log.info "reading config file", :path=>path
|
59
65
|
File.open(path) {|io|
|
@@ -63,7 +69,7 @@ module Fluent
|
|
63
69
|
|
64
70
|
def parse_config(io, fname, basepath=Dir.pwd)
|
65
71
|
conf = if fname =~ /\.rb$/
|
66
|
-
Config::DSL::
|
72
|
+
Config::DSL::Parser.parse(io, File.join(basepath, fname))
|
67
73
|
else
|
68
74
|
Config.parse(io, fname, basepath)
|
69
75
|
end
|
@@ -74,7 +80,9 @@ module Fluent
|
|
74
80
|
end
|
75
81
|
|
76
82
|
def configure(conf)
|
77
|
-
|
83
|
+
unless @suppress_config_dump
|
84
|
+
$log.info "using configuration file: #{conf.to_s.rstrip}"
|
85
|
+
end
|
78
86
|
|
79
87
|
conf.elements.select {|e|
|
80
88
|
e.name == 'source'
|
data/lib/fluent/event.rb
CHANGED
@@ -42,6 +42,10 @@ module Fluent
|
|
42
42
|
@record = record
|
43
43
|
end
|
44
44
|
|
45
|
+
def dup
|
46
|
+
OneEventStream.new(@time, @record.dup)
|
47
|
+
end
|
48
|
+
|
45
49
|
def repeatable?
|
46
50
|
true
|
47
51
|
end
|
@@ -58,6 +62,11 @@ module Fluent
|
|
58
62
|
@entries = entries
|
59
63
|
end
|
60
64
|
|
65
|
+
def dup
|
66
|
+
entries = @entries.map(:dup)
|
67
|
+
ArrayEventStream.new(entries)
|
68
|
+
end
|
69
|
+
|
61
70
|
def repeatable?
|
62
71
|
true
|
63
72
|
end
|
@@ -85,6 +94,14 @@ module Fluent
|
|
85
94
|
@record_array = []
|
86
95
|
end
|
87
96
|
|
97
|
+
def dup
|
98
|
+
es = MultiEventStream.new
|
99
|
+
@time_array.zip(@record_array).each { |time, record|
|
100
|
+
es.add(time, record.dup)
|
101
|
+
}
|
102
|
+
es
|
103
|
+
end
|
104
|
+
|
88
105
|
def add(time, record)
|
89
106
|
@time_array << time
|
90
107
|
@record_array << record
|
data/lib/fluent/output.rb
CHANGED
@@ -35,6 +35,18 @@ module Fluent
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
+
class CopyOutputChain < OutputChain
|
39
|
+
def next
|
40
|
+
if @array.length <= @offset
|
41
|
+
return @chain.next
|
42
|
+
end
|
43
|
+
@offset += 1
|
44
|
+
es = @array.length > @offset ? @es.dup : @es
|
45
|
+
result = @array[@offset-1].emit(@tag, es, self)
|
46
|
+
result
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
38
50
|
class NullOutputChain
|
39
51
|
require 'singleton'
|
40
52
|
include Singleton
|
data/lib/fluent/parser.rb
CHANGED
@@ -17,6 +17,40 @@
|
|
17
17
|
#
|
18
18
|
module Fluent
|
19
19
|
class TextParser
|
20
|
+
class TimeParser
|
21
|
+
def initialize(time_format)
|
22
|
+
@cache1_key = nil
|
23
|
+
@cache1_time = nil
|
24
|
+
@cache2_key = nil
|
25
|
+
@cache2_time = nil
|
26
|
+
@parser =
|
27
|
+
if time_format
|
28
|
+
Proc.new { |value| Time.strptime(value, time_format) }
|
29
|
+
else
|
30
|
+
Time.method(:parse)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def parse(value)
|
35
|
+
unless value.is_a?(String)
|
36
|
+
raise ArgumentError, "Value must be string: #{value}"
|
37
|
+
end
|
38
|
+
|
39
|
+
if @cache1_key == value
|
40
|
+
return @cache1_time
|
41
|
+
elsif @cache2_key == value
|
42
|
+
return @cache2_time
|
43
|
+
else
|
44
|
+
time = @parser.call(value).to_i
|
45
|
+
@cache1_key = @cache2_key
|
46
|
+
@cache1_time = @cache2_time
|
47
|
+
@cache2_key = value
|
48
|
+
@cache2_time = time
|
49
|
+
return time
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
20
54
|
class RegexpParser
|
21
55
|
include Configurable
|
22
56
|
|
@@ -28,6 +62,9 @@ module Fluent
|
|
28
62
|
unless conf.empty?
|
29
63
|
configure(conf)
|
30
64
|
end
|
65
|
+
|
66
|
+
@time_parser = TimeParser.new(@time_format)
|
67
|
+
@mutex = Mutex.new
|
31
68
|
end
|
32
69
|
|
33
70
|
def call(text)
|
@@ -44,11 +81,7 @@ module Fluent
|
|
44
81
|
if value = m[name]
|
45
82
|
case name
|
46
83
|
when "time"
|
47
|
-
|
48
|
-
time = Time.strptime(value, @time_format).to_i
|
49
|
-
else
|
50
|
-
time = Time.parse(value).to_i
|
51
|
-
end
|
84
|
+
time = @mutex.synchronize { @time_parser.parse(value) }
|
52
85
|
else
|
53
86
|
record[name] = value
|
54
87
|
end
|
@@ -67,12 +100,21 @@ module Fluent
|
|
67
100
|
config_param :time_key, :string, :default => 'time'
|
68
101
|
config_param :time_format, :string, :default => nil
|
69
102
|
|
103
|
+
def configure(conf)
|
104
|
+
super
|
105
|
+
|
106
|
+
unless @time_format.nil?
|
107
|
+
@time_parser = TimeParser.new(@time_format)
|
108
|
+
@mutex = Mutex.new
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
70
112
|
def call(text)
|
71
113
|
record = Yajl.load(text)
|
72
114
|
|
73
115
|
if value = record.delete(@time_key)
|
74
116
|
if @time_format
|
75
|
-
time =
|
117
|
+
time = @mutex.synchronize { @time_parser.parse(value) }
|
76
118
|
else
|
77
119
|
time = value.to_i
|
78
120
|
end
|
@@ -106,6 +148,9 @@ module Fluent
|
|
106
148
|
if @time_format && !@time_key
|
107
149
|
raise ConfigError, "time_format parameter is ignored because time_key parameter is not set. at #{conf.inspect}"
|
108
150
|
end
|
151
|
+
|
152
|
+
@time_parser = TimeParser.new(@time_format)
|
153
|
+
@mutex = Mutex.new
|
109
154
|
end
|
110
155
|
|
111
156
|
def values_map(values)
|
@@ -113,11 +158,7 @@ module Fluent
|
|
113
158
|
|
114
159
|
if @time_key
|
115
160
|
value = record.delete(@time_key)
|
116
|
-
|
117
|
-
time = Time.strptime(value, @time_format).to_i
|
118
|
-
else
|
119
|
-
time = Time.parse(value).to_i
|
120
|
-
end
|
161
|
+
time = @mutex.synchronize { @time_parser.parse(value) }
|
121
162
|
else
|
122
163
|
time = Engine.now
|
123
164
|
end
|
@@ -169,11 +210,28 @@ module Fluent
|
|
169
210
|
end
|
170
211
|
end
|
171
212
|
|
213
|
+
class NoneParser
|
214
|
+
include Configurable
|
215
|
+
|
216
|
+
config_param :message_key, :string, :default => 'message'
|
217
|
+
|
218
|
+
def call(text)
|
219
|
+
record = {}
|
220
|
+
record[@message_key] = text
|
221
|
+
return Engine.now, record
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
172
225
|
class ApacheParser
|
173
226
|
include Configurable
|
174
227
|
|
175
228
|
REGEXP = /^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$/
|
176
229
|
|
230
|
+
def initialize
|
231
|
+
@time_parser = TimeParser.new("%d/%b/%Y:%H:%M:%S %z")
|
232
|
+
@mutex = Mutex.new
|
233
|
+
end
|
234
|
+
|
177
235
|
def call(text)
|
178
236
|
m = REGEXP.match(text)
|
179
237
|
unless m
|
@@ -188,7 +246,7 @@ module Fluent
|
|
188
246
|
user = (user == '-') ? nil : user
|
189
247
|
|
190
248
|
time = m['time']
|
191
|
-
time =
|
249
|
+
time = @mutex.synchronize { @time_parser.parse(time) }
|
192
250
|
|
193
251
|
method = m['method']
|
194
252
|
path = m['path']
|
@@ -229,6 +287,7 @@ module Fluent
|
|
229
287
|
'ltsv' => Proc.new { LabeledTSVParser.new },
|
230
288
|
'csv' => Proc.new { CSVParser.new },
|
231
289
|
'nginx' => Proc.new { RegexpParser.new(/^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$/, {'time_format'=>"%d/%b/%Y:%H:%M:%S %z"}) },
|
290
|
+
'none' => Proc.new { NoneParser.new },
|
232
291
|
}
|
233
292
|
|
234
293
|
def self.register_template(name, regexp_or_proc, time_format=nil)
|
@@ -17,13 +17,14 @@
|
|
17
17
|
#
|
18
18
|
module Fluent
|
19
19
|
class FileBufferChunk < BufferChunk
|
20
|
-
def initialize(key, path, unique_id, mode="a+")
|
20
|
+
def initialize(key, path, unique_id, mode="a+", symlink_path = nil)
|
21
21
|
super(key)
|
22
22
|
@path = path
|
23
23
|
@unique_id = unique_id
|
24
24
|
@file = File.open(@path, mode, DEFAULT_FILE_PERMISSION)
|
25
25
|
@file.sync = true
|
26
26
|
@size = @file.stat.size
|
27
|
+
FileUtils.ln_sf(@path, symlink_path) if symlink_path
|
27
28
|
end
|
28
29
|
|
29
30
|
attr_reader :unique_id
|
@@ -84,6 +85,8 @@ module Fluent
|
|
84
85
|
|
85
86
|
config_param :buffer_path, :string
|
86
87
|
|
88
|
+
attr_accessor :symlink_path
|
89
|
+
|
87
90
|
def configure(conf)
|
88
91
|
super
|
89
92
|
|
@@ -119,7 +122,7 @@ module Fluent
|
|
119
122
|
encoded_key = encode_key(key)
|
120
123
|
path, tsuffix = make_path(encoded_key, "b")
|
121
124
|
unique_id = tsuffix_to_unique_id(tsuffix)
|
122
|
-
FileBufferChunk.new(key, path, unique_id)
|
125
|
+
FileBufferChunk.new(key, path, unique_id, "a+", @symlink_path)
|
123
126
|
end
|
124
127
|
|
125
128
|
def resume
|
@@ -39,11 +39,7 @@ module Fluent
|
|
39
39
|
raise ConfigError, "tail: 'path' parameter is required on tail input"
|
40
40
|
end
|
41
41
|
|
42
|
-
|
43
|
-
@pf_file = File.open(@pos_file, File::RDWR|File::CREAT, DEFAULT_FILE_PERMISSION)
|
44
|
-
@pf_file.sync = true
|
45
|
-
@pf = PositionFile.parse(@pf_file)
|
46
|
-
else
|
42
|
+
unless @pos_file
|
47
43
|
$log.warn "'pos_file PATH' parameter is not set to a 'tail' source."
|
48
44
|
$log.warn "this parameter is highly recommended to save the position to resume tailing."
|
49
45
|
end
|
@@ -57,6 +53,12 @@ module Fluent
|
|
57
53
|
end
|
58
54
|
|
59
55
|
def start
|
56
|
+
if @pos_file
|
57
|
+
@pf_file = File.open(@pos_file, File::RDWR|File::CREAT, DEFAULT_FILE_PERMISSION)
|
58
|
+
@pf_file.sync = true
|
59
|
+
@pf = PositionFile.parse(@pf_file)
|
60
|
+
end
|
61
|
+
|
60
62
|
@loop = Coolio::Loop.new
|
61
63
|
@tails = @paths.map {|path|
|
62
64
|
pe = @pf ? @pf[path] : MemoryPositionEntry.new
|
@@ -19,13 +19,17 @@ module Fluent
|
|
19
19
|
class CopyOutput < MultiOutput
|
20
20
|
Plugin.register_output('copy', self)
|
21
21
|
|
22
|
+
config_param :deep_copy, :bool, :default => false
|
23
|
+
|
22
24
|
def initialize
|
25
|
+
super
|
23
26
|
@outputs = []
|
24
27
|
end
|
25
28
|
|
26
29
|
attr_reader :outputs
|
27
30
|
|
28
31
|
def configure(conf)
|
32
|
+
super
|
29
33
|
conf.elements.select {|e|
|
30
34
|
e.name == 'store'
|
31
35
|
}.each {|e|
|
@@ -61,7 +65,11 @@ module Fluent
|
|
61
65
|
}
|
62
66
|
es = m
|
63
67
|
end
|
64
|
-
|
68
|
+
if @deep_copy
|
69
|
+
chain = CopyOutputChain.new(@outputs, tag, es, chain)
|
70
|
+
else
|
71
|
+
chain = OutputChain.new(@outputs, tag, es, chain)
|
72
|
+
end
|
65
73
|
chain.next
|
66
74
|
end
|
67
75
|
end
|
@@ -65,6 +65,8 @@ module Fluent
|
|
65
65
|
super
|
66
66
|
|
67
67
|
@timef = TimeFormatter.new(@time_format, @localtime)
|
68
|
+
|
69
|
+
@buffer.symlink_path = @symlink_path if @symlink_path
|
68
70
|
end
|
69
71
|
|
70
72
|
def format(tag, time, record)
|
@@ -97,7 +99,6 @@ module Fluent
|
|
97
99
|
chunk.write_to(f)
|
98
100
|
}
|
99
101
|
end
|
100
|
-
create_symlink(path, suffix) if @symlink_path
|
101
102
|
|
102
103
|
return path # for test
|
103
104
|
end
|
@@ -105,11 +106,5 @@ module Fluent
|
|
105
106
|
def secondary_init(primary)
|
106
107
|
# don't warn even if primary.class is not FileOutput
|
107
108
|
end
|
108
|
-
|
109
|
-
private
|
110
|
-
|
111
|
-
def create_symlink(path, suffix)
|
112
|
-
FileUtils.ln_sf(path, "#{@symlink_path}#{suffix}")
|
113
|
-
end
|
114
109
|
end
|
115
110
|
end
|
data/lib/fluent/supervisor.rb
CHANGED
@@ -67,6 +67,7 @@ module Fluent
|
|
67
67
|
@inline_config = opt[:inline_config]
|
68
68
|
@suppress_interval = opt[:suppress_interval]
|
69
69
|
@dry_run = opt[:dry_run]
|
70
|
+
@suppress_config_dump = opt[:suppress_config_dump]
|
70
71
|
|
71
72
|
@log = LoggerInitializer.new(@log_path, @log_level, @chuser, @chgroup)
|
72
73
|
@finished = false
|
@@ -320,6 +321,8 @@ module Fluent
|
|
320
321
|
Fluent::Engine.suppress_interval(@suppress_interval)
|
321
322
|
end
|
322
323
|
|
324
|
+
Fluent::Engine.suppress_config_dump = @suppress_config_dump
|
325
|
+
|
323
326
|
@libs.each {|lib|
|
324
327
|
require lib
|
325
328
|
}
|
@@ -363,7 +366,17 @@ module Fluent
|
|
363
366
|
$log.debug "fluentd main process get SIGUSR1"
|
364
367
|
$log.info "force flushing buffered events"
|
365
368
|
@log.reopen!
|
366
|
-
|
369
|
+
|
370
|
+
# Creating new thread due to mutex can't lock
|
371
|
+
# in main thread during trap context
|
372
|
+
Thread.new {
|
373
|
+
begin
|
374
|
+
Fluent::Engine.flush!
|
375
|
+
$log.debug "flushing thread: flushed"
|
376
|
+
rescue Exception => e
|
377
|
+
$log.warn "flushing thread error: #{e}"
|
378
|
+
end
|
379
|
+
}.run
|
367
380
|
end
|
368
381
|
end
|
369
382
|
|
data/lib/fluent/version.rb
CHANGED
data/test/config.rb
CHANGED
@@ -7,7 +7,7 @@ require 'fileutils'
|
|
7
7
|
class ConfigTest < Test::Unit::TestCase
|
8
8
|
include Fluent
|
9
9
|
|
10
|
-
TMP_DIR = File.dirname(__FILE__) + "/tmp"
|
10
|
+
TMP_DIR = File.dirname(__FILE__) + "/tmp/config#{ENV['TEST_ENV_NUMBER']}"
|
11
11
|
|
12
12
|
def prepare_config
|
13
13
|
write_config "#{TMP_DIR}/config_test_1.conf", %[
|
data/test/configdsl.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'fluent/config_dsl'
|
2
|
+
require 'fluent/test'
|
3
|
+
require 'helper'
|
2
4
|
|
3
5
|
class ConfigDSLTest < Test::Unit::TestCase
|
4
6
|
# TEST_CONFIG1 = %[
|
@@ -38,10 +40,24 @@ match('test.**') {
|
|
38
40
|
|
39
41
|
TEST_DSL_CONFIG2 = %q[
|
40
42
|
v = [0, 1, 2]
|
43
|
+
]
|
44
|
+
|
45
|
+
TEST_DSL_CONFIG3 = %q[
|
46
|
+
match
|
47
|
+
]
|
48
|
+
|
49
|
+
TEST_DSL_CONFIG4 = %q[
|
50
|
+
match('aa', 'bb'){
|
51
|
+
type :null
|
52
|
+
}
|
53
|
+
]
|
54
|
+
|
55
|
+
TEST_DSL_CONFIG5 = %q[
|
56
|
+
match('aa')
|
41
57
|
]
|
42
58
|
|
43
59
|
def test_parse
|
44
|
-
root = Fluent::Config::DSL::
|
60
|
+
root = Fluent::Config::DSL::Parser.parse(TEST_DSL_CONFIG1)
|
45
61
|
|
46
62
|
assert_equal 0, root.keys.size
|
47
63
|
assert_equal 2, root.elements.size
|
@@ -69,9 +85,23 @@ v = [0, 1, 2]
|
|
69
85
|
end
|
70
86
|
|
71
87
|
def test_parse2
|
72
|
-
root = Fluent::Config::DSL::
|
88
|
+
root = Fluent::Config::DSL::Parser.parse(TEST_DSL_CONFIG2)
|
73
89
|
|
74
90
|
assert_equal 0, root.keys.size
|
75
91
|
assert_equal 0, root.elements.size
|
76
92
|
end
|
93
|
+
|
94
|
+
def test_config_error
|
95
|
+
assert_raise(ArgumentError) {
|
96
|
+
Fluent::Config::DSL::Parser.parse(TEST_DSL_CONFIG3)
|
97
|
+
}
|
98
|
+
|
99
|
+
assert_raise(ArgumentError) {
|
100
|
+
Fluent::Config::DSL::Parser.parse(TEST_DSL_CONFIG4)
|
101
|
+
}
|
102
|
+
|
103
|
+
assert_raise(ArgumentError) {
|
104
|
+
Fluent::Config::DSL::Parser.parse(TEST_DSL_CONFIG5)
|
105
|
+
}
|
106
|
+
end
|
77
107
|
end
|
data/test/helper.rb
CHANGED
data/test/parser.rb
CHANGED
@@ -9,7 +9,35 @@ module ParserTest
|
|
9
9
|
if format
|
10
10
|
Time.strptime(str_time, format).to_i
|
11
11
|
else
|
12
|
-
Time.parse(str_time)
|
12
|
+
Time.parse(str_time).to_i
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class TimeParserTest < ::Test::Unit::TestCase
|
17
|
+
include ParserTest
|
18
|
+
|
19
|
+
def test_call_with_parse
|
20
|
+
parser = TextParser::TimeParser.new(nil)
|
21
|
+
|
22
|
+
time = str2time('2013-09-18 12:00:00 +0900')
|
23
|
+
assert_equal(time, parser.parse('2013-09-18 12:00:00 +0900'))
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_call_with_strptime
|
27
|
+
parser = TextParser::TimeParser.new('%d/%b/%Y:%H:%M:%S %z')
|
28
|
+
|
29
|
+
time = str2time('28/Feb/2013:12:00:00 +0900', '%d/%b/%Y:%H:%M:%S %z')
|
30
|
+
assert_equal(time, parser.parse('28/Feb/2013:12:00:00 +0900'))
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_call_with_invalid_argument
|
34
|
+
parser = TextParser::TimeParser.new(nil)
|
35
|
+
|
36
|
+
[[], {}, nil, true, 10000].each { |v|
|
37
|
+
assert_raise ArgumentError do
|
38
|
+
parser.parse(v)
|
39
|
+
end
|
40
|
+
}
|
13
41
|
end
|
14
42
|
end
|
15
43
|
|
@@ -151,6 +179,7 @@ module ParserTest
|
|
151
179
|
|
152
180
|
def test_call
|
153
181
|
parser = TextParser::LabeledTSVParser.new
|
182
|
+
parser.configure({})
|
154
183
|
time, record = parser.call("time:2013/02/28 12:00:00\thost:192.168.0.1\treq_id:111")
|
155
184
|
|
156
185
|
assert_equal(str2time('2013/02/28 12:00:00', '%Y/%m/%d %H:%M:%S'), time)
|
@@ -190,4 +219,32 @@ module ParserTest
|
|
190
219
|
}, record)
|
191
220
|
end
|
192
221
|
end
|
222
|
+
|
223
|
+
class NoneParserTest < ::Test::Unit::TestCase
|
224
|
+
include ParserTest
|
225
|
+
|
226
|
+
def test_config_params
|
227
|
+
parser = TextParser::NoneParser.new
|
228
|
+
assert_equal "message", parser.message_key
|
229
|
+
|
230
|
+
parser.configure('message_key' => 'foobar')
|
231
|
+
assert_equal "foobar", parser.message_key
|
232
|
+
end
|
233
|
+
|
234
|
+
def test_call
|
235
|
+
parser = TextParser::TEMPLATE_FACTORIES['none'].call
|
236
|
+
time, record = parser.call('log message!')
|
237
|
+
|
238
|
+
assert_equal({'message' => 'log message!'}, record)
|
239
|
+
end
|
240
|
+
|
241
|
+
def test_call_with_message_key
|
242
|
+
parser = TextParser::NoneParser.new
|
243
|
+
parser.configure('message_key' => 'foobar')
|
244
|
+
time, record = parser.call('log message!')
|
245
|
+
|
246
|
+
assert_equal({'foobar' => 'log message!'}, record)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
193
250
|
end
|
data/test/plugin/in_forward.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
require 'fluent/test'
|
2
|
+
require 'helper'
|
2
3
|
|
3
4
|
class ForwardInputTest < Test::Unit::TestCase
|
4
5
|
def setup
|
5
6
|
Fluent::Test.setup
|
6
7
|
end
|
7
8
|
|
9
|
+
PORT = unused_port
|
8
10
|
CONFIG = %[
|
9
|
-
port
|
11
|
+
port #{PORT}
|
10
12
|
bind 127.0.0.1
|
11
13
|
]
|
12
14
|
|
@@ -16,12 +18,12 @@ class ForwardInputTest < Test::Unit::TestCase
|
|
16
18
|
|
17
19
|
def test_configure
|
18
20
|
d = create_driver
|
19
|
-
assert_equal
|
21
|
+
assert_equal PORT, d.instance.port
|
20
22
|
assert_equal '127.0.0.1', d.instance.bind
|
21
23
|
end
|
22
24
|
|
23
25
|
def connect
|
24
|
-
TCPSocket.new('127.0.0.1',
|
26
|
+
TCPSocket.new('127.0.0.1', PORT)
|
25
27
|
end
|
26
28
|
|
27
29
|
def test_time
|
@@ -120,4 +122,3 @@ class ForwardInputTest < Test::Unit::TestCase
|
|
120
122
|
|
121
123
|
# TODO heartbeat
|
122
124
|
end
|
123
|
-
|
data/test/plugin/in_http.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'fluent/test'
|
2
|
+
require 'helper'
|
2
3
|
require 'net/http'
|
3
4
|
|
4
5
|
class HttpInputTest < Test::Unit::TestCase
|
@@ -6,8 +7,9 @@ class HttpInputTest < Test::Unit::TestCase
|
|
6
7
|
Fluent::Test.setup
|
7
8
|
end
|
8
9
|
|
10
|
+
PORT = unused_port
|
9
11
|
CONFIG = %[
|
10
|
-
port
|
12
|
+
port #{PORT}
|
11
13
|
bind 127.0.0.1
|
12
14
|
body_size_limit 10m
|
13
15
|
keepalive_timeout 5
|
@@ -19,7 +21,7 @@ class HttpInputTest < Test::Unit::TestCase
|
|
19
21
|
|
20
22
|
def test_configure
|
21
23
|
d = create_driver
|
22
|
-
assert_equal
|
24
|
+
assert_equal PORT, d.instance.port
|
23
25
|
assert_equal '127.0.0.1', d.instance.bind
|
24
26
|
assert_equal 10*1024*1024, d.instance.body_size_limit
|
25
27
|
assert_equal 5, d.instance.keepalive_timeout
|
@@ -68,7 +70,7 @@ class HttpInputTest < Test::Unit::TestCase
|
|
68
70
|
|
69
71
|
d.run do
|
70
72
|
d.expected_emits.each {|tag,time,record|
|
71
|
-
http = Net::HTTP.new("127.0.0.1",
|
73
|
+
http = Net::HTTP.new("127.0.0.1", PORT)
|
72
74
|
req = Net::HTTP::Post.new("/#{tag}?time=#{time.to_s}", {"content-type"=>"application/json; charset=utf-8"})
|
73
75
|
req.body = record.to_json
|
74
76
|
res = http.request(req)
|
@@ -94,7 +96,7 @@ class HttpInputTest < Test::Unit::TestCase
|
|
94
96
|
end
|
95
97
|
|
96
98
|
def post(path, params)
|
97
|
-
http = Net::HTTP.new("127.0.0.1",
|
99
|
+
http = Net::HTTP.new("127.0.0.1", PORT)
|
98
100
|
req = Net::HTTP::Post.new(path, {})
|
99
101
|
req.set_form_data(params)
|
100
102
|
http.request(req)
|
data/test/plugin/in_stream.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'fluent/test'
|
2
|
+
require 'helper'
|
2
3
|
|
3
4
|
module StreamInputTest
|
4
5
|
def setup
|
@@ -107,8 +108,9 @@ end
|
|
107
108
|
class TcpInputTest < Test::Unit::TestCase
|
108
109
|
include StreamInputTest
|
109
110
|
|
111
|
+
PORT = unused_port
|
110
112
|
CONFIG = %[
|
111
|
-
port
|
113
|
+
port #{PORT}
|
112
114
|
bind 127.0.0.1
|
113
115
|
]
|
114
116
|
|
@@ -118,20 +120,19 @@ class TcpInputTest < Test::Unit::TestCase
|
|
118
120
|
|
119
121
|
def test_configure
|
120
122
|
d = create_driver
|
121
|
-
assert_equal
|
123
|
+
assert_equal PORT, d.instance.port
|
122
124
|
assert_equal '127.0.0.1', d.instance.bind
|
123
125
|
end
|
124
126
|
|
125
127
|
def connect
|
126
|
-
TCPSocket.new('127.0.0.1',
|
128
|
+
TCPSocket.new('127.0.0.1', PORT)
|
127
129
|
end
|
128
130
|
end
|
129
131
|
|
130
132
|
class UnixInputTest < Test::Unit::TestCase
|
131
133
|
include StreamInputTest
|
132
134
|
|
133
|
-
TMP_DIR = File.dirname(__FILE__) + "/../tmp"
|
134
|
-
|
135
|
+
TMP_DIR = File.dirname(__FILE__) + "/../tmp/in_unix#{ENV['TEST_ENV_NUMBER']}"
|
135
136
|
CONFIG = %[
|
136
137
|
path #{TMP_DIR}/unix
|
137
138
|
backlog 1000
|
@@ -151,4 +152,3 @@ class UnixInputTest < Test::Unit::TestCase
|
|
151
152
|
UNIXSocket.new("#{TMP_DIR}/unix")
|
152
153
|
end
|
153
154
|
end
|
154
|
-
|
data/test/plugin/in_syslog.rb
CHANGED
@@ -7,14 +7,15 @@ class SyslogInputTest < Test::Unit::TestCase
|
|
7
7
|
require 'fluent/plugin/socket_util'
|
8
8
|
end
|
9
9
|
|
10
|
+
PORT = unused_port
|
10
11
|
CONFIG = %[
|
11
|
-
port
|
12
|
+
port #{PORT}
|
12
13
|
bind 127.0.0.1
|
13
14
|
tag syslog
|
14
15
|
]
|
15
16
|
|
16
17
|
IPv6_CONFIG = %[
|
17
|
-
port
|
18
|
+
port #{PORT}
|
18
19
|
bind ::1
|
19
20
|
tag syslog
|
20
21
|
]
|
@@ -29,7 +30,7 @@ class SyslogInputTest < Test::Unit::TestCase
|
|
29
30
|
|
30
31
|
configs.each_pair { |k, v|
|
31
32
|
d = create_driver(v)
|
32
|
-
assert_equal
|
33
|
+
assert_equal PORT, d.instance.port
|
33
34
|
assert_equal k, d.instance.bind
|
34
35
|
}
|
35
36
|
end
|
@@ -48,7 +49,7 @@ class SyslogInputTest < Test::Unit::TestCase
|
|
48
49
|
|
49
50
|
d.run do
|
50
51
|
u = Fluent::SocketUtil.create_udp_socket(k)
|
51
|
-
u.connect(k,
|
52
|
+
u.connect(k, PORT)
|
52
53
|
tests.each {|test|
|
53
54
|
u.send(test['msg'], 0)
|
54
55
|
}
|
@@ -72,7 +73,7 @@ class SyslogInputTest < Test::Unit::TestCase
|
|
72
73
|
|
73
74
|
d.run do
|
74
75
|
u = UDPSocket.new
|
75
|
-
u.connect('127.0.0.1',
|
76
|
+
u.connect('127.0.0.1', PORT)
|
76
77
|
tests.each {|test|
|
77
78
|
u.send(test['msg'], 0)
|
78
79
|
}
|
data/test/plugin/in_tail.rb
CHANGED
data/test/plugin/out_copy.rb
CHANGED
@@ -88,5 +88,83 @@ class CopyOutputTest < Test::Unit::TestCase
|
|
88
88
|
], o.events
|
89
89
|
}
|
90
90
|
end
|
91
|
+
|
92
|
+
def create_event_test_driver(is_deep_copy = false)
|
93
|
+
deep_copy_config = %[
|
94
|
+
deep_copy true
|
95
|
+
]
|
96
|
+
|
97
|
+
output1 = Fluent::Plugin.new_output('test')
|
98
|
+
output1.configure('name' => 'output1')
|
99
|
+
output1.define_singleton_method(:emit) do |tag, es, chain|
|
100
|
+
es.each do |time, record|
|
101
|
+
record['foo'] = 'bar'
|
102
|
+
super(tag, [[time, record]], chain)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
output2 = Fluent::Plugin.new_output('test')
|
107
|
+
output2.configure('name' => 'output2')
|
108
|
+
output2.define_singleton_method(:emit) do |tag, es, chain|
|
109
|
+
es.each do |time, record|
|
110
|
+
super(tag, [[time, record]], chain)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
outputs = [output1, output2]
|
115
|
+
|
116
|
+
d = Fluent::Test::OutputTestDriver.new(Fluent::CopyOutput)
|
117
|
+
d = d.configure(deep_copy_config) if is_deep_copy
|
118
|
+
d.instance.instance_eval { @outputs = outputs }
|
119
|
+
d
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_one_event
|
123
|
+
time = Time.parse("2013-05-26 06:37:22 UTC").to_i
|
124
|
+
|
125
|
+
d = create_event_test_driver(false)
|
126
|
+
es = Fluent::OneEventStream.new(time, {"a" => 1})
|
127
|
+
d.instance.emit('test', es, Fluent::NullOutputChain.instance)
|
128
|
+
|
129
|
+
assert_equal [
|
130
|
+
[[time, {"a"=>1, "foo"=>"bar"}]],
|
131
|
+
[[time, {"a"=>1, "foo"=>"bar"}]]
|
132
|
+
], d.instance.outputs.map{ |o| o.events }
|
133
|
+
|
134
|
+
d = create_event_test_driver(true)
|
135
|
+
es = Fluent::OneEventStream.new(time, {"a" => 1})
|
136
|
+
d.instance.emit('test', es, Fluent::NullOutputChain.instance)
|
137
|
+
|
138
|
+
assert_equal [
|
139
|
+
[[time, {"a"=>1, "foo"=>"bar"}]],
|
140
|
+
[[time, {"a"=>1}]]
|
141
|
+
], d.instance.outputs.map{ |o| o.events }
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_multi_event
|
145
|
+
time = Time.parse("2013-05-26 06:37:22 UTC").to_i
|
146
|
+
|
147
|
+
d = create_event_test_driver(false)
|
148
|
+
es = Fluent::MultiEventStream.new
|
149
|
+
es.add(time, {"a" => 1})
|
150
|
+
es.add(time, {"b" => 2})
|
151
|
+
d.instance.emit('test', es, Fluent::NullOutputChain.instance)
|
152
|
+
|
153
|
+
assert_equal [
|
154
|
+
[[time, {"a"=>1, "foo"=>"bar"}], [time, {"b"=>2, "foo"=>"bar"}]],
|
155
|
+
[[time, {"a"=>1, "foo"=>"bar"}], [time, {"b"=>2, "foo"=>"bar"}]]
|
156
|
+
], d.instance.outputs.map{ |o| o.events }
|
157
|
+
|
158
|
+
d = create_event_test_driver(true)
|
159
|
+
es = Fluent::MultiEventStream.new
|
160
|
+
es.add(time, {"a" => 1})
|
161
|
+
es.add(time, {"b" => 2})
|
162
|
+
d.instance.emit('test', es, Fluent::NullOutputChain.instance)
|
163
|
+
|
164
|
+
assert_equal [
|
165
|
+
[[time, {"a"=>1, "foo"=>"bar"}], [time, {"b"=>2, "foo"=>"bar"}]],
|
166
|
+
[[time, {"a"=>1}], [time, {"b"=>2}]]
|
167
|
+
], d.instance.outputs.map{ |o| o.events }
|
168
|
+
end
|
91
169
|
end
|
92
170
|
|
data/test/plugin/out_exec.rb
CHANGED
data/test/plugin/out_file.rb
CHANGED
@@ -9,7 +9,7 @@ class FileOutputTest < Test::Unit::TestCase
|
|
9
9
|
FileUtils.mkdir_p(TMP_DIR)
|
10
10
|
end
|
11
11
|
|
12
|
-
TMP_DIR = File.expand_path(File.dirname(__FILE__) + "/../tmp")
|
12
|
+
TMP_DIR = File.expand_path(File.dirname(__FILE__) + "/../tmp/out_file#{ENV['TEST_ENV_NUMBER']}")
|
13
13
|
SYMLINK_PATH = File.expand_path("#{TMP_DIR}/current")
|
14
14
|
|
15
15
|
CONFIG = %[
|
@@ -81,20 +81,32 @@ class FileOutputTest < Test::Unit::TestCase
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def test_write_with_symlink
|
84
|
-
|
84
|
+
conf = CONFIG + %[
|
85
85
|
symlink_path #{SYMLINK_PATH}
|
86
|
-
]
|
87
|
-
symlink_path = "#{SYMLINK_PATH}
|
86
|
+
]
|
87
|
+
symlink_path = "#{SYMLINK_PATH}"
|
88
88
|
|
89
|
-
|
90
|
-
d.
|
89
|
+
Fluent::FileBuffer.clear_buffer_paths
|
90
|
+
d = Fluent::Test::TestDriver.new(Fluent::FileOutput).configure(conf)
|
91
91
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
92
|
+
begin
|
93
|
+
d.instance.start
|
94
|
+
10.times { sleep 0.05 }
|
95
|
+
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
96
|
+
es = Fluent::OneEventStream.new(time, {"a"=>1})
|
97
|
+
d.instance.emit('tag', es, Fluent::NullOutputChain.instance)
|
98
|
+
|
99
|
+
assert File.exists?(symlink_path)
|
100
|
+
assert File.symlink?(symlink_path)
|
101
|
+
|
102
|
+
d.instance.enqueue_buffer
|
103
|
+
|
104
|
+
assert !File.exists?(symlink_path)
|
105
|
+
assert File.symlink?(symlink_path)
|
106
|
+
ensure
|
107
|
+
d.instance.shutdown
|
108
|
+
FileUtils.rm_rf(symlink_path)
|
109
|
+
end
|
98
110
|
end
|
99
111
|
end
|
100
112
|
|
data/test/plugin/out_stream.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'fluent/test'
|
2
|
+
require 'helper'
|
2
3
|
|
3
4
|
module StreamOutputTest
|
4
5
|
def setup
|
@@ -33,8 +34,9 @@ end
|
|
33
34
|
class TcpOutputTest < Test::Unit::TestCase
|
34
35
|
include StreamOutputTest
|
35
36
|
|
37
|
+
PORT = unused_port
|
36
38
|
CONFIG = %[
|
37
|
-
port
|
39
|
+
port #{PORT}
|
38
40
|
host 127.0.0.1
|
39
41
|
send_timeout 51
|
40
42
|
]
|
@@ -45,7 +47,7 @@ class TcpOutputTest < Test::Unit::TestCase
|
|
45
47
|
|
46
48
|
def test_configure
|
47
49
|
d = create_driver
|
48
|
-
assert_equal
|
50
|
+
assert_equal PORT, d.instance.port
|
49
51
|
assert_equal '127.0.0.1', d.instance.host
|
50
52
|
assert_equal 51, d.instance.send_timeout
|
51
53
|
end
|
@@ -54,8 +56,7 @@ end
|
|
54
56
|
class UnixOutputTest < Test::Unit::TestCase
|
55
57
|
include StreamOutputTest
|
56
58
|
|
57
|
-
TMP_DIR = File.dirname(__FILE__) + "/../tmp"
|
58
|
-
|
59
|
+
TMP_DIR = File.dirname(__FILE__) + "/../tmp/out_unix#{ENV['TEST_ENV_NUMBER']}"
|
59
60
|
CONFIG = %[
|
60
61
|
path #{TMP_DIR}/unix
|
61
62
|
send_timeout 52
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluentd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.10.
|
4
|
+
version: 0.10.39
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sadayuki Furuhashi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-09-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|
@@ -124,6 +124,20 @@ dependencies:
|
|
124
124
|
- - '>='
|
125
125
|
- !ruby/object:Gem::Version
|
126
126
|
version: 0.9.2
|
127
|
+
- !ruby/object:Gem::Dependency
|
128
|
+
name: parallel_tests
|
129
|
+
requirement: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 0.15.3
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - '>='
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: 0.15.3
|
127
141
|
- !ruby/object:Gem::Dependency
|
128
142
|
name: rr
|
129
143
|
requirement: !ruby/object:Gem::Requirement
|