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 CHANGED
@@ -1,5 +1,12 @@
1
1
 
2
- Release 0.10.19 - 2012/04/13
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.19
1
+ 0.10.20
@@ -78,7 +78,7 @@ module Config
78
78
  if @arg.empty?
79
79
  out << "#{indent}<#{@name}>\n"
80
80
  else
81
- out << "#{indent}<#{@name} #{@name}>\n"
81
+ out << "#{indent}<#{@name} #{@arg}>\n"
82
82
  end
83
83
  each_pair {|k,v|
84
84
  out << "#{nindent}#{k} #{v}\n"
@@ -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
- config_param :in_keys, :string
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(&method(:each_line))
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
- last = @in_keys.length-1
120
- for i in 0..last
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
- out << "\n"
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(&each_line)
185
+ def initialize(parser)
176
186
  @pid = nil
177
187
  @thread = nil
178
- @each_line = each_line
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
- @io.each_line(&@each_line)
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
- :gz => :gz,
26
- :gzip => :gz,
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.to_sym]
34
+ c = SUPPORTED_COMPRESS[val]
35
35
  unless c
36
- raise ConfigError, "Unsupported compression algorithm '#{compress}'"
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
@@ -1,5 +1,5 @@
1
1
  module Fluent
2
2
 
3
- VERSION = '0.10.19'
3
+ VERSION = '0.10.20'
4
4
 
5
5
  end
@@ -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.19
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-17 00:00:00.000000000Z
12
+ date: 2012-04-27 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: msgpack
16
- requirement: &70342941850580 !ruby/object:Gem::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: *70342941850580
24
+ version_requirements: *70174884555560
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: json
27
- requirement: &70342941849920 !ruby/object:Gem::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: *70342941849920
35
+ version_requirements: *70174884536260
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: yajl-ruby
38
- requirement: &70342941849140 !ruby/object:Gem::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: *70342941849140
46
+ version_requirements: *70174884535660
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: cool.io
49
- requirement: &70342941848200 !ruby/object:Gem::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: *70342941848200
57
+ version_requirements: *70174884535020
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: http_parser.rb
60
- requirement: &70342941847500 !ruby/object:Gem::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: *70342941847500
68
+ version_requirements: *70174884534420
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rake
71
- requirement: &70342941846860 !ruby/object:Gem::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: *70342941846860
79
+ version_requirements: *70174884533820
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rr
82
- requirement: &70342941846100 !ruby/object:Gem::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: *70342941846100
90
+ version_requirements: *70174884533220
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: timecop
93
- requirement: &70342941845440 !ruby/object:Gem::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: *70342941845440
101
+ version_requirements: *70174884532660
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: jeweler
104
- requirement: &70342941844840 !ruby/object:Gem::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: *70342941844840
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