fluentd 0.10.33 → 0.10.34

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,10 +1,27 @@
1
1
 
2
+ Release 0.10.34 - 2013/06/03
3
+
4
+ * fluentd: supports --emit-error-log-interval to suppress log messages with the
5
+ same message for a certain seconds
6
+ * BufferedOutput: fixed warning messages so that errors with the same meaning
7
+ use the same message
8
+ * Log: ignores ThreadError which could happen in signal handler
9
+ * Engine: prevents signal handlers from calling stop() method of plugins twice
10
+ * MessagePackEventStream/in_forward: doesn't cache MessagePack::Unpacker (if
11
+ it uses msgpack-0.5.5 which doesn't cause performance impact) to not cause
12
+ problems with out_copy
13
+ * TextParser/in_tail,in_syslog: 'json' format type removes time key from records
14
+ * TextParser/in_tail,in_syslog: raises exception if time_format is set while
15
+ time_key is not set
16
+ * in_tail: fixed minor bugs
17
+
18
+
2
19
  Release 0.10.33 - 2013/03/28
3
20
 
4
- * add in_monitor_agent
21
+ * added in_monitor_agent
5
22
  * switched from jeweler to bundler
6
23
  * updated dependency for msgpack from '~> 0.4.4' to '~> 0.4.4 OR ~> 0.5.4'
7
- * dded PluginId module so that in_monitor_agent can search plugins by id
24
+ * added PluginId module so that in_monitor_agent can search plugins by id
8
25
  * BufferedOutput: added queued_chunk_flush_interval option to insert delay
9
26
  time before flushing queued chunks
10
27
  * BufferedOutput: randomize retry interval to prevent multiple servers from
@@ -35,6 +35,7 @@ opts = {
35
35
  :setup_path => nil,
36
36
  :chuser => nil,
37
37
  :chgroup => nil,
38
+ :suppress_interval => 0,
38
39
  }
39
40
 
40
41
  op.on('-s', "--setup [DIR=#{File.dirname(Fluent::DEFAULT_CONFIG_PATH)}]", "install sample configuration file to the directory") {|s|
@@ -77,6 +78,9 @@ op.on('-i', '--inline-config CONFIG_STRING', "inline config which is appended to
77
78
  opts[:inline_config] = s
78
79
  }
79
80
 
81
+ op.on('--emit-error-log-interval SECONDS', "suppress interval seconds of emit error logs") {|s|
82
+ opts[:suppress_interval] = s.to_i
83
+ }
80
84
 
81
85
  op.on('-v', '--verbose', "increase verbose level (-v: debug, -vv: trace)", TrueClass) {|b|
82
86
  if b
data/lib/fluent/engine.rb CHANGED
@@ -26,6 +26,9 @@ class EngineClass
26
26
  @match_cache_keys = []
27
27
  @started = []
28
28
  @default_loop = nil
29
+
30
+ @suppress_emit_error_log_interval = 0
31
+ @next_emit_error_log_time = nil
29
32
  end
30
33
 
31
34
  MATCH_CACHE_SIZE = 1024
@@ -42,6 +45,11 @@ class EngineClass
42
45
  self
43
46
  end
44
47
 
48
+ def suppress_interval(interval_time)
49
+ @suppress_emit_error_log_interval = interval_time
50
+ @next_emit_error_log_time = Time.now.to_i
51
+ end
52
+
45
53
  def read_config(path)
46
54
  $log.info "reading config file", :path=>path
47
55
  File.open(path) {|io|
@@ -119,8 +127,14 @@ class EngineClass
119
127
  end
120
128
  target.emit(tag, es)
121
129
  rescue
122
- $log.warn "emit transaction failed ", :error=>$!.to_s
123
- $log.warn_backtrace
130
+ if @suppress_emit_error_log_interval == 0 || now > @next_emit_error_log_time
131
+ $log.warn "emit transaction failed ", :error=>$!.to_s
132
+ $log.warn_backtrace
133
+ # $log.debug "current next_emit_error_log_time: #{Time.at(@next_emit_error_log_time)}"
134
+ @next_emit_error_log_time = Time.now.to_i + @suppress_emit_error_log_interval
135
+ # $log.debug "next emit failure log suppressed"
136
+ # $log.debug "next logged time is #{Time.at(@next_emit_error_log_time)}"
137
+ end
124
138
  raise
125
139
  end
126
140
 
data/lib/fluent/event.rb CHANGED
@@ -110,29 +110,54 @@ class MultiEventStream < EventStream
110
110
  end
111
111
  end
112
112
 
113
+ if $use_msgpack_5
113
114
 
114
- class MessagePackEventStream < EventStream
115
- def initialize(data, cached_unpacker=nil)
116
- @data = data
117
- @unpacker = cached_unpacker || MessagePack::Unpacker.new
118
- end
115
+ class MessagePackEventStream < EventStream
116
+ def initialize(data, cached_unpacker=nil)
117
+ @data = data
118
+ end
119
119
 
120
- def repeatable?
121
- true
122
- end
120
+ def repeatable?
121
+ true
122
+ end
123
123
 
124
- def each(&block)
125
- @unpacker.reset
126
- # TODO format check
127
- @unpacker.feed_each(@data, &block)
128
- nil
124
+ def each(&block)
125
+ # TODO format check
126
+ unpacker = MessagePack::Unpacker.new
127
+ unpacker.feed_each(@data, &block)
128
+ nil
129
+ end
130
+
131
+ def to_msgpack_stream
132
+ @data
133
+ end
129
134
  end
130
135
 
131
- def to_msgpack_stream
132
- @data
136
+ else # for 0.4.x. Will be removed after 0.5.x is stable
137
+
138
+ class MessagePackEventStream < EventStream
139
+ def initialize(data, cached_unpacker=nil)
140
+ @data = data
141
+ @unpacker = cached_unpacker || MessagePack::Unpacker.new
142
+ end
143
+
144
+ def repeatable?
145
+ true
146
+ end
147
+
148
+ def each(&block)
149
+ @unpacker.reset
150
+ # TODO format check
151
+ @unpacker.feed_each(@data, &block)
152
+ nil
153
+ end
154
+
155
+ def to_msgpack_stream
156
+ @data
157
+ end
133
158
  end
134
- end
135
159
 
160
+ end
136
161
 
137
162
  #class IoEventStream < EventStream
138
163
  # def initialize(io, num)
data/lib/fluent/load.rb CHANGED
@@ -9,8 +9,10 @@ require 'json'
9
9
  require 'yajl'
10
10
  require 'uri'
11
11
  require 'msgpack'
12
+ # I hate global variable but we suffer pain now for the sake of future.
13
+ # We will switch to MessagePack 0.5 and deprecate 0.4.
14
+ $use_msgpack_5 = defined?(MessagePack::Packer) ? true : false
12
15
  require 'cool.io'
13
- require 'cool.io/eventmachine'
14
16
  require 'fluent/env'
15
17
  require 'fluent/version'
16
18
  require 'fluent/log'
data/lib/fluent/log.rb CHANGED
@@ -241,11 +241,11 @@ class Log
241
241
  def event(level, args)
242
242
  time = Time.now
243
243
  message = ''
244
- record = {'message'=>message}
244
+ map = {}
245
245
  args.each {|a|
246
246
  if a.is_a?(Hash)
247
247
  a.each_pair {|k,v|
248
- record[k.to_s] = v
248
+ map[k.to_s] = v
249
249
  }
250
250
  else
251
251
  message << a.to_s
@@ -255,14 +255,22 @@ class Log
255
255
  if @self_event
256
256
  c = caller
257
257
  if c.count(c.shift) <= 0
258
- Engine.emit("#{@tag}.#{level}", time.to_i, record)
258
+ record = map.dup
259
+ record['message'] = message.dup
260
+ ### In signal trap context, 'Engine.emit' cannot get Monitor lock (Thread level lock),
261
+ ### and ThreadError will be raised
262
+ begin
263
+ Engine.emit("#{@tag}.#{level}", time.to_i, record)
264
+ rescue ThreadError # message: can't be called from trap context
265
+ # ignore
266
+ end
267
+ # TODO: We should check 'GET_THREAD()->interrupt_mask & TRAP_INTERRUPT_MASK'
268
+ # for replacement of begin-rescue if any methods exists.
259
269
  end
260
270
  end
261
271
 
262
- record.each_pair {|k,v|
263
- if v.object_id != message.object_id
264
- message << " #{k}=#{v.inspect}"
265
- end
272
+ map.each_pair {|k,v|
273
+ message << " #{k}=#{v.inspect}"
266
274
  }
267
275
 
268
276
  return time, message
data/lib/fluent/mixin.rb CHANGED
@@ -93,8 +93,9 @@ module RecordFilterMixin
93
93
  def format_stream(tag, es)
94
94
  out = ''
95
95
  es.each {|time,record|
96
- filter_record(tag, time, record)
97
- out << format(tag, time, record)
96
+ tag_temp = tag.dup
97
+ filter_record(tag_temp, time, record)
98
+ out << format(tag_temp, time, record)
98
99
  }
99
100
  out
100
101
  end
data/lib/fluent/output.rb CHANGED
@@ -324,20 +324,20 @@ class BufferedOutput < Output
324
324
  end
325
325
 
326
326
  if error_count < @retry_limit
327
- $log.warn "temporarily failed to flush the buffer, next retry will be at #{Time.at(@next_retry_time)}.", :error=>e.to_s, :instance=>object_id
327
+ $log.warn "temporarily failed to flush the buffer.", :next_retry=>Time.at(@next_retry_time), :error_class=>e.class.to_s, :error=>e.to_s, :instance=>object_id
328
328
  $log.warn_backtrace e.backtrace
329
329
 
330
330
  elsif @secondary
331
331
  if error_count == @retry_limit
332
- $log.warn "failed to flush the buffer.", :error=>e.to_s, :instance=>object_id
332
+ $log.warn "failed to flush the buffer.", :error_class=>e.class.to_s, :error=>e.to_s, :instance=>object_id
333
333
  $log.warn "retry count exceededs limit. falling back to secondary output."
334
334
  $log.warn_backtrace e.backtrace
335
335
  retry # retry immediately
336
336
  elsif error_count <= @retry_limit + @secondary_limit
337
- $log.warn "failed to flush the buffer, next retry will be with secondary output at #{Time.at(@next_retry_time)}.", :error=>e.to_s, :instance=>object_id
337
+ $log.warn "failed to flush the buffer, next retry will be with secondary output.", :next_retry=>Time.at(@next_retry_time), :error_class=>e.class.to_s, :error=>e.to_s, :instance=>object_id
338
338
  $log.warn_backtrace e.backtrace
339
339
  else
340
- $log.warn "failed to flush the buffer.", :error=>e.to_s, :instance=>object_id
340
+ $log.warn "failed to flush the buffer.", :error_class=>e.class, :error=>e.to_s, :instance=>object_id
341
341
  $log.warn "secondary retry count exceededs limit."
342
342
  $log.warn_backtrace e.backtrace
343
343
  write_abort
@@ -345,7 +345,7 @@ class BufferedOutput < Output
345
345
  end
346
346
 
347
347
  else
348
- $log.warn "failed to flush the buffer.", :error=>e.to_s, :instance=>object_id
348
+ $log.warn "failed to flush the buffer.", :error_class=>e.class.to_s, :error=>e.to_s, :instance=>object_id
349
349
  $log.warn "retry count exceededs limit."
350
350
  $log.warn_backtrace e.backtrace
351
351
  write_abort
data/lib/fluent/parser.rb CHANGED
@@ -106,7 +106,7 @@ class TextParser
106
106
  end
107
107
 
108
108
  if @time_format && !@time_key
109
- $log.warn "time_format parameter is ignored because time_key parameter is not set"
109
+ raise ConfigError, "time_format parameter is ignored because time_key parameter is not set. at #{conf.inspect}"
110
110
  end
111
111
  end
112
112
 
@@ -114,7 +114,7 @@ class TextParser
114
114
  record = Hash[keys.zip(values)]
115
115
 
116
116
  if @time_key
117
- value = record[@time_key]
117
+ value = record.delete(@time_key)
118
118
  if @time_format
119
119
  time = Time.strptime(value, @time_format).to_i
120
120
  else
@@ -139,9 +139,10 @@ class TextParser
139
139
  class LabeledTSVParser < ValuesParser
140
140
  config_param :delimiter, :string, :default => "\t"
141
141
  config_param :label_delimiter, :string, :default => ":"
142
+ config_param :time_key, :string, :default => "time"
142
143
 
143
144
  def configure(conf)
144
- conf['keys'] = conf['time_key'] || ''
145
+ conf['keys'] = conf['time_key'] || 'time'
145
146
  super(conf)
146
147
  end
147
148
 
@@ -46,7 +46,7 @@ class ForwardInput < Input
46
46
  @loop.attach(@hbr)
47
47
 
48
48
  @thread = Thread.new(&method(:run))
49
- @cached_unpacker = MessagePack::Unpacker.new
49
+ @cached_unpacker = $use_msgpack_5 ? nil : MessagePack::Unpacker.new
50
50
  end
51
51
 
52
52
  def shutdown
@@ -31,7 +31,7 @@ class StreamInput < Input
31
31
  @lsock = listen
32
32
  @loop.attach(@lsock)
33
33
  @thread = Thread.new(&method(:run))
34
- @cached_unpacker = MessagePack::Unpacker.new
34
+ @cached_unpacker = $use_msgpack_5 ? nil : MessagePack::Unpacker.new
35
35
  end
36
36
 
37
37
  def shutdown
@@ -271,7 +271,7 @@ class TailInput < Input
271
271
  @wait = wait
272
272
  end
273
273
 
274
- attr_reader :io
274
+ attr_reader :io, :wait
275
275
 
276
276
  def tick
277
277
  @wait -= 1
@@ -71,6 +71,9 @@ class ExecFilterOutput < BufferedOutput
71
71
  # nil, 'none' or 0: no respawn, 'inf' or -1: infinite times, positive integer: try to respawn specified times only
72
72
  config_param :child_respawn, :string, :default => nil
73
73
 
74
+ # 0: output logs for all of messages to emit
75
+ config_param :suppress_error_log_interval, :time, :default => 0
76
+
74
77
  config_set_default :flush_interval, 1
75
78
 
76
79
  def configure(conf)
@@ -166,6 +169,9 @@ class ExecFilterOutput < BufferedOutput
166
169
  else
167
170
  raise ConfigError, "child_respawn option argument invalid: none(or 0), inf(or -1) or positive number"
168
171
  end
172
+
173
+ @suppress_error_log_interval ||= 0
174
+ @next_log_time = Time.now.to_i
169
175
  end
170
176
 
171
177
  def start
@@ -187,6 +193,10 @@ class ExecFilterOutput < BufferedOutput
187
193
 
188
194
  def before_shutdown
189
195
  super
196
+ $log.debug "out_exec_filter#before_shutdown called"
197
+ @children.each {|c|
198
+ c.finished = true
199
+ }
190
200
  sleep 0.5 # TODO wait time before killing child process
191
201
  end
192
202
 
@@ -227,12 +237,15 @@ class ExecFilterOutput < BufferedOutput
227
237
  end
228
238
 
229
239
  class ChildProcess
240
+ attr_accessor :finished
241
+
230
242
  def initialize(parser,respawns=0)
231
243
  @pid = nil
232
244
  @thread = nil
233
245
  @parser = parser
234
246
  @respawns = respawns
235
247
  @mutex = Mutex.new
248
+ @finished = nil
236
249
  end
237
250
 
238
251
  def start(command)
@@ -372,8 +385,11 @@ class ExecFilterOutput < BufferedOutput
372
385
  Engine.emit(tag, time, record)
373
386
 
374
387
  rescue
375
- $log.error "exec_filter failed to emit", :error=>$!.to_s, :record=>Yajl.dump(record)
376
- $log.warn_backtrace $!.backtrace
388
+ if @suppress_error_log_interval == 0 || Time.now.to_i > @next_log_time
389
+ $log.error "exec_filter failed to emit", :error=>$!.to_s, :error_class=>$!.class.to_s, :record=>Yajl.dump(record)
390
+ $log.warn_backtrace $!.backtrace
391
+ @next_log_time = Time.now.to_i + @suppress_error_log_interval
392
+ end
377
393
  end
378
394
 
379
395
  class Parser
@@ -128,7 +128,9 @@ class ForwardOutput < ObjectBufferedOutput
128
128
  $log.error_backtrace
129
129
  end
130
130
 
131
- def write_objects(tag, es)
131
+ def write_objects(tag, chunk)
132
+ return if chunk.empty?
133
+
132
134
  error = nil
133
135
 
134
136
  wlen = @weight_array.length
@@ -138,7 +140,7 @@ class ForwardOutput < ObjectBufferedOutput
138
140
 
139
141
  if node.available?
140
142
  begin
141
- send_data(node, tag, es)
143
+ send_data(node, tag, chunk)
142
144
  return
143
145
  rescue
144
146
  # for load balancing during detecting crashed servers
@@ -217,7 +219,7 @@ class ForwardOutput < ObjectBufferedOutput
217
219
  end
218
220
  end
219
221
 
220
- def send_data(node, tag, es)
222
+ def send_data(node, tag, chunk)
221
223
  sock = connect(node)
222
224
  begin
223
225
  opt = [1, @send_timeout.to_i].pack('I!I!') # { int l_onoff; int l_linger; }
@@ -233,7 +235,7 @@ class ForwardOutput < ObjectBufferedOutput
233
235
  sock.write tag.to_msgpack # tag
234
236
 
235
237
  # beginRaw(size)
236
- sz = es.size
238
+ sz = chunk.size
237
239
  #if sz < 32
238
240
  # # FixRaw
239
241
  # sock.write [0xa0 | sz].pack('C')
@@ -246,7 +248,7 @@ class ForwardOutput < ObjectBufferedOutput
246
248
  #end
247
249
 
248
250
  # writeRawBody(packed_es)
249
- es.write_to(sock)
251
+ chunk.write_to(sock)
250
252
 
251
253
  node.heartbeat(false)
252
254
  ensure
@@ -180,7 +180,7 @@ class DetachProcessManager
180
180
 
181
181
  def read_event_stream(r, &block)
182
182
  u = MessagePack::Unpacker.new(r)
183
- cached_unpacker = MessagePack::Unpacker.new
183
+ cached_unpacker = $use_msgpack_5 ? nil : MessagePack::Unpacker.new
184
184
  begin
185
185
  #buf = ''
186
186
  #map = {}
@@ -67,6 +67,7 @@ class Supervisor
67
67
  @libs = opt[:libs]
68
68
  @plugin_dirs = opt[:plugin_dirs]
69
69
  @inline_config = opt[:inline_config]
70
+ @suppress_interval = opt[:suppress_interval]
70
71
 
71
72
  @log = LoggerInitializer.new(@log_path, @log_level, @chuser, @chgroup)
72
73
  @finished = false
@@ -90,6 +91,7 @@ class Supervisor
90
91
  run_engine
91
92
  exit 0
92
93
  end
94
+ $log.error "fluentd main process died unexpectedly. restarting." unless @finished
93
95
  end
94
96
  end
95
97
 
@@ -203,30 +205,50 @@ class Supervisor
203
205
 
204
206
  def install_supervisor_signal_handlers
205
207
  trap :INT do
208
+ $log.debug "fluentd supervisor process get SIGINT"
206
209
  @finished = true
207
210
  if pid = @main_pid
208
- Process.kill(:INT, pid)
211
+ # kill processes only still exists
212
+ unless Process.waitpid(pid, Process::WNOHANG)
213
+ begin
214
+ Process.kill(:INT, pid)
215
+ rescue Errno::ESRCH
216
+ # ignore processes already died
217
+ end
218
+ end
209
219
  end
210
220
  end
211
221
 
212
222
  trap :TERM do
223
+ $log.debug "fluentd supervisor process get SIGTERM"
213
224
  @finished = true
214
225
  if pid = @main_pid
215
- Process.kill(:TERM, pid)
226
+ # kill processes only still exists
227
+ unless Process.waitpid(pid, Process::WNOHANG)
228
+ begin
229
+ Process.kill(:TERM, pid)
230
+ rescue Errno::ESRCH
231
+ # ignore processes already died
232
+ end
233
+ end
216
234
  end
217
235
  end
218
236
 
219
237
  trap :HUP do
238
+ $log.debug "fluentd supervisor process get SIGHUP"
220
239
  $log.info "restarting"
221
240
  if pid = @main_pid
222
241
  Process.kill(:TERM, pid)
242
+ # don't resuce Erro::ESRSH here (invalid status)
223
243
  end
224
244
  end
225
245
 
226
246
  trap :USR1 do
247
+ $log.debug "fluentd supervisor process get SIGUSR1"
227
248
  @log.reopen!
228
249
  if pid = @main_pid
229
250
  Process.kill(:USR1, pid)
251
+ # don't resuce Erro::ESRSH here (invalid status)
230
252
  end
231
253
  end
232
254
  end
@@ -281,6 +303,9 @@ class Supervisor
281
303
  def init_engine
282
304
  require 'fluent/load'
283
305
  Fluent::Engine.init
306
+ if @suppress_interval
307
+ Fluent::Engine.suppress_interval(@suppress_interval)
308
+ end
284
309
 
285
310
  @libs.each {|lib|
286
311
  require lib
@@ -295,19 +320,34 @@ class Supervisor
295
320
  end
296
321
 
297
322
  def install_main_process_signal_handlers
323
+ # Strictly speaking, these signal handling is not thread safe.
324
+ # But enough safe to limit twice call of Fluent::Engine.stop.
325
+
298
326
  trap :INT do
299
- Fluent::Engine.stop
327
+ $log.debug "fluentd main process get SIGINT"
328
+ unless @finished
329
+ @finished = true
330
+ $log.debug "getting start to shutdown main process"
331
+ Fluent::Engine.stop
332
+ end
300
333
  end
301
334
 
302
335
  trap :TERM do
303
- Fluent::Engine.stop
336
+ $log.debug "fluentd main process get SIGTERM"
337
+ unless @finished
338
+ @finished = true
339
+ $log.debug "getting start to shutdown main process"
340
+ Fluent::Engine.stop
341
+ end
304
342
  end
305
343
 
306
344
  trap :HUP do
307
345
  # TODO
346
+ $log.debug "fluentd main process get SIGHUP"
308
347
  end
309
348
 
310
349
  trap :USR1 do
350
+ $log.debug "fluentd main process get SIGUSR1"
311
351
  $log.info "force flushing buffered events"
312
352
  @log.reopen!
313
353
  Fluent::Engine.flush!
@@ -38,7 +38,7 @@ class TestDriver
38
38
  attr_reader :instance, :config
39
39
 
40
40
  def configure(str)
41
- if str.is_a?(Config)
41
+ if str.is_a?(Fluent::Config::Element)
42
42
  @config = str
43
43
  else
44
44
  @config = Config.parse(str, "(test)")
@@ -1,5 +1,5 @@
1
1
  module Fluent
2
2
 
3
- VERSION = '0.10.33'
3
+ VERSION = '0.10.34'
4
4
 
5
5
  end
data/test/helper.rb CHANGED
@@ -3,6 +3,11 @@ require 'fileutils'
3
3
  require 'fluent/log'
4
4
  require 'rr'
5
5
 
6
+ unless defined?(Test::Unit::AssertionFailedError)
7
+ class Test::Unit::AssertionFailedError < StandardError
8
+ end
9
+ end
10
+
6
11
  class Test::Unit::TestCase
7
12
  include RR::Adapters::TestUnit
8
13
  end
data/test/mixin.rb CHANGED
@@ -35,7 +35,7 @@ module MixinTest
35
35
  mock(Checker).format_check(tagname, @time.to_i, hash)
36
36
  end
37
37
 
38
- def create_driver(include_klass, conf = '')
38
+ def create_driver(include_klass, conf = '', tag = "test")
39
39
  register_output_name = create_register_output_name
40
40
  include_klasses = [include_klass].flatten
41
41
 
@@ -51,7 +51,7 @@ module MixinTest
51
51
  def write(chunk); end
52
52
  }
53
53
 
54
- Fluent::Test::BufferedOutputTestDriver.new(klass) {
54
+ Fluent::Test::BufferedOutputTestDriver.new(klass, tag) {
55
55
  }.configure("type #{register_output_name}" + conf)
56
56
  end
57
57
  end
@@ -164,6 +164,9 @@ module MixinTest
164
164
  format_check({
165
165
  'a' => 1
166
166
  }, 'tag_prefix.test')
167
+ format_check({
168
+ 'a' => 2
169
+ }, 'tag_prefix.test')
167
170
 
168
171
  d = create_driver(Fluent::HandleTagNameMixin, %[
169
172
  add_tag_prefix tag_prefix.
@@ -171,6 +174,7 @@ module MixinTest
171
174
  ])
172
175
 
173
176
  d.emit({'a' => 1})
177
+ d.emit({'a' => 2})
174
178
  d.run
175
179
  end
176
180
 
@@ -178,6 +182,9 @@ module MixinTest
178
182
  format_check({
179
183
  'a' => 1
180
184
  }, 'test.test_suffix')
185
+ format_check({
186
+ 'a' => 2
187
+ }, 'test.test_suffix')
181
188
 
182
189
  d = create_driver(Fluent::HandleTagNameMixin, %[
183
190
  add_tag_suffix .test_suffix
@@ -185,34 +192,43 @@ module MixinTest
185
192
  ])
186
193
 
187
194
  d.emit({'a' => 1})
195
+ d.emit({'a' => 2})
188
196
  d.run
189
197
  end
190
198
 
191
199
  def test_remove_tag_prefix
192
200
  format_check({
193
201
  'a' => 1
194
- }, 'st')
202
+ }, 'test')
203
+ format_check({
204
+ 'a' => 2
205
+ }, 'test')
195
206
 
196
207
  d = create_driver(Fluent::HandleTagNameMixin, %[
197
208
  remove_tag_prefix te
198
209
  include_tag_key true
199
- ])
210
+ ], "tetest")
200
211
 
201
212
  d.emit({'a' => 1})
213
+ d.emit({'a' => 2})
202
214
  d.run
203
215
  end
204
216
 
205
217
  def test_remove_tag_suffix
206
218
  format_check({
207
219
  'a' => 1
208
- }, 'te')
220
+ }, 'test')
221
+ format_check({
222
+ 'a' => 2
223
+ }, 'test')
209
224
 
210
225
  d = create_driver(Fluent::HandleTagNameMixin, %[
211
226
  remove_tag_suffix st
212
227
  include_tag_key true
213
- ])
228
+ ], "testst")
214
229
 
215
230
  d.emit({'a' => 1})
231
+ d.emit({'a' => 2})
216
232
  d.run
217
233
  end
218
234
 
data/test/parser.rb CHANGED
@@ -151,12 +151,12 @@ module ParserTest
151
151
 
152
152
  def test_call
153
153
  parser = TextParser::LabeledTSVParser.new
154
- time, record = parser.call("time:[28/Feb/2013:12:00:00 +0900]\thost:192.168.0.1\treq:GET /list HTTP/1.1")
154
+ time, record = parser.call("time:2013/02/28 12:00:00\thost:192.168.0.1\treq_id:111")
155
155
 
156
+ assert_equal(str2time('2013/02/28 12:00:00', '%Y/%m/%d %H:%M:%S'), time)
156
157
  assert_equal({
157
- 'time' => '[28/Feb/2013:12:00:00 +0900]',
158
- 'host' => '192.168.0.1',
159
- 'req' => 'GET /list HTTP/1.1',
158
+ 'host' => '192.168.0.1',
159
+ 'req_id' => '111',
160
160
  }, record)
161
161
  end
162
162
 
@@ -166,27 +166,27 @@ module ParserTest
166
166
  'delimiter' => ',',
167
167
  'label_delimiter' => '=',
168
168
  )
169
- time, record = parser.call('time=[28/Feb/2013:12:00:00 +0900],host=192.168.0.1,req=GET /list HTTP/1.1')
169
+ time, record = parser.call('time=2013/02/28 12:00:00,host=192.168.0.1,req_id=111')
170
170
 
171
+ assert_equal(str2time('2013/02/28 12:00:00', '%Y/%m/%d %H:%M:%S'), time)
171
172
  assert_equal({
172
- 'time' => '[28/Feb/2013:12:00:00 +0900]',
173
- 'host' => '192.168.0.1',
174
- 'req' => 'GET /list HTTP/1.1',
173
+ 'host' => '192.168.0.1',
174
+ 'req_id' => '111',
175
175
  }, record)
176
176
  end
177
177
 
178
178
  def test_call_with_customized_time_format
179
179
  parser = TextParser::LabeledTSVParser.new
180
180
  parser.configure(
181
- 'time_key' => 'time',
182
- 'time_format' => '[%d/%b/%Y:%H:%M:%S %z]',
181
+ 'time_key' => 'mytime',
182
+ 'time_format' => '%d/%b/%Y:%H:%M:%S %z',
183
183
  )
184
- time, record = parser.call("time:[28/Feb/2013:12:00:00 +0900]\thost:192.168.0.1\treq:GET /list HTTP/1.1")
184
+ time, record = parser.call("mytime:28/Feb/2013:12:00:00 +0900\thost:192.168.0.1\treq_id:111")
185
185
 
186
+ assert_equal(str2time('28/Feb/2013:12:00:00 +0900', '%d/%b/%Y:%H:%M:%S %z'), time)
186
187
  assert_equal({
187
- 'time' => '[28/Feb/2013:12:00:00 +0900]',
188
- 'host' => '192.168.0.1',
189
- 'req' => 'GET /list HTTP/1.1',
188
+ 'host' => '192.168.0.1',
189
+ 'req_id' => '111',
190
190
  }, record)
191
191
  end
192
192
  end
@@ -51,5 +51,42 @@ class CopyOutputTest < Test::Unit::TestCase
51
51
  ], o.events
52
52
  }
53
53
  end
54
+
55
+ def test_msgpack_es_emit_bug
56
+ d = Fluent::Test::OutputTestDriver.new(Fluent::CopyOutput)
57
+
58
+ outputs = %w(p1 p2).map do |pname|
59
+ p = Fluent::Plugin.new_output('test')
60
+ p.configure('name' => pname)
61
+ p.define_singleton_method(:emit) do |tag, es, chain|
62
+ es.each do |time, record|
63
+ super(tag, [[time, record]], chain)
64
+ end
65
+ end
66
+ p
67
+ end
68
+
69
+ d.instance.instance_eval { @outputs = outputs }
70
+
71
+ es = if defined?(MessagePack::Packer)
72
+ time = Time.parse("2013-05-26 06:37:22 UTC").to_i
73
+ packer = MessagePack::Packer.new
74
+ packer.pack([time, {"a" => 1}])
75
+ packer.pack([time, {"a" => 2}])
76
+ Fluent::MessagePackEventStream.new(packer.to_s)
77
+ else
78
+ events = "#{[time, {"a" => 1}].to_msgpack}#{[time, {"a" => 2}].to_msgpack}"
79
+ Fluent::MessagePackEventStream.new(events)
80
+ end
81
+
82
+ d.instance.emit('test', es, Fluent::NullOutputChain.instance)
83
+
84
+ d.instance.outputs.each { |o|
85
+ assert_equal [
86
+ [time, {"a"=>1}],
87
+ [time, {"a"=>2}],
88
+ ], o.events
89
+ }
90
+ end
54
91
  end
55
92
 
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.33
4
+ version: 0.10.34
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-28 00:00:00.000000000 Z
12
+ date: 2013-06-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: msgpack