fluentd 0.12.18 → 0.12.19

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 07240444ef56a97335d1f42c0153a8be4059e77a
4
- data.tar.gz: 31cec22258753e9e6e51780b6a8d33e1194879c2
3
+ metadata.gz: 251e0a23a2109a9b8434de8be77676e4acb84b0f
4
+ data.tar.gz: 495d9a6ca6baa5266da3c04f11f5b65336252674
5
5
  SHA512:
6
- metadata.gz: 404559093a12caba1b073e0106287975f9e3dd3ea4ae8be191e95a71abf8d49b13c81c53539830bc2672e0a4741d5088cae800b6906fe3789a7849a8f19997b0
7
- data.tar.gz: d8d4411e79d2211526ca7ce69d47263c18b7d8b47606be018a926b2dbf44a25195ffc35fa4aadb23a77067e390d7f4dbe2d395b9d81e912ad25aca085683e63b
6
+ metadata.gz: 9799adf3dbb5078f797aedf12275283b153e8201c1ab6fa4310bf80e9460911f3077499def817a82f2709cbc4a9fda82be1f88b7b0149b17d45b98cf4f8c237a
7
+ data.tar.gz: a1ef697d0b1ae85a414b9a3f65aaef5b108fea491c13edf0f9c17ab965d2dfd2606b276d81762c5d59f185aaba25bb74424b40d04048608dcb6b937d69411c2d
data/ChangeLog CHANGED
@@ -1,5 +1,21 @@
1
1
  # v0.12
2
2
 
3
+ ## Release 0.12.19 - 2015/12/21
4
+
5
+ ### New features / Enhancement
6
+
7
+ * input: Standardize logging level for source configs
8
+ https://github.com/fluent/fluentd/pull/743
9
+ * buffer: Add buffer_queue_full_action parameter
10
+ https://github.com/fluent/fluentd/pull/745
11
+ * parser/formatter: Use 'oj' when oj is installed in json parser/formatter
12
+ https://github.com/fluent/fluentd/pull/748
13
+
14
+ ### Bug fixes
15
+
16
+ * fluent-cat: fix the regression of --msgpack option
17
+ https://github.com/fluent/fluentd/pull/747
18
+
3
19
  ## Release 0.12.18 - 2015/12/09
4
20
 
5
21
  ### New features / Enhancement
@@ -37,4 +37,5 @@ Gem::Specification.new do |gem|
37
37
  gem.add_development_dependency("timecop", [">= 0.3.0"])
38
38
  gem.add_development_dependency("test-unit", ["~> 3.1.4"])
39
39
  gem.add_development_dependency("test-unit-rr", ["~> 1.0.3"])
40
+ gem.add_development_dependency("oj", ["~> 2.14"])
40
41
  end
@@ -143,6 +143,8 @@ module Fluent
143
143
  config_param :buffer_chunk_limit, :size, :default => 8*1024*1024
144
144
  desc 'The length limit of the chunk queue.'
145
145
  config_param :buffer_queue_limit, :integer, :default => 256
146
+ desc 'The action when the size of buffer queue exceeds the buffer_queue_limit.'
147
+ config_param :buffer_queue_full_action, :enum, :list => [:exception, :block], :default => :exception
146
148
 
147
149
  alias chunk_limit buffer_chunk_limit
148
150
  alias chunk_limit= buffer_chunk_limit=
@@ -151,6 +153,10 @@ module Fluent
151
153
 
152
154
  def configure(conf)
153
155
  super
156
+
157
+ if @buffer_queue_full_action == :block
158
+ $log.warn "'block' action stops input process until the buffer full is resolved. Check your pipeline this action is fit or not"
159
+ end
154
160
  end
155
161
 
156
162
  def start
@@ -179,16 +185,28 @@ module Fluent
179
185
  key = key.to_s
180
186
 
181
187
  synchronize do
182
- # chunk unique id is generated in #new_chunk
183
- chunk = (@map[key] ||= new_chunk(key))
188
+ begin
189
+ # chunk unique id is generated in #new_chunk
190
+ chunk = (@map[key] ||= new_chunk(key))
184
191
 
185
- if storable?(chunk, data)
186
- chain.next
187
- chunk << data
188
- return false
192
+ if storable?(chunk, data)
193
+ chain.next
194
+ chunk << data
195
+ return false
189
196
 
190
- elsif @queue.size >= @buffer_queue_limit
191
- raise BufferQueueLimitError, "queue size exceeds limit"
197
+ elsif @queue.size >= @buffer_queue_limit
198
+ raise BufferQueueLimitError, "queue size exceeds limit"
199
+ end
200
+ rescue BufferQueueLimitError => e
201
+ case @buffer_queue_full_action
202
+ when :exception
203
+ raise e
204
+ when :block
205
+ # This is rough implementation. New Buffer API should improve this routine by using wait/signal
206
+ $log.debug "buffer queue is full. Wait 1 second to re-emit events"
207
+ sleep 1
208
+ retry
209
+ end
192
210
  end
193
211
 
194
212
  if data.bytesize > @buffer_chunk_limit
@@ -288,6 +288,8 @@ when 'json'
288
288
  end
289
289
 
290
290
  when 'msgpack'
291
+ require 'fluent/engine'
292
+
291
293
  begin
292
294
  u = Fluent::Engine.msgpack_factory.unpacker($stdin)
293
295
  u.each {|record|
@@ -17,6 +17,7 @@
17
17
  module Fluent
18
18
  require 'fluent/event_router'
19
19
  require 'fluent/root_agent'
20
+ require 'fluent/time'
20
21
 
21
22
  class EngineClass
22
23
  class DummyMessagePackFactory
@@ -131,8 +131,23 @@ module Fluent
131
131
  include HandleTagAndTimeMixin
132
132
  include StructuredFormatMixin
133
133
 
134
+ config_param :json_parser, :string, :default => 'oj'
135
+
136
+ def configure(conf)
137
+ super
138
+
139
+ begin
140
+ raise LoadError unless @json_parser == 'oj'
141
+ require 'oj'
142
+ Oj.default_options = {:mode => :compat}
143
+ @dump_proc = Oj.method(:dump)
144
+ rescue LoadError
145
+ @dump_proc = Yajl.method(:dump)
146
+ end
147
+ end
148
+
134
149
  def format_record(record)
135
- "#{Yajl.dump(record)}\n"
150
+ "#{@dump_proc.call(record)}\n"
136
151
  end
137
152
  end
138
153
 
@@ -237,6 +237,7 @@ module Fluent
237
237
  class JSONParser < Parser
238
238
  config_param :time_key, :string, :default => 'time'
239
239
  config_param :time_format, :string, :default => nil
240
+ config_param :json_parser, :string, :default => 'oj'
240
241
 
241
242
  def configure(conf)
242
243
  super
@@ -245,10 +246,20 @@ module Fluent
245
246
  @time_parser = TimeParser.new(@time_format)
246
247
  @mutex = Mutex.new
247
248
  end
249
+
250
+ begin
251
+ raise LoadError unless @json_parser == 'oj'
252
+ require 'oj'
253
+ @load_proc = Oj.method(:load)
254
+ @error_class = Oj::ParseError
255
+ rescue LoadError
256
+ @load_proc = Yajl.method(:load)
257
+ @error_class = Yajl::ParseError
258
+ end
248
259
  end
249
260
 
250
261
  def parse(text)
251
- record = Yajl.load(text)
262
+ record = @load_proc.call(text)
252
263
 
253
264
  value = @keep_time_key ? record[@time_key] : record.delete(@time_key)
254
265
  if value
@@ -274,7 +285,7 @@ module Fluent
274
285
  else
275
286
  return time, record
276
287
  end
277
- rescue Yajl::ParseError
288
+ rescue @error_class
278
289
  if block_given?
279
290
  yield nil, nil
280
291
  else
@@ -179,7 +179,7 @@ module Fluent
179
179
  File.unlink(@path)
180
180
  end
181
181
  FileUtils.mkdir_p File.dirname(@path)
182
- log.debug "listening fluent socket on #{@path}"
182
+ log.info "listening fluent socket on #{@path}"
183
183
  s = Coolio::UNIXServer.new(@path, Handler, log, method(:on_message))
184
184
  s.listen(@backlog) unless @backlog.nil?
185
185
  s
@@ -173,7 +173,7 @@ module Fluent
173
173
  private
174
174
 
175
175
  def listen(callback)
176
- log.debug "listening syslog socket on #{@bind}:#{@port} with #{@protocol_type}"
176
+ log.info "listening syslog socket on #{@bind}:#{@port} with #{@protocol_type}"
177
177
  if @protocol_type == :udp
178
178
  @usock = SocketUtil.create_udp_socket(@bind)
179
179
  @usock.bind(@bind, @port)
@@ -25,7 +25,7 @@ module Fluent
25
25
  config_param :delimiter, :string, :default => "\n" # syslog family add "\n" to each message and this seems only way to split messages in tcp stream
26
26
 
27
27
  def listen(callback)
28
- log.debug "listening tcp socket on #{@bind}:#{@port}"
28
+ log.info "listening tcp socket on #{@bind}:#{@port}"
29
29
  Coolio::TCPServer.new(@bind, @port, SocketUtil::TcpHandler, log, @delimiter, callback)
30
30
  end
31
31
  end
@@ -24,7 +24,7 @@ module Fluent
24
24
  config_param :body_size_limit, :size, :default => 4096
25
25
 
26
26
  def listen(callback)
27
- log.debug "listening udp socket on #{@bind}:#{@port}"
27
+ log.info "listening udp socket on #{@bind}:#{@port}"
28
28
  @usock = SocketUtil.create_udp_socket(@bind)
29
29
  @usock.bind(@bind, @port)
30
30
  SocketUtil::UdpHandler.new(@usock, log, @body_size_limit, callback)
@@ -16,6 +16,8 @@
16
16
 
17
17
  module Fluent
18
18
  module Test
19
+ require 'fluent/config'
20
+
19
21
  class FormatterTestDriver
20
22
  def initialize(klass_or_str, proc=nil, &block)
21
23
  if klass_or_str.is_a?(Class)
@@ -41,8 +43,7 @@ module Fluent
41
43
  when Fluent::Config::Element
42
44
  @config = conf
43
45
  when String
44
- io = StringIO.new(conf)
45
- @config = Config::Parser.parse(io, 'fluent.conf')
46
+ @config = Config.parse(conf, 'fluent.conf')
46
47
  when Hash
47
48
  @config = Config::Element.new('ROOT', '', conf, [])
48
49
  else
@@ -16,6 +16,8 @@
16
16
 
17
17
  module Fluent
18
18
  module Test
19
+ require 'fluent/config'
20
+
19
21
  class ParserTestDriver
20
22
  def initialize(klass_or_str, format=nil, conf={}, &block)
21
23
  if klass_or_str.is_a?(Class)
@@ -47,8 +49,7 @@ module Fluent
47
49
  when Fluent::Config::Element
48
50
  @config = conf
49
51
  when String
50
- io = StringIO.new(conf)
51
- @config = Config::Parser.parse(io, 'fluent.conf')
52
+ @config = Config.parse(conf, 'fluent.conf')
52
53
  when Hash
53
54
  @config = Config::Element.new('ROOT', '', conf, [])
54
55
  else
@@ -0,0 +1 @@
1
+ # placeholder for v0.14 time module
@@ -16,6 +16,6 @@
16
16
 
17
17
  module Fluent
18
18
 
19
- VERSION = '0.12.18'
19
+ VERSION = '0.12.19'
20
20
 
21
21
  end
@@ -30,14 +30,20 @@ class StdoutOutputTest < Test::Unit::TestCase
30
30
  end
31
31
  end
32
32
 
33
- def test_emit_json
34
- d = create_driver(CONFIG + "\noutput_type json")
33
+ data('oj' => 'oj', 'yajl' => 'yajl')
34
+ def test_emit_json(data)
35
+ d = create_driver(CONFIG + "\noutput_type json\njson_parser #{data}")
35
36
  time = Time.now
36
37
  out = capture_log { d.emit({'test' => 'test'}, time) }
37
38
  assert_equal "#{time.localtime} test: {\"test\":\"test\"}\n", out
38
39
 
39
- # NOTE: Float::NAN is not jsonable
40
- assert_raise(Yajl::EncodeError) { d.emit({'test' => Float::NAN}, time) }
40
+ if data == 'yajl'
41
+ # NOTE: Float::NAN is not jsonable
42
+ assert_raise(Yajl::EncodeError) { d.emit({'test' => Float::NAN}, time) }
43
+ else
44
+ out = capture_log { d.emit({'test' => Float::NAN}, time) }
45
+ assert_equal "#{time.localtime} test: {\"test\":NaN}\n", out
46
+ end
41
47
  end
42
48
 
43
49
  def test_emit_hash
@@ -4,6 +4,7 @@ require 'fluent/buffer'
4
4
 
5
5
  require 'stringio'
6
6
  require 'msgpack'
7
+ require 'timeout'
7
8
 
8
9
  module FluentBufferTest
9
10
  class BufferTest < Test::Unit::TestCase
@@ -526,5 +527,80 @@ module FluentBufferTest
526
527
 
527
528
  assert chunks.reduce(true){|a,b| a && b.purged }
528
529
  end
530
+
531
+ sub_test_case 'buffer_queue_full_action' do
532
+ def dummy_buffer(action)
533
+ db = DummyBuffer.new
534
+ db.configure(
535
+ "buffer_chunk_limit" => 1024,
536
+ "buffer_queue_limit" => 1,
537
+ "buffer_queue_full_action" => action
538
+ )
539
+ db.start
540
+ db
541
+ end
542
+
543
+ def data
544
+ @data ||= "a" * 1024
545
+ end
546
+
547
+ def chain
548
+ @chain ||= DummyChain.new
549
+ end
550
+
551
+ def test_emit_with_exception
552
+ db = dummy_buffer(:exception)
553
+
554
+ assert !db.emit('key', data, chain)
555
+ assert db.emit('key', data, chain)
556
+
557
+ assert_raise(Fluent::BufferQueueLimitError) {
558
+ assert db.emit('key', data, chain)
559
+ }
560
+ assert db.queue.size == 1
561
+
562
+ assert !pop_chunk(db)
563
+ assert db.queue.size == 0
564
+
565
+ # queue is now empty so can emit data again
566
+ assert db.emit('key', data, chain)
567
+ end
568
+
569
+ def test_emit_with_block
570
+ db = dummy_buffer(:block)
571
+
572
+ assert !db.emit('key', data, chain)
573
+ assert db.emit('key', data, chain)
574
+
575
+ begin
576
+ # with block, emit events to full queue causes sleep loop
577
+ timeout(1) {
578
+ assert db.emit('key', data, chain)
579
+ }
580
+ flunk("timeout must happen")
581
+ rescue Timeout::Error => e
582
+ end
583
+ assert db.queue.size == 1
584
+
585
+ assert !pop_chunk(db)
586
+ assert db.queue.size == 0
587
+
588
+ # queue is now empty so can emit data again
589
+ assert db.emit('key', data, chain)
590
+ end
591
+
592
+ def pop_chunk(db)
593
+ out = DummyOutput.new
594
+ c1 = DummyChunk.new('k1', 1)
595
+
596
+ pop_return_value = nil
597
+ c1.synchronize do
598
+ pop_return_value = Thread.new {
599
+ db.pop(out)
600
+ }.value
601
+ end
602
+ pop_return_value
603
+ end
604
+ end
529
605
  end
530
606
  end
@@ -130,15 +130,17 @@ module FormatterTest
130
130
  @time = Engine.now
131
131
  end
132
132
 
133
- def test_format
134
- @formatter.configure({})
133
+ data('oj' => 'oj', 'yajl' => 'yajl')
134
+ def test_format(data)
135
+ @formatter.configure('json_parser' => data)
135
136
  formatted = @formatter.format(tag, @time, record)
136
137
 
137
138
  assert_equal("#{Yajl.dump(record)}\n", formatted)
138
139
  end
139
140
 
140
- def test_format_with_include_tag
141
- @formatter.configure('include_tag_key' => 'true', 'tag_key' => 'foo')
141
+ data('oj' => 'oj', 'yajl' => 'yajl')
142
+ def test_format_with_include_tag(data)
143
+ @formatter.configure('include_tag_key' => 'true', 'tag_key' => 'foo', 'json_parser' => data)
142
144
  formatted = @formatter.format(tag, @time, record.dup)
143
145
 
144
146
  r = record
@@ -146,8 +148,9 @@ module FormatterTest
146
148
  assert_equal("#{Yajl.dump(r)}\n", formatted)
147
149
  end
148
150
 
149
- def test_format_with_include_time
150
- @formatter.configure('include_time_key' => 'true', 'localtime' => '')
151
+ data('oj' => 'oj', 'yajl' => 'yajl')
152
+ def test_format_with_include_time(data)
153
+ @formatter.configure('include_time_key' => 'true', 'localtime' => '', 'json_parser' => data)
151
154
  formatted = @formatter.format(tag, @time, record.dup)
152
155
 
153
156
  r = record
@@ -155,8 +158,9 @@ module FormatterTest
155
158
  assert_equal("#{Yajl.dump(r)}\n", formatted)
156
159
  end
157
160
 
158
- def test_format_with_include_time_as_number
159
- @formatter.configure('include_time_key' => 'true', 'time_as_epoch' => 'true', 'time_key' => 'epoch')
161
+ data('oj' => 'oj', 'yajl' => 'yajl')
162
+ def test_format_with_include_time_as_number(data)
163
+ @formatter.configure('include_time_key' => 'true', 'time_as_epoch' => 'true', 'time_key' => 'epoch', 'json_parser' => data)
160
164
  formatted = @formatter.format(tag, @time, record.dup)
161
165
 
162
166
  r = record
@@ -1,6 +1,7 @@
1
1
  require_relative 'helper'
2
2
  require 'fluent/test'
3
3
  require 'fluent/parser'
4
+ require 'fluent/plugin/string_util'
4
5
 
5
6
  module ParserTest
6
7
  include Fluent
@@ -372,7 +373,9 @@ module ParserTest
372
373
  @parser = TextParser::JSONParser.new
373
374
  end
374
375
 
375
- def test_parse
376
+ data('oj' => 'oj', 'yajl' => 'yajl')
377
+ def test_parse(data)
378
+ @parser.configure('json_parser' => data)
376
379
  @parser.parse('{"time":1362020400,"host":"192.168.0.1","size":777,"method":"PUT"}') { |time, record|
377
380
  assert_equal(str2time('2013-02-28 12:00:00 +0900').to_i, time)
378
381
  assert_equal({
@@ -383,9 +386,11 @@ module ParserTest
383
386
  }
384
387
  end
385
388
 
386
- def test_parse_without_time
389
+ data('oj' => 'oj', 'yajl' => 'yajl')
390
+ def test_parse_without_time(data)
387
391
  time_at_start = Time.now.to_i
388
392
 
393
+ @parser.configure('json_parser' => data)
389
394
  @parser.parse('{"host":"192.168.0.1","size":777,"method":"PUT"}') { |time, record|
390
395
  assert time && time >= time_at_start, "parser puts current time without time input"
391
396
  assert_equal({
@@ -397,7 +402,7 @@ module ParserTest
397
402
 
398
403
  parser = TextParser::JSONParser.new
399
404
  parser.estimate_current_event = false
400
- parser.configure({})
405
+ parser.configure('json_parser' => data)
401
406
  parser.parse('{"host":"192.168.0.1","size":777,"method":"PUT"}') { |time, record|
402
407
  assert_equal({
403
408
  'host' => '192.168.0.1',
@@ -408,17 +413,21 @@ module ParserTest
408
413
  }
409
414
  end
410
415
 
411
- def test_parse_with_invalid_time
416
+ data('oj' => 'oj', 'yajl' => 'yajl')
417
+ def test_parse_with_invalid_time(data)
418
+ @parser.configure('json_parser' => data)
412
419
  assert_raise Fluent::ParserError do
413
420
  @parser.parse('{"time":[],"k":"v"}') { |time, record| }
414
421
  end
415
422
  end
416
423
 
417
- def test_parse_with_keep_time_key
424
+ data('oj' => 'oj', 'yajl' => 'yajl')
425
+ def test_parse_with_keep_time_key(data)
418
426
  parser = TextParser::JSONParser.new
419
427
  parser.configure(
420
- 'time_format'=>"%d/%b/%Y:%H:%M:%S %z",
421
- 'keep_time_key'=>'true',
428
+ 'time_format' => "%d/%b/%Y:%H:%M:%S %z",
429
+ 'keep_time_key' => 'true',
430
+ 'json_parser' => data
422
431
  )
423
432
  text = "28/Feb/2013:12:00:00 +0900"
424
433
  parser.parse("{\"time\":\"#{text}\"}") do |time, record|
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.12.18
4
+ version: 0.12.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sadayuki Furuhashi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-09 00:00:00.000000000 Z
11
+ date: 2015-12-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -266,6 +266,20 @@ dependencies:
266
266
  - - "~>"
267
267
  - !ruby/object:Gem::Version
268
268
  version: 1.0.3
269
+ - !ruby/object:Gem::Dependency
270
+ name: oj
271
+ requirement: !ruby/object:Gem::Requirement
272
+ requirements:
273
+ - - "~>"
274
+ - !ruby/object:Gem::Version
275
+ version: '2.14'
276
+ type: :development
277
+ prerelease: false
278
+ version_requirements: !ruby/object:Gem::Requirement
279
+ requirements:
280
+ - - "~>"
281
+ - !ruby/object:Gem::Version
282
+ version: '2.14'
269
283
  description: Fluentd is an open source data collector designed to scale and simplify
270
284
  log management. It can collect, process and ship many kinds of data in near real-time.
271
285
  email:
@@ -384,6 +398,7 @@ files:
384
398
  - lib/fluent/test/input_test.rb
385
399
  - lib/fluent/test/output_test.rb
386
400
  - lib/fluent/test/parser_test.rb
401
+ - lib/fluent/time.rb
387
402
  - lib/fluent/timezone.rb
388
403
  - lib/fluent/version.rb
389
404
  - test/config/assertions.rb