fluentd 0.10.19 → 0.10.20
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.
- data/ChangeLog +8 -1
- data/VERSION +1 -1
- data/lib/fluent/config.rb +1 -1
- data/lib/fluent/plugin/out_exec_filter.rb +164 -54
- data/lib/fluent/plugin/out_file.rb +4 -4
- data/lib/fluent/plugin/out_stdout.rb +4 -0
- data/lib/fluent/version.rb +1 -1
- data/test/plugin/out_exec_filter.rb +20 -0
- data/test/plugin/out_stdout.rb +28 -0
- metadata +22 -20
data/ChangeLog
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
|
2
|
-
Release 0.10.
|
2
|
+
Release 0.10.20 - 2012/04/27
|
3
|
+
|
4
|
+
* Fixed Config#to_s
|
5
|
+
* out_exec_filter: supports 'out_format json' option
|
6
|
+
* out_exec_filter: supports 'in_format json' option
|
7
|
+
|
8
|
+
|
9
|
+
Release 0.10.19 - 2012/04/17
|
3
10
|
|
4
11
|
* Fixed in_syslog
|
5
12
|
* in_tail: fixed "invalid byte sequence in US-ASCII" error
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.10.
|
1
|
+
0.10.20
|
data/lib/fluent/config.rb
CHANGED
@@ -25,15 +25,41 @@ class ExecFilterOutput < BufferedOutput
|
|
25
25
|
super
|
26
26
|
end
|
27
27
|
|
28
|
+
SUPPORTED_FORMAT = {
|
29
|
+
'tsv' => :tsv,
|
30
|
+
'json' => :json,
|
31
|
+
'msgpack' => :msgpack,
|
32
|
+
}
|
33
|
+
|
28
34
|
config_param :command, :string
|
29
|
-
|
35
|
+
|
30
36
|
config_param :remove_prefix, :string, :default => nil
|
31
|
-
config_param :out_keys, :string
|
32
37
|
config_param :add_prefix, :string, :default => nil
|
38
|
+
|
39
|
+
config_param :in_format, :default => :tsv do |val|
|
40
|
+
f = SUPPORTED_FORMAT[val]
|
41
|
+
raise ConfigError, "Unsupported in_format '#{val}'" unless f
|
42
|
+
f
|
43
|
+
end
|
44
|
+
config_param :in_keys, :default => [] do |val|
|
45
|
+
val.split(',')
|
46
|
+
end
|
47
|
+
|
48
|
+
config_param :out_format, :default => :tsv do |val|
|
49
|
+
f = SUPPORTED_FORMAT[val]
|
50
|
+
raise ConfigError, "Unsupported out_format '#{val}'" unless f
|
51
|
+
f
|
52
|
+
end
|
53
|
+
config_param :out_keys, :default => [] do |val| # for tsv format
|
54
|
+
val.split(',')
|
55
|
+
end
|
56
|
+
|
33
57
|
config_param :tag, :string, :default => nil
|
34
58
|
config_param :tag_key, :string, :default => nil
|
59
|
+
|
35
60
|
config_param :time_key, :string, :default => nil
|
36
61
|
config_param :time_format, :string, :default => nil
|
62
|
+
|
37
63
|
config_param :localtime, :bool, :default => true
|
38
64
|
config_param :num_children, :integer, :default => 1
|
39
65
|
|
@@ -52,9 +78,6 @@ class ExecFilterOutput < BufferedOutput
|
|
52
78
|
raise ConfigError, "'tag' or 'tag_key' option is required on exec_filter output"
|
53
79
|
end
|
54
80
|
|
55
|
-
@in_keys = @in_keys.split(',')
|
56
|
-
@out_keys = @out_keys.split(',')
|
57
|
-
|
58
81
|
if @time_key
|
59
82
|
if @time_format
|
60
83
|
f = @time_format
|
@@ -74,6 +97,30 @@ class ExecFilterOutput < BufferedOutput
|
|
74
97
|
if @add_prefix
|
75
98
|
@added_prefix_string = @add_prefix + '.'
|
76
99
|
end
|
100
|
+
|
101
|
+
case @in_format
|
102
|
+
when :tsv
|
103
|
+
if @in_keys.empty?
|
104
|
+
raise ConfigError, "in_keys option is required on exec_filter output for tsv in_format"
|
105
|
+
end
|
106
|
+
@formatter = TSVFormatter.new(@in_keys)
|
107
|
+
when :json
|
108
|
+
@formatter = JSONFormatter.new
|
109
|
+
when :msgpack
|
110
|
+
@formatter = MessagePackFormatter.new
|
111
|
+
end
|
112
|
+
|
113
|
+
case @out_format
|
114
|
+
when :tsv
|
115
|
+
if @out_keys.empty?
|
116
|
+
raise ConfigError, "out_keys option is required on exec_filter output for tsv in_format"
|
117
|
+
end
|
118
|
+
@parser = TSVParser.new(@out_keys, method(:on_message))
|
119
|
+
when :json
|
120
|
+
@parser = JSONParser.new(method(:on_message))
|
121
|
+
when :msgpack
|
122
|
+
@parser = MessagePackParser.new(method(:on_message))
|
123
|
+
end
|
77
124
|
end
|
78
125
|
|
79
126
|
def start
|
@@ -83,7 +130,7 @@ class ExecFilterOutput < BufferedOutput
|
|
83
130
|
@rr = 0
|
84
131
|
begin
|
85
132
|
@num_children.times do
|
86
|
-
c = ChildProcess.new(
|
133
|
+
c = ChildProcess.new(@parser)
|
87
134
|
c.start(@command)
|
88
135
|
@children << c
|
89
136
|
end
|
@@ -108,27 +155,22 @@ class ExecFilterOutput < BufferedOutput
|
|
108
155
|
end
|
109
156
|
|
110
157
|
def format_stream(tag, es)
|
111
|
-
out = ''
|
112
158
|
if @remove_prefix
|
113
159
|
if (tag[0, @removed_length] == @removed_prefix_string and tag.length > @removed_length) or tag == @removed_prefix
|
114
160
|
tag = tag[@removed_length..-1] || ''
|
115
161
|
end
|
116
162
|
end
|
117
163
|
|
164
|
+
out = ''
|
165
|
+
|
118
166
|
es.each {|time,record|
|
119
|
-
|
120
|
-
|
121
|
-
key = @in_keys[i]
|
122
|
-
if key == @time_key
|
123
|
-
out << @time_format_proc.call(time)
|
124
|
-
elsif key == @tag_key
|
125
|
-
out << tag
|
126
|
-
else
|
127
|
-
out << record[key].to_s
|
128
|
-
end
|
129
|
-
out << "\t" if i != last
|
167
|
+
if @time_key
|
168
|
+
record[@time_key] = @time_format_proc.call(time)
|
130
169
|
end
|
131
|
-
|
170
|
+
if @tag_key
|
171
|
+
record[@tag_key] = tag
|
172
|
+
end
|
173
|
+
@formatter.call(record, out)
|
132
174
|
}
|
133
175
|
|
134
176
|
out
|
@@ -139,43 +181,11 @@ class ExecFilterOutput < BufferedOutput
|
|
139
181
|
@children[r].write chunk
|
140
182
|
end
|
141
183
|
|
142
|
-
def each_line(line)
|
143
|
-
line.chomp!
|
144
|
-
vals = line.split("\t")
|
145
|
-
|
146
|
-
tag = @tag
|
147
|
-
time = nil
|
148
|
-
record = {}
|
149
|
-
for i in 0..@out_keys.length-1
|
150
|
-
key = @out_keys[i]
|
151
|
-
val = vals[i]
|
152
|
-
if key == @time_key
|
153
|
-
time = @time_parse_proc.call(val)
|
154
|
-
elsif key == @tag_key
|
155
|
-
tag = if @add_prefix
|
156
|
-
@added_prefix_string + val
|
157
|
-
else
|
158
|
-
val
|
159
|
-
end
|
160
|
-
else
|
161
|
-
record[key] = val
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
if tag
|
166
|
-
time ||= Engine.now
|
167
|
-
Engine.emit(tag, time, record)
|
168
|
-
end
|
169
|
-
rescue
|
170
|
-
$log.error "exec_filter failed to emit", :error=>$!.to_s, :line=>line
|
171
|
-
$log.warn_backtrace $!.backtrace
|
172
|
-
end
|
173
|
-
|
174
184
|
class ChildProcess
|
175
|
-
def initialize(
|
185
|
+
def initialize(parser)
|
176
186
|
@pid = nil
|
177
187
|
@thread = nil
|
178
|
-
@
|
188
|
+
@parser = parser
|
179
189
|
end
|
180
190
|
|
181
191
|
def start(command)
|
@@ -215,7 +225,7 @@ class ExecFilterOutput < BufferedOutput
|
|
215
225
|
end
|
216
226
|
|
217
227
|
def run
|
218
|
-
@
|
228
|
+
@parser.call(@io)
|
219
229
|
rescue
|
220
230
|
$log.error "exec_filter process exited", :error=>$!.to_s
|
221
231
|
$log.warn_backtrace $!.backtrace
|
@@ -223,6 +233,106 @@ class ExecFilterOutput < BufferedOutput
|
|
223
233
|
Process.waitpid(@pid)
|
224
234
|
end
|
225
235
|
end
|
236
|
+
|
237
|
+
class Formatter
|
238
|
+
end
|
239
|
+
|
240
|
+
class TSVFormatter < Formatter
|
241
|
+
def initialize(in_keys)
|
242
|
+
@in_keys = in_keys
|
243
|
+
super()
|
244
|
+
end
|
245
|
+
|
246
|
+
def call(record, out)
|
247
|
+
last = @in_keys.length-1
|
248
|
+
for i in 0..last
|
249
|
+
key = @in_keys[i]
|
250
|
+
out << record[key].to_s
|
251
|
+
out << "\t" if i != last
|
252
|
+
end
|
253
|
+
out << "\n"
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
class JSONFormatter < Formatter
|
258
|
+
def call(record, out)
|
259
|
+
out << Yajl.dump(record)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
class MessagePackFormatter < Formatter
|
264
|
+
def call(record, out)
|
265
|
+
record.to_msgpack(out)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def on_message(record)
|
270
|
+
if val = record.delete(@time_key)
|
271
|
+
time = @time_parse_proc.call(val)
|
272
|
+
else
|
273
|
+
time = Engine.now
|
274
|
+
end
|
275
|
+
|
276
|
+
if val = record.delete(@tag_key)
|
277
|
+
tag = if @add_prefix
|
278
|
+
@added_prefix_string + val
|
279
|
+
else
|
280
|
+
val
|
281
|
+
end
|
282
|
+
else
|
283
|
+
tag = @tag
|
284
|
+
end
|
285
|
+
|
286
|
+
Engine.emit(tag, time, record)
|
287
|
+
|
288
|
+
rescue
|
289
|
+
$log.error "exec_filter failed to emit", :error=>$!.to_s, :record=>Yajl.dump(record)
|
290
|
+
$log.warn_backtrace $!.backtrace
|
291
|
+
end
|
292
|
+
|
293
|
+
class Parser
|
294
|
+
def initialize(on_message)
|
295
|
+
@on_message = on_message
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
class TSVParser < Parser
|
300
|
+
def initialize(out_keys, on_message)
|
301
|
+
@out_keys = out_keys
|
302
|
+
super(on_message)
|
303
|
+
end
|
304
|
+
|
305
|
+
def call(io)
|
306
|
+
io.each_line(&method(:each_line))
|
307
|
+
end
|
308
|
+
|
309
|
+
def each_line(line)
|
310
|
+
line.chomp!
|
311
|
+
vals = line.split("\t")
|
312
|
+
|
313
|
+
record = Hash[@out_keys.zip(vals)]
|
314
|
+
|
315
|
+
@on_message.call(record)
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
class JSONParser < Parser
|
320
|
+
def call(io)
|
321
|
+
y = Yajl::Parser.new
|
322
|
+
y.on_parse_complete = @on_message
|
323
|
+
y.parse(io)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
class MessagePackParser < Parser
|
328
|
+
def call(io)
|
329
|
+
@u = MessagePack::Unpacker.new(io)
|
330
|
+
begin
|
331
|
+
@u.each(&@on_message)
|
332
|
+
rescue EOFError
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
226
336
|
end
|
227
337
|
|
228
338
|
|
@@ -22,8 +22,8 @@ class FileOutput < TimeSlicedOutput
|
|
22
22
|
Plugin.register_output('file', self)
|
23
23
|
|
24
24
|
SUPPORTED_COMPRESS = {
|
25
|
-
|
26
|
-
|
25
|
+
'gz' => :gz,
|
26
|
+
'gzip' => :gz,
|
27
27
|
}
|
28
28
|
|
29
29
|
config_param :path, :string
|
@@ -31,9 +31,9 @@ class FileOutput < TimeSlicedOutput
|
|
31
31
|
config_param :time_format, :string, :default => nil
|
32
32
|
|
33
33
|
config_param :compress, :default => nil do |val|
|
34
|
-
c = SUPPORTED_COMPRESS[val
|
34
|
+
c = SUPPORTED_COMPRESS[val]
|
35
35
|
unless c
|
36
|
-
raise ConfigError, "Unsupported compression algorithm '#{
|
36
|
+
raise ConfigError, "Unsupported compression algorithm '#{val}'"
|
37
37
|
end
|
38
38
|
c
|
39
39
|
end
|
@@ -21,10 +21,14 @@ module Fluent
|
|
21
21
|
class StdoutOutput < Output
|
22
22
|
Plugin.register_output('stdout', self)
|
23
23
|
|
24
|
+
config_param :autoflush, :bool, :default => false
|
25
|
+
|
24
26
|
def emit(tag, es, chain)
|
25
27
|
es.each {|time,record|
|
26
28
|
puts "#{Time.at(time).localtime} #{tag}: #{Yajl.dump(record)}"
|
27
29
|
}
|
30
|
+
STDOUT.flush if @autoflush
|
31
|
+
|
28
32
|
chain.next
|
29
33
|
end
|
30
34
|
end
|
data/lib/fluent/version.rb
CHANGED
@@ -156,5 +156,25 @@ class ExecFilterOutputTest < Test::Unit::TestCase
|
|
156
156
|
assert_equal ["output.test", time, {"val2"=>"sed-ed value bar"}], emits[0]
|
157
157
|
assert_equal ["output.test", time, {"val2"=>"sed-ed value poo"}], emits[1]
|
158
158
|
end
|
159
|
+
|
160
|
+
def test_json_1
|
161
|
+
d = create_driver(%[
|
162
|
+
command cat
|
163
|
+
in_keys message
|
164
|
+
out_format json
|
165
|
+
time_key time
|
166
|
+
tag_key tag
|
167
|
+
], 'input.test')
|
168
|
+
|
169
|
+
time = Time.parse("2011-01-02 13:14:15").to_i
|
170
|
+
|
171
|
+
d.run do
|
172
|
+
d.emit({"message"=>%[{"time":#{time},"tag":"t1","k1":"v1"}]}, time+10)
|
173
|
+
end
|
174
|
+
|
175
|
+
emits = d.emits
|
176
|
+
assert_equal 1, emits.length
|
177
|
+
assert_equal ["t1", time, {"k1"=>"v1"}], emits[0]
|
178
|
+
end
|
159
179
|
end
|
160
180
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'fluent/test'
|
2
|
+
|
3
|
+
class StdoutOutputTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
Fluent::Test.setup
|
6
|
+
end
|
7
|
+
|
8
|
+
CONFIG = %[
|
9
|
+
]
|
10
|
+
|
11
|
+
def create_driver(conf = CONFIG)
|
12
|
+
Fluent::Test::OutputTestDriver.new(Fluent::StdoutOutput).configure(conf)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_configure
|
16
|
+
d = create_driver
|
17
|
+
assert (not d.instance.autoflush)
|
18
|
+
|
19
|
+
d = create_driver %[
|
20
|
+
autoflush true
|
21
|
+
]
|
22
|
+
assert d.instance.autoflush
|
23
|
+
end
|
24
|
+
|
25
|
+
# def test_emit
|
26
|
+
# end
|
27
|
+
end
|
28
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
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.20
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-04-
|
12
|
+
date: 2012-04-27 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: msgpack
|
16
|
-
requirement: &
|
16
|
+
requirement: &70174884555560 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 0.4.4
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70174884555560
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: json
|
27
|
-
requirement: &
|
27
|
+
requirement: &70174884536260 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 1.4.3
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70174884536260
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: yajl-ruby
|
38
|
-
requirement: &
|
38
|
+
requirement: &70174884535660 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '1.0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70174884535660
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: cool.io
|
49
|
-
requirement: &
|
49
|
+
requirement: &70174884535020 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 1.1.0
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70174884535020
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: http_parser.rb
|
60
|
-
requirement: &
|
60
|
+
requirement: &70174884534420 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: 0.5.1
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70174884534420
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rake
|
71
|
-
requirement: &
|
71
|
+
requirement: &70174884533820 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: 0.9.2
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70174884533820
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: rr
|
82
|
-
requirement: &
|
82
|
+
requirement: &70174884533220 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: 1.0.0
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70174884533220
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: timecop
|
93
|
-
requirement: &
|
93
|
+
requirement: &70174884532660 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: 0.3.0
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70174884532660
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: jeweler
|
104
|
-
requirement: &
|
104
|
+
requirement: &70174884532120 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,7 +109,7 @@ dependencies:
|
|
109
109
|
version: 1.0.0
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *70174884532120
|
113
113
|
description:
|
114
114
|
email: frsyuki@gmail.com
|
115
115
|
executables:
|
@@ -192,6 +192,7 @@ files:
|
|
192
192
|
- test/plugin/out_file.rb
|
193
193
|
- test/plugin/out_forward.rb
|
194
194
|
- test/plugin/out_roundrobin.rb
|
195
|
+
- test/plugin/out_stdout.rb
|
195
196
|
- test/plugin/out_stream.rb
|
196
197
|
- ChangeLog
|
197
198
|
- README
|
@@ -237,4 +238,5 @@ test_files:
|
|
237
238
|
- test/plugin/out_file.rb
|
238
239
|
- test/plugin/out_forward.rb
|
239
240
|
- test/plugin/out_roundrobin.rb
|
241
|
+
- test/plugin/out_stdout.rb
|
240
242
|
- test/plugin/out_stream.rb
|