fluentd 0.10.52 → 0.10.53

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: 6871e2cbaea0e7068a4671988446b2cbbf8d5efb
4
- data.tar.gz: 7ec21b7f21fa8787b7a577894849df0ea5acf22b
3
+ metadata.gz: b76b903de67ead21383835723d9b289f437de46e
4
+ data.tar.gz: b1b787a0cc37983a878136b9731d5ad83eea40cc
5
5
  SHA512:
6
- metadata.gz: 924081ce1193ab72e08f05bc9ab758716d2aea3d988b1c2f735781eda2432acc78c5fea0bf40032aedc54f72067a5a39784e23cb9fa3a15ac4064792aff45dc7
7
- data.tar.gz: 726dbda087652aa3c88f17f3a7f6dcd34d4dc7dab5a576efbf08883f10256f3e2ee3fa0bae375a69a3f769fd47deb36f22bb256f6defbd607f1bd6596649dc1c
6
+ metadata.gz: 05b4ab5c735e1d6d01c059dde695faa7513180f1520b56f7078eedf9b1491fb00b9fd29aaec0f87f28784750a5c5aa210c5aaff2f5c9fe7740fad857c92b30ee
7
+ data.tar.gz: 075c930dd72a40427330313e11bf4e3fe5d4399ea91a44df072cbe6fb2605b584549b9075ae55234a999fd737ff805b24f0285969574cca485f360a9b9b6ffa8
data/AUTHORS CHANGED
@@ -1 +1,2 @@
1
1
  FURUHASHI Sadayuki <frsyuki _at_ gmail.com>
2
+ NAKAGAWA Masahiro <repeatedly _at_ gmail.com>
data/ChangeLog CHANGED
@@ -1,3 +1,17 @@
1
+ Release 0.10.53 - 2014/08/21
2
+
3
+ * in_tail: Fix forget to detach Closer timer object
4
+ * in_debug_agent: Fix config_param type of unix_path
5
+ * in_syslog: Add include_source_host and source_host_Key options
6
+ * config: Dump V1 escaped parameter correctly at start phase
7
+ * config: Fix bug for config_param of bool value without defaults
8
+ * config: Add 'alias' option to config_section and config_param
9
+ * buffer: Add 'disable_retry_limit' option
10
+ * engine: Reduce memory usage when retry_limit is large
11
+ * parser: Add apache_error format
12
+ * supervisor: Dump Fluentd version at dry run mode
13
+ * test: InputTestDriver wait 'run' until input plugin emits all test data
14
+
1
15
  Release 0.10.52 - 2014/07/15
2
16
 
3
17
  * in_tail: Fix typo of warning argument. lb to line
data/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  Fluentd: Open-Source Data Collector
2
2
  ===================================
3
3
 
4
- [<img src="https://travis-ci.org/fluent/fluentd.png" />](https://travis-ci.org/fluent/fluentd) [<img src="https://codeclimate.com/github/fluent/fluentd.png " />](https://codeclimate.com/github/fluent/fluentd)
4
+ [<img src="https://travis-ci.org/fluent/fluentd.svg" />](https://travis-ci.org/fluent/fluentd) [![Code Climate](https://codeclimate.com/github/fluent/fluentd/badges/gpa.svg)](https://codeclimate.com/github/fluent/fluentd)
5
5
 
6
6
 
7
- [Fluentd](http://fluentd.org/) collects events from various data sources and writes them to files, database or other types of storages. You can simplify your data stream, and have robust data collection mechanism instantly:
7
+ [Fluentd](http://fluentd.org/) collects events from various data sources and writes them to files, RDBMS, NoSQL, IaaS, SaaS, Hadoop and so on. Fluentd helps you unify your logging infrastructure (Learn more about the [Unified Logging Layer](http://www.fluentd.org/blog/unified-logging-layer)).
8
8
 
9
9
  <p align="center">
10
10
  <img src="http://docs.fluentd.org/images/fluentd-architecture.png" width="500px"/>
@@ -20,6 +20,10 @@ An event consists of *tag*, *time* and *record*. Tag is a string separated with
20
20
  $ fluentd -c conf/fluent.conf &
21
21
  $ echo '{"json":"message"}' | fluent-cat debug.test
22
22
 
23
+ ## Fluentd UI: Admin GUI
24
+
25
+ [Fluentd UI](https://github.com/fluent/fluentd-ui) is a graphical user interface to start/stop/configure Fluentd.
26
+
23
27
  ## More Information
24
28
 
25
29
  - Website: http://fluentd.org/
@@ -1,7 +1,7 @@
1
1
  module Fluent
2
2
  module Config
3
3
  class ConfigureProxy
4
- attr_accessor :name, :param_name, :required, :multi, :argument, :params, :defaults, :sections
4
+ attr_accessor :name, :param_name, :required, :multi, :alias, :argument, :params, :defaults, :sections
5
5
  # config_param :desc, :string, :default => '....'
6
6
  # config_set_default :buffer_type, :memory
7
7
  #
@@ -12,7 +12,7 @@ module Fluent
12
12
  # config_param :power, :integer
13
13
  # end
14
14
  #
15
- # config_section :child, param_name: 'children', required: false, multi: true do
15
+ # config_section :child, param_name: 'children', required: false, multi: true, alias: 'node' do
16
16
  # config_param :name, :string
17
17
  # config_param :power, :integer, default: nil
18
18
  # config_section :item do
@@ -26,6 +26,7 @@ module Fluent
26
26
  @param_name = (opts[:param_name] || @name).to_sym
27
27
  @required = opts[:required]
28
28
  @multi = opts[:multi]
29
+ @alias = opts[:alias]
29
30
 
30
31
  @argument = nil # nil: ignore argument
31
32
  @params = {}
@@ -12,12 +12,14 @@ module Fluent
12
12
  self[k] = v
13
13
  }
14
14
  @unused = unused || attrs.keys
15
+ @v1_config = false
15
16
  end
16
17
 
17
- attr_accessor :name, :arg, :elements, :unused
18
+ attr_accessor :name, :arg, :elements, :unused, :v1_config
18
19
 
19
20
  def add_element(name, arg='')
20
21
  e = Element.new(name, arg, {}, [])
22
+ e.v1_config = @v1_config
21
23
  @elements << e
22
24
  e
23
25
  end
@@ -36,7 +38,9 @@ module Fluent
36
38
  end
37
39
 
38
40
  def +(o)
39
- Element.new(@name.dup, @arg.dup, o.merge(self), @elements + o.elements, (@unused + o.unused).uniq)
41
+ e = Element.new(@name.dup, @arg.dup, o.merge(self), @elements + o.elements, (@unused + o.unused).uniq)
42
+ e.v1_config = @v1_config
43
+ e
40
44
  end
41
45
 
42
46
  def each_element(*names, &block)
@@ -82,7 +86,11 @@ module Fluent
82
86
  out << "#{indent}<#{@name} #{@arg}>\n"
83
87
  end
84
88
  each_pair { |k, v|
85
- out << "#{nindent}#{k} #{v}\n"
89
+ if @v1_config
90
+ out << "#{nindent}#{k} #{Element.unescape_parameter(v)}\n"
91
+ else
92
+ out << "#{nindent}#{k} #{v}\n"
93
+ end
86
94
  }
87
95
  @elements.each { |e|
88
96
  out << e.to_s(nest + 1)
@@ -90,6 +98,12 @@ module Fluent
90
98
  out << "#{indent}</#{@name}>\n"
91
99
  out
92
100
  end
101
+
102
+ def self.unescape_parameter(v)
103
+ result = ''
104
+ v.each_char { |c| result << LiteralParser.unescape_char(c) }
105
+ result
106
+ end
93
107
  end
94
108
  end
95
109
  end
@@ -21,6 +21,29 @@ module Fluent
21
21
  require 'irb/ruby-lex' # RubyLex
22
22
 
23
23
  class LiteralParser < BasicParser
24
+ def self.unescape_char(c)
25
+ case c
26
+ when '"'
27
+ '\"'
28
+ when "'"
29
+ "\\'"
30
+ when '\\'
31
+ '\\\\'
32
+ when "\r"
33
+ '\r'
34
+ when "\n"
35
+ '\n'
36
+ when "\t"
37
+ '\t'
38
+ when "\f"
39
+ '\f'
40
+ when "\b"
41
+ '\b'
42
+ else
43
+ c
44
+ end
45
+ end
46
+
24
47
  def initialize(strscan, eval_context)
25
48
  super(strscan)
26
49
  @eval_context = eval_context
@@ -86,7 +86,12 @@ module Fluent
86
86
  proxy.params.each_pair do |name, defval|
87
87
  varname = name.to_sym
88
88
  block, opts = defval
89
- if val = conf[name.to_s]
89
+ if conf.has_key?(name.to_s) || opts[:alias] && conf.has_key?(opts[:alias].to_s)
90
+ val = if conf.has_key?(name.to_s)
91
+ conf[name.to_s]
92
+ else
93
+ conf[opts[:alias].to_s]
94
+ end
90
95
  section_params[varname] = self.instance_exec(val, opts, name, &block)
91
96
  end
92
97
  unless section_params.has_key?(varname)
@@ -97,7 +102,7 @@ module Fluent
97
102
 
98
103
  proxy.sections.each do |name, subproxy|
99
104
  varname = subproxy.param_name.to_sym
100
- elements = (conf.respond_to?(:elements) ? conf.elements : []).select{ |e| e.name == subproxy.name.to_s }
105
+ elements = (conf.respond_to?(:elements) ? conf.elements : []).select{ |e| e.name == subproxy.name.to_s || e.name == subproxy.alias.to_s }
101
106
 
102
107
  if subproxy.required? && elements.size < 1
103
108
  logger.error "config error in:\n#{conf}"
@@ -71,7 +71,7 @@ module Fluent
71
71
  })
72
72
 
73
73
  Configurable.register_type(:hash, Proc.new { |val, opts|
74
- param = JSON.load(val)
74
+ param = val.is_a?(String) ? JSON.load(val) : val
75
75
  if param.class != Hash
76
76
  raise ConfigError, "hash required but got #{val.inspect}"
77
77
  end
@@ -79,7 +79,7 @@ module Fluent
79
79
  })
80
80
 
81
81
  Configurable.register_type(:array, Proc.new { |val, opts|
82
- param = JSON.load(val)
82
+ param = val.is_a?(String) ? JSON.load(val) : val
83
83
  if param.class != Array
84
84
  raise ConfigError, "array required but got #{val.inspect}"
85
85
  end
@@ -39,6 +39,7 @@ module Fluent
39
39
  def parse!
40
40
  attrs, elems = parse_element(true, nil)
41
41
  root = Element.new('ROOT', '', attrs, elems)
42
+ root.v1_config = true
42
43
 
43
44
  spacing
44
45
  unless eof?
@@ -86,7 +87,9 @@ module Fluent
86
87
  e_arg ||= ''
87
88
  # call parse_element recursively
88
89
  e_attrs, e_elems = parse_element(false, e_name)
89
- elems << Element.new(e_name, e_arg, e_attrs, e_elems)
90
+ new_e = Element.new(e_name, e_arg, e_attrs, e_elems)
91
+ new_e.v1_config = true
92
+ elems << new_e
90
93
 
91
94
  elsif root_element && skip(/(\@include|include)#{SPACING}/)
92
95
  if !prev_match.start_with?('@')
@@ -23,8 +23,9 @@ module Fluent
23
23
  false
24
24
  end
25
25
 
26
- #def each(&block)
27
- #end
26
+ def each(&block)
27
+ raise NotImplementedError, "DO NOT USE THIS CLASS directly."
28
+ end
28
29
 
29
30
  def to_msgpack_stream
30
31
  out = ''
@@ -56,7 +57,10 @@ module Fluent
56
57
  end
57
58
  end
58
59
 
59
-
60
+ # EventStream from entries: Array of [time, record]
61
+ #
62
+ # Use this class for many events data with a tag
63
+ # and its representation is [ [time, record], [time, record], .. ]
60
64
  class ArrayEventStream < EventStream
61
65
  def initialize(entries)
62
66
  @entries = entries
@@ -79,15 +83,18 @@ module Fluent
79
83
  @entries.each(&block)
80
84
  nil
81
85
  end
82
-
83
- #attr_reader :entries
84
- #
85
- #def to_a
86
- # @entries
87
- #end
88
86
  end
89
87
 
90
-
88
+ # EventStream from entries: numbers of pairs of time and record.
89
+ #
90
+ # This class can handle many events more efficiently than ArrayEventStream
91
+ # because this class generate less objects than ArrayEventStream.
92
+ #
93
+ # Use this class as below, in loop of data-enumeration:
94
+ # 1. initialize blank stream:
95
+ # streams[tag] ||= MultiEventStream
96
+ # 2. add events
97
+ # stream[tag].add(time, record)
91
98
  class MultiEventStream < EventStream
92
99
  def initialize
93
100
  @time_array = []
@@ -173,25 +180,5 @@ module Fluent
173
180
  end
174
181
 
175
182
  end
176
-
177
- #class IoEventStream < EventStream
178
- # def initialize(io, num)
179
- # @io = io
180
- # @num = num
181
- # @u = MessagePack::Unpacker.new(@io)
182
- # end
183
- #
184
- # def repeatable?
185
- # false
186
- # end
187
- #
188
- # def each(&block)
189
- # return nil if @num == 0
190
- # @u.each {|obj|
191
- # block.call(obj[0], obj[1])
192
- # break if @array.size >= @num
193
- # }
194
- # end
195
- #end
196
183
  end
197
184
 
@@ -120,46 +120,33 @@ module Fluent
120
120
  def configure(conf)
121
121
  super
122
122
 
123
+ @include_time_key = false
124
+
123
125
  if s = conf['include_time_key']
124
- b = Config.bool_value(s)
125
- if s.empty?
126
- b = true
127
- elsif b == nil
128
- raise ConfigError, "Invalid boolean expression '#{s}' for include_time_key parameter"
129
- end
130
- @include_time_key = b
126
+ include_time_key = Config.bool_value(s)
127
+ raise ConfigError, "Invalid boolean expression '#{s}' for include_time_key parameter" if include_time_key.nil?
128
+
129
+ @include_time_key = include_time_key
131
130
  end
132
131
 
133
132
  if @include_time_key
134
- if time_key = conf['time_key']
135
- @time_key = time_key
136
- end
137
- unless @time_key
138
- @time_key = 'time'
139
- end
133
+ @time_key = conf['time_key'] || 'time'
134
+ @time_format = conf['time_format']
140
135
 
141
- if time_format = conf['time_format']
142
- @time_format = time_format
143
- end
144
-
145
- if localtime = conf['localtime']
136
+ if conf['localtime']
146
137
  @localtime = true
147
- elsif utc = conf['utc']
138
+ elsif conf['utc']
148
139
  @localtime = false
149
140
  end
150
141
 
151
142
  @timef = TimeFormatter.new(@time_format, @localtime)
152
-
153
- else
154
- @include_time_key = false
155
143
  end
156
144
  end
157
145
 
158
146
  def filter_record(tag, time, record)
159
147
  super
160
- if @include_time_key
161
- record[@time_key] = @timef.format(time)
162
- end
148
+
149
+ record[@time_key] = @timef.format(time) if @include_time_key
163
150
  end
164
151
  end
165
152
 
@@ -171,34 +158,22 @@ module Fluent
171
158
  def configure(conf)
172
159
  super
173
160
 
174
- if s = conf['include_tag_key']
175
- b = Config.bool_value(s)
176
- if s.empty?
177
- b = true
178
- elsif b == nil
179
- raise ConfigError, "Invalid boolean expression '#{s}' for include_tag_key parameter"
180
- end
181
- @include_tag_key = b
182
- end
161
+ @include_tag_key = false
183
162
 
184
- if @include_tag_key
185
- if tag_key = conf['tag_key']
186
- @tag_key = tag_key
187
- end
188
- unless @tag_key
189
- @tag_key = 'tag'
190
- end
163
+ if s = conf['include_tag_key']
164
+ include_tag_key = Config.bool_value(s)
165
+ raise ConfigError, "Invalid boolean expression '#{s}' for include_tag_key parameter" if include_tag_key.nil?
191
166
 
192
- else
193
- @include_tag_key = false
167
+ @include_tag_key = include_tag_key
194
168
  end
169
+
170
+ @tag_key = conf['tag_key'] || 'tag' if @include_tag_key
195
171
  end
196
172
 
197
173
  def filter_record(tag, time, record)
198
174
  super
199
- if @include_tag_key
200
- record[@tag_key] = tag
201
- end
175
+
176
+ record[@tag_key] = tag if @include_tag_key
202
177
  end
203
178
  end
204
179
  end
@@ -165,8 +165,8 @@ module Fluent
165
165
  @next_flush_time = 0
166
166
  @last_retry_time = 0
167
167
  @next_retry_time = 0
168
- @error_history = []
169
- @error_history.extend(MonitorMixin)
168
+ @num_errors = 0
169
+ @num_errors_lock = Mutex.new
170
170
  @secondary_limit = 8
171
171
  @emit_count = 0
172
172
  end
@@ -174,6 +174,7 @@ module Fluent
174
174
  config_param :buffer_type, :string, :default => 'memory'
175
175
  config_param :flush_interval, :time, :default => 60
176
176
  config_param :try_flush_interval, :float, :default => 1
177
+ config_param :disable_retry_limit, :bool, :default => false
177
178
  config_param :retry_limit, :integer, :default => 17
178
179
  config_param :retry_wait, :time, :default => 1.0
179
180
  config_param :max_retry_wait, :time, :default => nil
@@ -286,11 +287,11 @@ module Fluent
286
287
  end
287
288
 
288
289
  begin
289
- retrying = !@error_history.empty?
290
+ retrying = !@num_errors.zero?
290
291
 
291
292
  if retrying
292
- @error_history.synchronize do
293
- if retrying = !@error_history.empty? # re-check in synchronize
293
+ @num_errors_lock.synchronize do
294
+ if retrying = !@num_errors.zero? # re-check in synchronize
294
295
  if @next_retry_time >= time
295
296
  # allow retrying for only one thread
296
297
  return time + @try_flush_interval
@@ -298,13 +299,13 @@ module Fluent
298
299
  # assume next retry failes and
299
300
  # clear them if when it succeeds
300
301
  @last_retry_time = time
301
- @error_history << time
302
+ @num_errors += 1
302
303
  @next_retry_time += calc_retry_wait
303
304
  end
304
305
  end
305
306
  end
306
307
 
307
- if @secondary && @error_history.size > @retry_limit
308
+ if @secondary && !@disable_retry_limit && @num_errors > @retry_limit
308
309
  has_next = flush_secondary(@secondary)
309
310
  else
310
311
  has_next = @buffer.pop(self)
@@ -312,7 +313,7 @@ module Fluent
312
313
 
313
314
  # success
314
315
  if retrying
315
- @error_history.clear
316
+ @num_errors = 0
316
317
  # Note: don't notify to other threads to prevent
317
318
  # burst to recovered server
318
319
  $log.warn "retry succeeded.", :instance=>object_id
@@ -326,20 +327,20 @@ module Fluent
326
327
 
327
328
  rescue => e
328
329
  if retrying
329
- error_count = @error_history.size
330
+ error_count = @num_errors
330
331
  else
331
332
  # first error
332
333
  error_count = 0
333
- @error_history.synchronize do
334
- if @error_history.empty?
334
+ @num_errors_lock.synchronize do
335
+ if @num_errors.zero?
335
336
  @last_retry_time = time
336
- @error_history << time
337
+ @num_errors += 1
337
338
  @next_retry_time = time + calc_retry_wait
338
339
  end
339
340
  end
340
341
  end
341
342
 
342
- if error_count < @retry_limit
343
+ if @disable_retry_limit || error_count < @retry_limit
343
344
  $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
344
345
  $log.warn_backtrace e.backtrace
345
346
 
@@ -357,7 +358,7 @@ module Fluent
357
358
  $log.warn "secondary retry count exceededs limit."
358
359
  $log.warn_backtrace e.backtrace
359
360
  write_abort
360
- @error_history.clear
361
+ @num_errors = 0
361
362
  end
362
363
 
363
364
  else
@@ -365,7 +366,7 @@ module Fluent
365
366
  $log.warn "retry count exceededs limit."
366
367
  $log.warn_backtrace e.backtrace
367
368
  write_abort
368
- @error_history.clear
369
+ @num_errors = 0
369
370
  end
370
371
 
371
372
  return @next_retry_time
@@ -388,11 +389,11 @@ module Fluent
388
389
 
389
390
  def calc_retry_wait
390
391
  # TODO retry pattern
391
- wait = if @error_history.size <= @retry_limit
392
- @retry_wait * (2 ** (@error_history.size-1))
392
+ wait = if @disable_retry_limit || @num_errors <= @retry_limit
393
+ @retry_wait * (2 ** (@num_errors - 1))
393
394
  else
394
395
  # secondary retry
395
- @retry_wait * (2 ** (@error_history.size-2-@retry_limit))
396
+ @retry_wait * (2 ** (@num_errors - 2 - @retry_limit))
396
397
  end
397
398
  retry_wait = wait + (rand * (wait / 4.0) - (wait / 8.0))
398
399
  @max_retry_wait ? [retry_wait, @max_retry_wait].min : retry_wait
@@ -257,8 +257,6 @@ module Fluent
257
257
  config_param :time_key, :string, :default => nil
258
258
  config_param :time_format, :string, :default => nil
259
259
 
260
- # SET false BEFORE CONFIGURE, to return nil when time not parsed
261
- # 'configure()' may raise errors for unexpected configurations
262
260
  attr_accessor :estimate_current_event
263
261
 
264
262
  def initialize
@@ -624,6 +622,7 @@ module Fluent
624
622
  TEMPLATE_REGISTRY = Registry.new(:config_type, 'fluent/plugin/parser_')
625
623
  {
626
624
  'apache' => Proc.new { RegexpParser.new(/^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$/, {'time_format'=>"%d/%b/%Y:%H:%M:%S %z"}) },
625
+ 'apache_error' => Proc.new { RegexpParser.new(/^\[[^ ]* (?<time>[^\]]*)\] \[(?<level>[^\]]*)\](?: \[pid (?<pid>[^\]]*)\])?( \[client (?<client>[^\]]*)\])? (?<message>.*)$/) },
627
626
  'apache2' => Proc.new { ApacheParser.new },
628
627
  'syslog' => Proc.new { SyslogParser.new },
629
628
  'json' => Proc.new { JSONParser.new },
@@ -650,10 +649,15 @@ module Fluent
650
649
 
651
650
  def initialize
652
651
  @parser = nil
652
+ @estimate_current_event = nil
653
653
  end
654
654
 
655
655
  attr_reader :parser
656
656
 
657
+ # SET false BEFORE CONFIGURE, to return nil when time not parsed
658
+ # 'configure()' may raise errors for unexpected configurations
659
+ attr_accessor :estimate_current_event
660
+
657
661
  def configure(conf, required=true)
658
662
  format = conf['format']
659
663
 
@@ -687,6 +691,10 @@ module Fluent
687
691
  @parser = factory.call
688
692
  end
689
693
 
694
+ if ! @estimate_current_event.nil? && @parser.respond_to?(:'estimate_current_event=')
695
+ @parser.estimate_current_event = @estimate_current_event
696
+ end
697
+
690
698
  if @parser.respond_to?(:configure)
691
699
  @parser.configure(conf)
692
700
  end
@@ -26,7 +26,7 @@ module Fluent
26
26
 
27
27
  config_param :bind, :string, :default => '0.0.0.0'
28
28
  config_param :port, :integer, :default => 24230
29
- config_param :unix_path, :integer, :default => nil
29
+ config_param :unix_path, :string, :default => nil
30
30
  #config_param :unix_mode # TODO
31
31
  config_param :object, :string, :default => 'Engine'
32
32
 
@@ -217,7 +217,7 @@ module Fluent
217
217
  'output_plugin' => 'is_a?(::Fluent::Output)',
218
218
  'buffer_queue_length' => '@buffer.queue_size',
219
219
  'buffer_total_queued_size' => '@buffer.total_queued_chunk_size',
220
- 'retry_count' => '@error_history.size',
220
+ 'retry_count' => '@num_errors',
221
221
  'config' => 'config',
222
222
  }
223
223
 
@@ -78,6 +78,8 @@ module Fluent
78
78
  raise ConfigError, "syslog input protocol type should be 'tcp' or 'udp'"
79
79
  end
80
80
  end
81
+ config_param :include_source_host, :bool, :default => false
82
+ config_param :source_host_key, :string, :default => 'source_host'.freeze
81
83
 
82
84
  def configure(conf)
83
85
  super
@@ -137,6 +139,7 @@ module Fluent
137
139
  return
138
140
  end
139
141
 
142
+ record[@source_host_key] = addr[2] if @include_source_host
140
143
  emit(pri, time, record)
141
144
  }
142
145
  rescue => e
@@ -152,6 +155,7 @@ module Fluent
152
155
  end
153
156
 
154
157
  pri = record.delete('pri')
158
+ record[@source_host_key] = addr[2] if @include_source_host
155
159
  emit(pri, time, record)
156
160
  }
157
161
  rescue => e
@@ -462,6 +462,8 @@ module Fluent
462
462
  rescue => e
463
463
  @log.error e.to_s
464
464
  @log.error_backtrace(e.backtrace)
465
+ ensure
466
+ detach
465
467
  end
466
468
  end
467
469
 
@@ -151,6 +151,8 @@ module Fluent
151
151
  private
152
152
 
153
153
  def dry_run
154
+ $log.info "starting fluentd-#{Fluent::VERSION} as dry run mode"
155
+
154
156
  read_config
155
157
  change_privilege
156
158
  init_engine
@@ -158,7 +160,7 @@ module Fluent
158
160
  run_configure
159
161
  exit 0
160
162
  rescue => e
161
- $log.error "Dry run failed: #{e}"
163
+ $log.error "dry run failed: #{e}"
162
164
  exit 1
163
165
  end
164
166
 
@@ -358,6 +360,7 @@ module Fluent
358
360
  end
359
361
  end
360
362
 
363
+ # TODO: this method should be moved to SystemConfig class method
361
364
  def apply_system_config(opt)
362
365
  # Create NULL file to avoid $log uninitialized problem before call @log.init
363
366
  file = File.open(File::NULL)
@@ -29,6 +29,9 @@ module Fluent
29
29
  super(klass, &block)
30
30
  @emit_streams = []
31
31
  @expects = nil
32
+ # for checking only the number of emitted records during run
33
+ @expected_emits_length = nil
34
+ @run_timeout = 5
32
35
  end
33
36
 
34
37
  def expect_emit(tag, time, record)
@@ -40,6 +43,8 @@ module Fluent
40
43
  @expects ||= []
41
44
  end
42
45
 
46
+ attr_accessor :expected_emits_length
47
+ attr_accessor :run_timeout
43
48
  attr_reader :emit_streams
44
49
 
45
50
  def emits
@@ -78,15 +83,24 @@ module Fluent
78
83
  super {
79
84
  block.call if block
80
85
 
81
- if @expects
82
- i = 0
83
- @emit_streams.each {|tag,events|
84
- events.each {|time,record|
85
- assert_equal(@expects[i], [tag, time, record])
86
+ if @expected_emits_length || @expects
87
+ max_length = @expected_emits_length || @expects.length
88
+ started_at = Time.now
89
+ i, j = 0, 0
90
+ while i < max_length && Time.now <= started_at + @run_timeout
91
+ if j >= @emit_streams.length
92
+ sleep 0.01
93
+ next
94
+ end
95
+
96
+ tag, events = @emit_streams[j]
97
+ events.each do |time, record|
98
+ assert_equal(@expects[i], [tag, time, record]) if @expects
86
99
  i += 1
87
- }
88
- }
89
- assert_equal @expects.length, i
100
+ end
101
+ j += 1
102
+ end
103
+ assert_equal(@expects.length, i) if @expects
90
104
  end
91
105
  }
92
106
  self
@@ -1,5 +1,5 @@
1
1
  module Fluent
2
2
 
3
- VERSION = '0.10.52'
3
+ VERSION = '0.10.53'
4
4
 
5
5
  end
@@ -299,5 +299,16 @@ describe Fluent::Config::V1Parser do
299
299
 
300
300
  # TODO: Add uri based include spec
301
301
  end
302
- end
303
302
 
303
+ describe 'unescape parameter' do
304
+ it 'parses dumpped configuration' do
305
+ original = %q!a\\\\\n\r\f\b\\'\\"z!
306
+ expected = %!a\\\n\r\f\b'"z!
307
+
308
+ conf = parse_text(%[k1 #{original}])
309
+ expect(conf['k1']).to eq(expected) # escape check
310
+ conf2 = parse_text(conf.to_s) # use dumpped configuration to check unescape
311
+ expect(conf2.elements.first['k1']).to eq(expected)
312
+ end
313
+ end
314
+ end
@@ -80,6 +80,33 @@ module ConfigurableSpec
80
80
  ary + [@nodes, @description1, @description2, @description3]
81
81
  end
82
82
  end
83
+
84
+ class Example0
85
+ include Fluent::Configurable
86
+
87
+ config_param :stringvalue, :string
88
+ config_param :boolvalue, :bool
89
+ config_param :integervalue, :integer
90
+ config_param :sizevalue, :size
91
+ config_param :timevalue, :time
92
+ config_param :floatvalue, :float
93
+ config_param :hashvalue, :hash
94
+ config_param :arrayvalue, :array
95
+ end
96
+
97
+ class Example1
98
+ include Fluent::Configurable
99
+
100
+ config_param :name, :string, alias: :fullname
101
+ config_param :bool, :bool, alias: :flag
102
+ config_section :detail, required: true, multi: false, alias: "information" do
103
+ config_param :address, :string
104
+ end
105
+
106
+ def get_all
107
+ [@name, @detail]
108
+ end
109
+ end
83
110
  end
84
111
 
85
112
  describe Fluent::Configurable do
@@ -111,6 +138,11 @@ describe Fluent::Configurable do
111
138
  end
112
139
 
113
140
  describe '#configure' do
141
+ it 'returns configurable object itself' do
142
+ b2 = ConfigurableSpec::Base2.new
143
+ expect(b2.configure({"name1" => "t1", "name5" => "t5"})).to be_a(ConfigurableSpec::Base2)
144
+ end
145
+
114
146
  it 'raise errors without any specifications for param without defaults' do
115
147
  b2 = ConfigurableSpec::Base2.new
116
148
  expect{ b2.configure({}) }.to raise_error(Fluent::ConfigError)
@@ -128,7 +160,7 @@ describe Fluent::Configurable do
128
160
  expect(b2a.flag2).to eq(true)
129
161
 
130
162
  b2b = ConfigurableSpec::Base2.new
131
- expect{ b2b.configure({"flag1" => "false", "flag2" => "no", "name1" => "t1", "name5" => "t5"}) }.not_to raise_error()
163
+ expect{ b2b.configure({"flag1" => false, "flag2" => "no", "name1" => "t1", "name5" => "t5"}) }.not_to raise_error()
132
164
  expect(b2b.flag1).to eq(false)
133
165
  expect(b2b.flag2).to eq(false)
134
166
  end
@@ -368,6 +400,125 @@ describe Fluent::Configurable do
368
400
  expect(b4.description3[2].note).to eql('desc3: d-3a')
369
401
  expect(b4.description3[2].text).to eql('dddd3-3')
370
402
  end
403
+
404
+ it 'checks missing of specifications' do
405
+ conf0 = e('ROOT', '', {}, [])
406
+ ex01 = ConfigurableSpec::Example0.new
407
+ expect { ex01.configure(conf0) }.to raise_error(Fluent::ConfigError)
408
+
409
+ complete = {
410
+ "stringvalue" => "s1", "boolvalue" => "yes", "integervalue" => "10",
411
+ "sizevalue" => "10m", "timevalue" => "100s", "floatvalue" => "1.001",
412
+ "hashvalue" => '{"foo":1, "bar":2}',
413
+ "arrayvalue" => '[1,"ichi"]',
414
+ }
415
+
416
+ checker = lambda {|conf| ConfigurableSpec::Example0.new.configure(conf) }
417
+
418
+ expect { checker.call(complete) }.not_to raise_error()
419
+ expect { checker.call(complete.reject{|k,v| k == "stringvalue" }) }.to raise_error(Fluent::ConfigError)
420
+ expect { checker.call(complete.reject{|k,v| k == "boolvalue" }) }.to raise_error(Fluent::ConfigError)
421
+ expect { checker.call(complete.reject{|k,v| k == "integervalue"}) }.to raise_error(Fluent::ConfigError)
422
+ expect { checker.call(complete.reject{|k,v| k == "sizevalue" }) }.to raise_error(Fluent::ConfigError)
423
+ expect { checker.call(complete.reject{|k,v| k == "timevalue" }) }.to raise_error(Fluent::ConfigError)
424
+ expect { checker.call(complete.reject{|k,v| k == "floatvalue" }) }.to raise_error(Fluent::ConfigError)
425
+ expect { checker.call(complete.reject{|k,v| k == "hashvalue" }) }.to raise_error(Fluent::ConfigError)
426
+ expect { checker.call(complete.reject{|k,v| k == "arrayvalue" }) }.to raise_error(Fluent::ConfigError)
427
+ end
428
+
429
+ it 'accepts configuration values as string representation' do
430
+ conf = {
431
+ "stringvalue" => "s1", "boolvalue" => "yes", "integervalue" => "10",
432
+ "sizevalue" => "10m", "timevalue" => "10m", "floatvalue" => "1.001",
433
+ "hashvalue" => '{"foo":1, "bar":2}',
434
+ "arrayvalue" => '[1,"ichi"]',
435
+ }
436
+ ex = ConfigurableSpec::Example0.new.configure(conf)
437
+ expect(ex.stringvalue).to eq("s1")
438
+ expect(ex.boolvalue).to equal(true)
439
+ expect(ex.integervalue).to eq(10)
440
+ expect(ex.sizevalue).to eq(10 * 1024 * 1024)
441
+ expect(ex.timevalue).to eq(10 * 60)
442
+ expect(ex.floatvalue).to eq(1.001)
443
+ expect(ex.hashvalue).to eq({"foo" => 1, "bar" => 2})
444
+ expect(ex.arrayvalue).to eq([1, "ichi"])
445
+ end
446
+
447
+ it 'accepts configuration values as ruby value representation (especially for DSL)' do
448
+ conf = {
449
+ "stringvalue" => "s1", "boolvalue" => true, "integervalue" => 10,
450
+ "sizevalue" => 10 * 1024 * 1024, "timevalue" => 10 * 60, "floatvalue" => 1.001,
451
+ "hashvalue" => {"foo" => 1, "bar" => 2},
452
+ "arrayvalue" => [1,"ichi"],
453
+ }
454
+ ex = ConfigurableSpec::Example0.new.configure(conf)
455
+ expect(ex.stringvalue).to eq("s1")
456
+ expect(ex.boolvalue).to equal(true)
457
+ expect(ex.integervalue).to eq(10)
458
+ expect(ex.sizevalue).to eq(10 * 1024 * 1024)
459
+ expect(ex.timevalue).to eq(10 * 60)
460
+ expect(ex.floatvalue).to eq(1.001)
461
+ expect(ex.hashvalue).to eq({"foo" => 1, "bar" => 2})
462
+ expect(ex.arrayvalue).to eq([1, "ichi"])
463
+ end
464
+
465
+ it 'gets both of true(yes) and false(no) for bool value parameter' do
466
+ conf = {
467
+ "stringvalue" => "s1", "integervalue" => 10,
468
+ "sizevalue" => 10 * 1024 * 1024, "timevalue" => 10 * 60, "floatvalue" => 1.001,
469
+ "hashvalue" => {"foo" => 1, "bar" => 2},
470
+ "arrayvalue" => [1,"ichi"],
471
+ }
472
+ ex0 = ConfigurableSpec::Example0.new.configure(conf.merge({"boolvalue" => "true"}))
473
+ expect(ex0.boolvalue).to equal(true)
474
+
475
+ ex1 = ConfigurableSpec::Example0.new.configure(conf.merge({"boolvalue" => "yes"}))
476
+ expect(ex1.boolvalue).to equal(true)
477
+
478
+ ex2 = ConfigurableSpec::Example0.new.configure(conf.merge({"boolvalue" => true}))
479
+ expect(ex2.boolvalue).to equal(true)
480
+
481
+ ex3 = ConfigurableSpec::Example0.new.configure(conf.merge({"boolvalue" => "false"}))
482
+ expect(ex3.boolvalue).to equal(false)
483
+
484
+ ex4 = ConfigurableSpec::Example0.new.configure(conf.merge({"boolvalue" => "no"}))
485
+ expect(ex4.boolvalue).to equal(false)
486
+
487
+ ex5 = ConfigurableSpec::Example0.new.configure(conf.merge({"boolvalue" => false}))
488
+ expect(ex5.boolvalue).to equal(false)
489
+ end
490
+ end
491
+ end
492
+
493
+ context 'class defined with config_param/config_section having :alias' do
494
+ describe '#initialize' do
495
+ it 'does not create methods for alias' do
496
+ ex1 = ConfigurableSpec::Example1.new
497
+ expect { ex1.name }.not_to raise_error()
498
+ expect { ex1.fullname }.to raise_error(NoMethodError)
499
+ expect { ex1.bool }.not_to raise_error()
500
+ expect { ex1.flag }.to raise_error(NoMethodError)
501
+ expect { ex1.detail }.not_to raise_error()
502
+ expect { ex1.information}.to raise_error(NoMethodError)
503
+ end
504
+ end
505
+
506
+ describe '#configure' do
507
+ def e(name, arg = '', attrs = {}, elements = [])
508
+ attrs_str_keys = {}
509
+ attrs.each{|key, value| attrs_str_keys[key.to_s] = value }
510
+ Fluent::Config::Element.new(name, arg, attrs_str_keys, elements)
511
+ end
512
+
513
+ it 'provides accessible data for alias attribute keys' do
514
+ ex1 = ConfigurableSpec::Example1.new
515
+ ex1.configure(e('ROOT', '', {"fullname" => "foo bar", "bool" => false}, [e('information', '', {"address" => "Mountain View 0"})]))
516
+ expect(ex1.name).to eql("foo bar")
517
+ expect(ex1.bool).not_to be_nil
518
+ expect(ex1.bool).to be_falsy
519
+ expect(ex1.detail).not_to be_nil
520
+ expect(ex1.detail.address).to eql("Mountain View 0")
521
+ end
371
522
  end
372
523
  end
373
524
  end
@@ -0,0 +1,49 @@
1
+ require 'fluent/configurable'
2
+ require 'fluent/config/element'
3
+ require 'fluent/config/section'
4
+ require 'fluent/supervisor'
5
+
6
+ describe Fluent::Supervisor::SystemConfig do
7
+ def parse_text(text)
8
+ basepath = File.expand_path(File.dirname(__FILE__) + '/../../')
9
+ Fluent::Config.parse(text, '(test)', basepath, true).elements.find { |e| e.name == 'system' }
10
+ end
11
+
12
+ it 'should not override default configurations when no parameters' do
13
+ conf = parse_text(<<EOS)
14
+ <system>
15
+ </system>
16
+ EOS
17
+ sc = Fluent::Supervisor::SystemConfig.new(conf)
18
+ expect(sc.log_level).to be_nil
19
+ expect(sc.suppress_repeated_stacktrace).to be_nil
20
+ expect(sc.emit_error_log_interval).to be_nil
21
+ expect(sc.suppress_config_dump).to be_nil
22
+ expect(sc.without_source).to be_nil
23
+ expect(sc.to_opt).to eql({})
24
+ end
25
+
26
+ {'log_level' => 'error', 'suppress_repeated_stacktrace' => true, 'emit_error_log_interval' => 60, 'suppress_config_dump' => true, 'without_source' => true}.each { |k, v|
27
+ it "accepts #{k} parameter" do
28
+ conf = parse_text(<<EOS)
29
+ <system>
30
+ #{k} #{v}
31
+ </system>
32
+ EOS
33
+ sc = Fluent::Supervisor::SystemConfig.new(conf)
34
+ expect(sc.instance_variable_get("@#{k}")).not_to be_nil
35
+ if k == 'emit_error_log_interval'
36
+ expect(sc.to_opt).to include(:suppress_interval)
37
+ else
38
+ expect(sc.to_opt).to include(k.to_sym)
39
+ end
40
+ end
41
+ }
42
+
43
+ {'foo' => 'bar', 'hoge' => 'fuga'}.each { |k, v|
44
+ it "should not affect settable parameters with unknown #{k} parameter" do
45
+ sc = Fluent::Supervisor::SystemConfig.new({k => v})
46
+ expect(sc.to_opt).to be_empty
47
+ end
48
+ }
49
+ end
@@ -44,7 +44,6 @@ class ForwardInputTest < Test::Unit::TestCase
44
44
  d.expected_emits.each {|tag,time,record|
45
45
  send_data [tag, 0, record].to_msgpack
46
46
  }
47
- sleep 0.5
48
47
  end
49
48
  end
50
49
 
@@ -60,7 +59,6 @@ class ForwardInputTest < Test::Unit::TestCase
60
59
  d.expected_emits.each {|tag,time,record|
61
60
  send_data [tag, time, record].to_msgpack
62
61
  }
63
- sleep 0.5
64
62
  end
65
63
  end
66
64
 
@@ -78,7 +76,6 @@ class ForwardInputTest < Test::Unit::TestCase
78
76
  entries << [time, record]
79
77
  }
80
78
  send_data ["tag1", entries].to_msgpack
81
- sleep 0.5
82
79
  end
83
80
  end
84
81
 
@@ -96,7 +93,6 @@ class ForwardInputTest < Test::Unit::TestCase
96
93
  [time, record].to_msgpack(entries)
97
94
  }
98
95
  send_data ["tag1", entries].to_msgpack
99
- sleep 0.5
100
96
  end
101
97
  end
102
98
 
@@ -112,7 +108,6 @@ class ForwardInputTest < Test::Unit::TestCase
112
108
  d.expected_emits.each {|tag,time,record|
113
109
  send_data [tag, time, record].to_json
114
110
  }
115
- sleep 0.5
116
111
  end
117
112
  end
118
113
 
@@ -33,15 +33,15 @@ class ObjectSpaceInputTest < Test::Unit::TestCase
33
33
 
34
34
  time = Time.parse("2011-01-02 13:14:15").to_i
35
35
 
36
- d.run do
37
- sleep 2
38
- end
36
+ d.expected_emits_length = 2
37
+ d.run
39
38
 
40
39
  emits = d.emits
41
40
  assert_equal true, emits.length > 0
42
41
 
43
- tag, time, record = emits[0]
44
- assert_equal 2, record.size
42
+ emits.each { |tag, time, record|
43
+ assert_equal d.instance.tag, tag
44
+ assert_equal d.instance.top, record.keys.size
45
+ }
45
46
  end
46
47
  end
47
-
@@ -19,7 +19,6 @@ module StreamInputTest
19
19
  d.expected_emits.each {|tag,time,record|
20
20
  send_data [tag, 0, record].to_msgpack
21
21
  }
22
- sleep 0.5
23
22
  end
24
23
  end
25
24
 
@@ -35,7 +34,6 @@ module StreamInputTest
35
34
  d.expected_emits.each {|tag,time,record|
36
35
  send_data [tag, time, record].to_msgpack
37
36
  }
38
- sleep 0.5
39
37
  end
40
38
  end
41
39
 
@@ -53,7 +51,6 @@ module StreamInputTest
53
51
  entries << [time, record]
54
52
  }
55
53
  send_data ["tag1", entries].to_msgpack
56
- sleep 0.5
57
54
  end
58
55
  end
59
56
 
@@ -71,7 +68,6 @@ module StreamInputTest
71
68
  [time, record].to_msgpack(entries)
72
69
  }
73
70
  send_data ["tag1", entries].to_msgpack
74
- sleep 0.5
75
71
  end
76
72
  end
77
73
 
@@ -87,7 +83,6 @@ module StreamInputTest
87
83
  d.expected_emits.each {|tag,time,record|
88
84
  send_data [tag, time, record].to_json
89
85
  }
90
- sleep 0.5
91
86
  end
92
87
  end
93
88
 
@@ -131,6 +131,24 @@ class SyslogInputTest < Test::Unit::TestCase
131
131
  compare_test_result(d.emits, tests)
132
132
  end
133
133
 
134
+ def test_msg_size_with_include_source_host
135
+ d = create_driver([CONFIG, 'include_source_host'].join("\n"))
136
+ tests = create_test_case
137
+
138
+ host = nil
139
+ d.run do
140
+ u = UDPSocket.new
141
+ u.connect('127.0.0.1', PORT)
142
+ host = u.peeraddr[2]
143
+ tests.each {|test|
144
+ u.send(test['msg'], 0)
145
+ }
146
+ sleep 1
147
+ end
148
+
149
+ compare_test_result(d.emits, tests, host)
150
+ end
151
+
134
152
  def create_test_case
135
153
  # actual syslog message has "\n"
136
154
  [
@@ -139,10 +157,11 @@ class SyslogInputTest < Test::Unit::TestCase
139
157
  ]
140
158
  end
141
159
 
142
- def compare_test_result(emits, tests)
160
+ def compare_test_result(emits, tests, host = nil)
143
161
  emits.each_index { |i|
144
162
  assert_equal('syslog.kern.info', emits[0][0]) # <6> means kern.info
145
163
  assert_equal(tests[i]['expected'], emits[i][2]['message'])
164
+ assert_equal(host, emits[i][2]['source_host']) if host
146
165
  }
147
166
  end
148
167
  end
@@ -27,6 +27,7 @@ module FluentOutputTest
27
27
  d = create_driver
28
28
  assert_equal 'memory', d.instance.buffer_type
29
29
  assert_equal 60, d.instance.flush_interval
30
+ assert_equal false, d.instance.disable_retry_limit
30
31
  assert_equal 17, d.instance.retry_limit
31
32
  assert_equal 1.0, d.instance.retry_wait
32
33
  assert_equal nil, d.instance.max_retry_wait
@@ -37,18 +38,27 @@ module FluentOutputTest
37
38
  # max_retry_wait
38
39
  d = create_driver(CONFIG + %[max_retry_wait 4])
39
40
  assert_equal 4, d.instance.max_retry_wait
41
+
42
+ # disable_retry_limit
43
+ d = create_driver(CONFIG + %[disable_retry_limit true])
44
+ assert_equal true, d.instance.disable_retry_limit
40
45
  end
41
46
 
42
47
  def test_calc_retry_wait
43
48
  # default
44
49
  d = create_driver
45
- d.instance.retry_limit.times { d.instance.instance_variable_get(:@error_history) << Engine.now }
50
+ d.instance.retry_limit.times {
51
+ # "d.instance.instance_variable_get(:@num_errors) += 1" causes SyntaxError
52
+ d.instance.instance_eval { @num_errors += 1 }
53
+ }
46
54
  wait = d.instance.retry_wait * (2 ** (d.instance.retry_limit - 1))
47
55
  assert( d.instance.calc_retry_wait > wait - wait / 8.0 )
48
56
 
49
57
  # max_retry_wait
50
58
  d = create_driver(CONFIG + %[max_retry_wait 4])
51
- d.instance.retry_limit.times { d.instance.instance_variable_get(:@error_history) << Engine.now }
59
+ d.instance.retry_limit.times {
60
+ d.instance.instance_eval { @num_errors += 1 }
61
+ }
52
62
  assert_equal 4, d.instance.calc_retry_wait
53
63
  end
54
64
 
@@ -130,6 +130,43 @@ module ParserTest
130
130
  end
131
131
  end
132
132
 
133
+ class ApacheErrorParserTest < ::Test::Unit::TestCase
134
+ include ParserTest
135
+
136
+ def setup
137
+ @parser = TextParser::TEMPLATE_REGISTRY.lookup('apache_error').call
138
+ @expected = {
139
+ 'level' => 'error',
140
+ 'client' => '127.0.0.1',
141
+ 'message' => 'client denied by server configuration'
142
+ }
143
+ end
144
+
145
+ def test_call
146
+ @parser.call('[Wed Oct 11 14:32:52 2000] [error] [client 127.0.0.1] client denied by server configuration') { |time, record|
147
+ assert_equal(str2time('Wed Oct 11 14:32:52 2000'), time)
148
+ assert_equal(@expected, record)
149
+ }
150
+ end
151
+
152
+ def test_call_with_pid
153
+ @parser.call('[Wed Oct 11 14:32:52 2000] [error] [pid 1000] [client 127.0.0.1] client denied by server configuration') { |time, record|
154
+ assert_equal(str2time('Wed Oct 11 14:32:52 2000'), time)
155
+ assert_equal(@expected.merge('pid' => '1000'), record)
156
+ }
157
+ end
158
+
159
+ def test_call_without_client
160
+ @parser.call('[Wed Oct 11 14:32:52 2000] [notice] Apache/2.2.15 (Unix) DAV/2 configured -- resuming normal operations') { |time, record|
161
+ assert_equal(str2time('Wed Oct 11 14:32:52 2000'), time)
162
+ assert_equal({
163
+ 'level' => 'notice',
164
+ 'message' => 'Apache/2.2.15 (Unix) DAV/2 configured -- resuming normal operations'
165
+ }, record)
166
+ }
167
+ end
168
+ end
169
+
133
170
  class Apache2ParserTest < ::Test::Unit::TestCase
134
171
  include ParserTest
135
172
 
@@ -656,5 +693,23 @@ EOS
656
693
  i += 1
657
694
  }
658
695
  end
696
+
697
+ def test_setting_estimate_current_event_value
698
+ p1 = TextParser.new
699
+ assert_nil p1.estimate_current_event
700
+ assert_nil p1.parser
701
+
702
+ p1.configure('format' => 'none')
703
+ assert_equal true, p1.parser.estimate_current_event
704
+
705
+ p2 = TextParser.new
706
+ assert_nil p2.estimate_current_event
707
+ assert_nil p2.parser
708
+
709
+ p2.estimate_current_event = false
710
+
711
+ p2.configure('format' => 'none')
712
+ assert_equal false, p2.parser.estimate_current_event
713
+ end
659
714
  end
660
715
  end
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.52
4
+ version: 0.10.53
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sadayuki Furuhashi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-14 00:00:00.000000000 Z
11
+ date: 2014-08-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -341,6 +341,7 @@ files:
341
341
  - spec/config/helper.rb
342
342
  - spec/config/literal_parser_spec.rb
343
343
  - spec/config/section_spec.rb
344
+ - spec/config/system_config_spec.rb
344
345
  - spec/spec_helper.rb
345
346
  - test/helper.rb
346
347
  - test/plugin/data/2010/01/20100102-030405.log
@@ -409,6 +410,7 @@ test_files:
409
410
  - spec/config/helper.rb
410
411
  - spec/config/literal_parser_spec.rb
411
412
  - spec/config/section_spec.rb
413
+ - spec/config/system_config_spec.rb
412
414
  - spec/spec_helper.rb
413
415
  - test/helper.rb
414
416
  - test/plugin/data/2010/01/20100102-030405.log