fluentd 0.10.55 → 0.10.56

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: 8f6c7392b51882506144d22dbef860923ca396a8
4
- data.tar.gz: 57b91cf45454978c20ae3a497502c2b41580d29d
3
+ metadata.gz: 15aab20b26be1dd37d9f185c97971a38767f30a6
4
+ data.tar.gz: 782800a38871c60c45a69a36e96f8577488809fb
5
5
  SHA512:
6
- metadata.gz: 09247456a29976eec30ca20b77f69bc5179a82fdbe1052133234e7b926bb8fd403bf951ea478d0fc0a9f4ba54cbfded565bf653717b350178ada538c08baac6c
7
- data.tar.gz: 8f9dd61a23a67c4e90b937cdfa5d7ed881f54853ae1fe9b942f0b19e648472f8714d394af6ed21e5848b9a0a245af86974d55a28760da3c759a5e3eadf7ad671
6
+ metadata.gz: ed67bd0d60ed78502d18d10920343db5f78cd8b99ba012b1547d3eef1550e49d1bf0456f88cf5ede4e066a03867821007ef1dd65a19a10ddce5f9e4f8478a7d8
7
+ data.tar.gz: 359d689bc9ec1b8f158759a1b8a876f5b14858d845263a8b2fd32dff39c7edafb408003875dd4089c6a29d1c6bf58be38843c99e17bba1a7ff15d1ccdd90c3c9
data/ChangeLog CHANGED
@@ -1,3 +1,10 @@
1
+ Release 0.10.56 - 2014/10/30
2
+
3
+ * config: Add Fluent::Config::Section#object_id to avoid NoMethodError by object dump tools
4
+ * mixin: Fix SetTagKeyMixin and SetTimeKeyMixin which ignores config_set_default since 0.10.53
5
+ * input/output: Support 'timezone' configuration parameter (e.g. "+09:00" for JST).
6
+ * log: Use plugin_id instead of object_id in log message for consistency with in_monitor_agent
7
+
1
8
  Release 0.10.55 - 2014/10/17
2
9
 
3
10
  * config: Relax '@' handling in the plugin configuration for backward compatibility
@@ -24,6 +24,8 @@ Gem::Specification.new do |gem|
24
24
  gem.add_runtime_dependency("cool.io", [">= 1.1.1", "!= 1.2.0", "< 2.0.0"])
25
25
  gem.add_runtime_dependency("http_parser.rb", [">= 0.5.1", "< 0.7.0"])
26
26
  gem.add_runtime_dependency("sigdump", ["~> 0.2.2"])
27
+ gem.add_runtime_dependency("tzinfo", [">= 1.0.0"])
28
+ gem.add_runtime_dependency("tzinfo-data", [">= 1.0.0"])
27
29
 
28
30
  gem.add_development_dependency("rake", [">= 0.9.2"])
29
31
  gem.add_development_dependency("flexmock")
@@ -14,6 +14,8 @@ module Fluent
14
14
  @params = params
15
15
  end
16
16
 
17
+ alias :object_id :__id__
18
+
17
19
  def inspect
18
20
  "<Fluent::Config::Section #{@params.to_json}>"
19
21
  end
@@ -28,6 +28,7 @@ module Fluent
28
28
  config_param :include_tag_key, :bool, :default => false
29
29
  config_param :tag_key, :string, :default => 'tag'
30
30
  config_param :localtime, :bool, :default => true
31
+ config_param :timezone, :string, :default => nil
31
32
  }
32
33
  end
33
34
 
@@ -37,7 +38,7 @@ module Fluent
37
38
  if conf['utc']
38
39
  @localtime = false
39
40
  end
40
- @timef = TimeFormatter.new(@time_format, @localtime)
41
+ @timef = TimeFormatter.new(@time_format, @localtime, @timezone)
41
42
  end
42
43
 
43
44
  def filter_record(tag, time, record)
@@ -17,12 +17,21 @@
17
17
  #
18
18
  module Fluent
19
19
  class TimeFormatter
20
- def initialize(format, localtime)
20
+ require 'fluent/timezone'
21
+
22
+ def initialize(format, localtime, timezone = nil)
21
23
  @tc1 = 0
22
24
  @tc1_str = nil
23
25
  @tc2 = 0
24
26
  @tc2_str = nil
25
27
 
28
+ if formatter = Fluent::Timezone.formatter(timezone, format)
29
+ define_singleton_method(:format_nocache) {|time|
30
+ formatter.call(time)
31
+ }
32
+ return
33
+ end
34
+
26
35
  if format
27
36
  if localtime
28
37
  define_singleton_method(:format_nocache) {|time|
@@ -113,15 +122,16 @@ module Fluent
113
122
  end
114
123
 
115
124
  module SetTimeKeyMixin
125
+ require 'fluent/timezone'
116
126
  include RecordFilterMixin
117
127
 
118
- attr_accessor :include_time_key, :time_key, :localtime
128
+ attr_accessor :include_time_key, :time_key, :localtime, :timezone
119
129
 
120
130
  def configure(conf)
121
- super
122
-
123
131
  @include_time_key = false
124
132
 
133
+ super
134
+
125
135
  if s = conf['include_time_key']
126
136
  include_time_key = Config.bool_value(s)
127
137
  raise ConfigError, "Invalid boolean expression '#{s}' for include_time_key parameter" if include_time_key.nil?
@@ -139,7 +149,12 @@ module Fluent
139
149
  @localtime = false
140
150
  end
141
151
 
142
- @timef = TimeFormatter.new(@time_format, @localtime)
152
+ if conf['timezone']
153
+ @timezone = conf['timezone']
154
+ Fluent::Timezone.validate!(@timezone)
155
+ end
156
+
157
+ @timef = TimeFormatter.new(@time_format, @localtime, @timezone)
143
158
  end
144
159
  end
145
160
 
@@ -156,10 +171,10 @@ module Fluent
156
171
  attr_accessor :include_tag_key, :tag_key
157
172
 
158
173
  def configure(conf)
159
- super
160
-
161
174
  @include_tag_key = false
162
175
 
176
+ super
177
+
163
178
  if s = conf['include_tag_key']
164
179
  include_tag_key = Config.bool_value(s)
165
180
  raise ConfigError, "Invalid boolean expression '#{s}' for include_tag_key parameter" if include_tag_key.nil?
@@ -316,7 +316,7 @@ module Fluent
316
316
  @num_errors = 0
317
317
  # Note: don't notify to other threads to prevent
318
318
  # burst to recovered server
319
- $log.warn "retry succeeded.", :instance=>object_id
319
+ $log.warn "retry succeeded.", :plugin_id=>plugin_id
320
320
  end
321
321
 
322
322
  if has_next
@@ -341,20 +341,20 @@ module Fluent
341
341
  end
342
342
 
343
343
  if @disable_retry_limit || error_count < @retry_limit
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
+ $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, :plugin_id=>plugin_id
345
345
  $log.warn_backtrace e.backtrace
346
346
 
347
347
  elsif @secondary
348
348
  if error_count == @retry_limit
349
- $log.warn "failed to flush the buffer.", :error_class=>e.class.to_s, :error=>e.to_s, :instance=>object_id
349
+ $log.warn "failed to flush the buffer.", :error_class=>e.class.to_s, :error=>e.to_s, :plugin_id=>plugin_id
350
350
  $log.warn "retry count exceededs limit. falling back to secondary output."
351
351
  $log.warn_backtrace e.backtrace
352
352
  retry # retry immediately
353
353
  elsif error_count <= @retry_limit + @secondary_limit
354
- $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
354
+ $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, :plugin_id=>plugin_id
355
355
  $log.warn_backtrace e.backtrace
356
356
  else
357
- $log.warn "failed to flush the buffer.", :error_class=>e.class, :error=>e.to_s, :instance=>object_id
357
+ $log.warn "failed to flush the buffer.", :error_class=>e.class, :error=>e.to_s, :plugin_id=>plugin_id
358
358
  $log.warn "secondary retry count exceededs limit."
359
359
  $log.warn_backtrace e.backtrace
360
360
  write_abort
@@ -362,7 +362,7 @@ module Fluent
362
362
  end
363
363
 
364
364
  else
365
- $log.warn "failed to flush the buffer.", :error_class=>e.class.to_s, :error=>e.to_s, :instance=>object_id
365
+ $log.warn "failed to flush the buffer.", :error_class=>e.class.to_s, :error=>e.to_s, :plugin_id=>plugin_id
366
366
  $log.warn "retry count exceededs limit."
367
367
  $log.warn_backtrace e.backtrace
368
368
  write_abort
@@ -453,6 +453,8 @@ module Fluent
453
453
 
454
454
 
455
455
  class TimeSlicedOutput < BufferedOutput
456
+ require 'fluent/timezone'
457
+
456
458
  def initialize
457
459
  super
458
460
  @localtime = true
@@ -461,6 +463,7 @@ module Fluent
461
463
 
462
464
  config_param :time_slice_format, :string, :default => '%Y%m%d'
463
465
  config_param :time_slice_wait, :time, :default => 10*60
466
+ config_param :timezone, :string, :default => nil
464
467
  config_set_default :buffer_type, 'file' # overwrite default buffer_type
465
468
  config_set_default :buffer_chunk_limit, 256*1024*1024 # overwrite default buffer_chunk_limit
466
469
  config_set_default :flush_interval, nil
@@ -470,14 +473,20 @@ module Fluent
470
473
  def configure(conf)
471
474
  super
472
475
 
473
- # TODO timezone
474
476
  if conf['utc']
475
477
  @localtime = false
476
478
  elsif conf['localtime']
477
479
  @localtime = true
478
480
  end
479
481
 
480
- if @localtime
482
+ if conf['timezone']
483
+ @timezone = conf['timezone']
484
+ Fluent::Timezone.validate!(@timezone)
485
+ end
486
+
487
+ if @timezone
488
+ @time_slicer = Timezone.formatter(@timezone, @time_slice_format)
489
+ elsif @localtime
481
490
  @time_slicer = Proc.new {|time|
482
491
  Time.at(time).strftime(@time_slice_format)
483
492
  }
@@ -22,6 +22,7 @@ module Fluent
22
22
  def initialize
23
23
  super
24
24
  require 'fluent/plugin/exec_util'
25
+ require 'fluent/timezone'
25
26
  end
26
27
 
27
28
  SUPPORTED_FORMAT = {
@@ -54,6 +55,11 @@ module Fluent
54
55
  @localtime = false
55
56
  end
56
57
 
58
+ if conf['timezone']
59
+ @timezone = conf['timezone']
60
+ Fluent::Timezone.validate!(@timezone)
61
+ end
62
+
57
63
  if !@tag && !@tag_key
58
64
  raise ConfigError, "'tag' or 'tag_key' option is required on exec input"
59
65
  end
@@ -58,7 +58,7 @@ module Fluent
58
58
 
59
59
  if @time_key
60
60
  if @time_format
61
- tf = TimeFormatter.new(@time_format, @localtime)
61
+ tf = TimeFormatter.new(@time_format, @localtime, @timezone)
62
62
  @time_format_proc = tf.method(:format)
63
63
  else
64
64
  @time_format_proc = Proc.new { |time| time.to_s }
@@ -24,6 +24,7 @@ module Fluent
24
24
 
25
25
  def initialize
26
26
  super
27
+ require 'fluent/timezone'
27
28
  end
28
29
 
29
30
  config_param :command, :string
@@ -61,6 +62,7 @@ module Fluent
61
62
  config_param :time_format, :string, :default => nil
62
63
 
63
64
  config_param :localtime, :bool, :default => true
65
+ config_param :timezone, :string, :default => nil
64
66
  config_param :num_children, :integer, :default => 1
65
67
 
66
68
  # nil, 'none' or 0: no respawn, 'inf' or -1: infinite times, positive integer: try to respawn specified times only
@@ -98,13 +100,18 @@ module Fluent
98
100
  @localtime = false
99
101
  end
100
102
 
103
+ if conf['timezone']
104
+ @timezone = conf['timezone']
105
+ Fluent::Timezone.validate!(@timezone)
106
+ end
107
+
101
108
  if !@tag && !@out_tag_key
102
109
  raise ConfigError, "'tag' or 'out_tag_key' option is required on exec_filter output"
103
110
  end
104
111
 
105
112
  if @in_time_key
106
113
  if f = @in_time_format
107
- tf = TimeFormatter.new(f, @localtime)
114
+ tf = TimeFormatter.new(f, @localtime, @timezone)
108
115
  @time_format_proc = tf.method(:format)
109
116
  else
110
117
  @time_format_proc = Proc.new {|time| time.to_s }
@@ -87,7 +87,7 @@ module Fluent
87
87
  node_conf = NodeConfig.new(name, host, port, weight, standby, failure,
88
88
  @phi_threshold, recover_sample_size, @expire_dns_cache, @phi_failure_detector)
89
89
  @nodes << Node.new(log, node_conf)
90
- log.info "adding forwarding server '#{name}'", :host=>host, :port=>port, :weight=>weight
90
+ log.info "adding forwarding server '#{name}'", :host=>host, :port=>port, :weight=>weight, :plugin_id=>plugin_id
91
91
  }
92
92
  end
93
93
 
@@ -0,0 +1,131 @@
1
+ #
2
+ # Fluentd
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'tzinfo'
18
+
19
+ module Fluent
20
+ class Timezone
21
+ # [+-]HH:MM, [+-]HHMM, [+-]HH
22
+ NUMERIC_PATTERN = %r{\A[+-]\d\d(:?\d\d)?\z}
23
+
24
+ # Region/Zone, Region/Zone/Zone
25
+ NAME_PATTERN = %r{\A[^/]+/[^/]+(/[^/]+)?\z}
26
+
27
+ # Validate the format of the specified timezone.
28
+ #
29
+ # Valid formats are as follows. Note that timezone abbreviations
30
+ # such as PST and JST are not supported intentionally.
31
+ #
32
+ # 1. [+-]HH:MM (e.g. "+09:00")
33
+ # 2. [+-]HHMM (e.g. "+0900")
34
+ # 3. [+-]HH (e.g. "+09")
35
+ # 4. Region/Zone (e.g. "Asia/Tokyo")
36
+ # 5. Region/Zone/Zone (e.g. "America/Argentina/Buenos_Aires")
37
+ #
38
+ # In the 4th and 5th cases, it is checked whether the specified
39
+ # timezone exists in the timezone database.
40
+ #
41
+ # When the given timezone is valid, true is returned. Otherwise,
42
+ # false is returned. When nil is given, false is returned.
43
+ def self.validate(timezone)
44
+ # If the specified timezone is nil.
45
+ if timezone.nil?
46
+ # Invalid.
47
+ return false
48
+ end
49
+
50
+ # [+-]HH:MM, [+-]HHMM, [+-]HH
51
+ if NUMERIC_PATTERN === timezone
52
+ # Valid. It can be parsed by Time.zone_offset method.
53
+ return true
54
+ end
55
+
56
+ # Region/Zone, Region/Zone/Zone
57
+ if NAME_PATTERN === timezone
58
+ begin
59
+ # Get a Timezone instance for the specified timezone.
60
+ TZInfo::Timezone.get(timezone)
61
+ rescue
62
+ # Invalid. The string does not exist in the timezone database.
63
+ return false
64
+ else
65
+ # Valid. The string was found in the timezone database.
66
+ return true
67
+ end
68
+ else
69
+ # Invalid. Timezone abbreviations are not supported.
70
+ return false
71
+ end
72
+ end
73
+
74
+ # Validate the format of the specified timezone.
75
+ #
76
+ # The implementation of this method calls validate(timezone) method
77
+ # to check whether the given timezone is valid. When invalid, this
78
+ # method raises a ConfigError.
79
+ def self.validate!(timezone)
80
+ unless validate(timezone)
81
+ raise ConfigError, "Unsupported timezone '#{timezone}'"
82
+ end
83
+ end
84
+
85
+ # Create a formatter for a timezone and optionally a format.
86
+ #
87
+ # An Proc object is returned. If the given timezone is invalid,
88
+ # nil is returned.
89
+ def self.formatter(timezone, format = nil)
90
+ if timezone.nil?
91
+ return nil
92
+ end
93
+
94
+ # [+-]HH:MM, [+-]HHMM, [+-]HH
95
+ if NUMERIC_PATTERN === timezone
96
+ offset = Time.zone_offset(timezone)
97
+
98
+ if format
99
+ return Proc.new {|time|
100
+ Time.at(time).localtime(offset).strftime(format)
101
+ }
102
+ else
103
+ return Proc.new {|time|
104
+ Time.at(time).localtime(offset).iso8601
105
+ }
106
+ end
107
+ end
108
+
109
+ # Region/Zone, Region/Zone/Zone
110
+ if NAME_PATTERN === timezone
111
+ begin
112
+ tz = TZInfo::Timezone.get(timezone)
113
+ rescue
114
+ return nil
115
+ end
116
+
117
+ if format
118
+ return Proc.new {|time|
119
+ Time.at(time).localtime(tz.period_for_utc(time).utc_total_offset).strftime(format)
120
+ }
121
+ else
122
+ return Proc.new {|time|
123
+ Time.at(time).localtime(tz.period_for_utc(time).utc_total_offset).iso8601
124
+ }
125
+ end
126
+ end
127
+
128
+ return nil
129
+ end
130
+ end
131
+ end
@@ -1,5 +1,5 @@
1
1
  module Fluent
2
2
 
3
- VERSION = '0.10.55'
3
+ VERSION = '0.10.56'
4
4
 
5
5
  end
@@ -45,6 +45,16 @@ module Fluent::Config
45
45
  end
46
46
  end
47
47
 
48
+ sub_test_case '#object_id' do
49
+ test 'returns its object id' do
50
+ s1 = Fluent::Config::Section.new({})
51
+ assert s1.object_id
52
+ s2 = Fluent::Config::Section.new({})
53
+ assert s2.object_id
54
+ assert_not_equal s1.object_id, s2.object_id
55
+ end
56
+ end
57
+
48
58
  sub_test_case '#to_h' do
49
59
  test 'returns internal hash itself' do
50
60
  hash = {
@@ -63,6 +63,41 @@ class FileOutputTest < Test::Unit::TestCase
63
63
  d.run
64
64
  end
65
65
 
66
+ def test_timezone_1
67
+ d = create_driver %[
68
+ path #{TMP_DIR}/out_file_test
69
+ timezone Asia/Taipei
70
+ ]
71
+
72
+ time = Time.parse("2011-01-02 13:14:15 UTC").to_i
73
+
74
+ d.emit({"a"=>1}, time)
75
+ d.expect_format %[2011-01-02T21:14:15+08:00\ttest\t{"a":1}\n]
76
+ d.run
77
+ end
78
+
79
+ def test_timezone_2
80
+ d = create_driver %[
81
+ path #{TMP_DIR}/out_file_test
82
+ timezone -03:30
83
+ ]
84
+
85
+ time = Time.parse("2011-01-02 13:14:15 UTC").to_i
86
+
87
+ d.emit({"a"=>1}, time)
88
+ d.expect_format %[2011-01-02T09:44:15-03:30\ttest\t{"a":1}\n]
89
+ d.run
90
+ end
91
+
92
+ def test_timezone_invalid
93
+ assert_raise(Fluent::ConfigError) do
94
+ create_driver %[
95
+ path #{TMP_DIR}/out_file_test
96
+ timezone Invalid/Invalid
97
+ ]
98
+ end
99
+ end
100
+
66
101
  def check_gzipped_result(path, expect)
67
102
  # Zlib::GzipReader has a bug of concatenated file: https://bugs.ruby-lang.org/issues/9790
68
103
  # Following code from https://www.ruby-forum.com/topic/971591#979520
@@ -29,6 +29,13 @@ module FormatterTest
29
29
  {'message' => 'awesome'}
30
30
  end
31
31
 
32
+ def with_timezone(tz)
33
+ oldtz, ENV['TZ'] = ENV['TZ'], tz
34
+ yield
35
+ ensure
36
+ ENV['TZ'] = oldtz
37
+ end
38
+
32
39
  class OutFileFormatterTest < ::Test::Unit::TestCase
33
40
  include FormatterTest
34
41
 
@@ -216,4 +223,220 @@ module FormatterTest
216
223
  end
217
224
  end
218
225
  end
226
+
227
+ class TimeFormatterTest < ::Test::Unit::TestCase
228
+ include FormatterTest
229
+
230
+ def setup
231
+ @time = Time.new(2014, 9, 27, 0, 0, 0, 0).to_i
232
+ @fmt = "%Y%m%d %H%M%z" # YYYYMMDD HHMM[+-]HHMM
233
+ end
234
+
235
+ def format(format, localtime, timezone)
236
+ formatter = Fluent::TimeFormatter.new(format, localtime, timezone)
237
+ formatter.format(@time)
238
+ end
239
+
240
+ def test_default_utc_nil
241
+ assert_equal("2014-09-27T00:00:00Z", format(nil, false, nil))
242
+ end
243
+
244
+ def test_default_utc_pHH_MM
245
+ assert_equal("2014-09-27T01:30:00+01:30", format(nil, false, "+01:30"))
246
+ end
247
+
248
+ def test_default_utc_nHH_MM
249
+ assert_equal("2014-09-26T22:30:00-01:30", format(nil, false, "-01:30"))
250
+ end
251
+
252
+ def test_default_utc_pHHMM
253
+ assert_equal("2014-09-27T02:30:00+02:30", format(nil, false, "+0230"))
254
+ end
255
+
256
+ def test_default_utc_nHHMM
257
+ assert_equal("2014-09-26T21:30:00-02:30", format(nil, false, "-0230"))
258
+ end
259
+
260
+ def test_default_utc_pHH
261
+ assert_equal("2014-09-27T03:00:00+03:00", format(nil, false, "+03"))
262
+ end
263
+
264
+ def test_default_utc_nHH
265
+ assert_equal("2014-09-26T21:00:00-03:00", format(nil, false, "-03"))
266
+ end
267
+
268
+ def test_default_utc_timezone_1
269
+ # Asia/Tokyo (+09:00) does not have daylight saving time.
270
+ assert_equal("2014-09-27T09:00:00+09:00", format(nil, false, "Asia/Tokyo"))
271
+ end
272
+
273
+ def test_default_utc_timezone_2
274
+ # Pacific/Honolulu (-10:00) does not have daylight saving time.
275
+ assert_equal("2014-09-26T14:00:00-10:00", format(nil, false, "Pacific/Honolulu"))
276
+ end
277
+
278
+ def test_default_utc_timezone_3
279
+ # America/Argentina/Buenos_Aires (-03:00) does not have daylight saving time.
280
+ assert_equal("2014-09-26T21:00:00-03:00", format(nil, false, "America/Argentina/Buenos_Aires"))
281
+ end
282
+
283
+ def test_default_utc_timezone_4
284
+ # Europe/Paris has daylight saving time. Its UTC offset is +01:00 and its
285
+ # UTC offset in DST is +02:00. In September, Europe/Paris is in DST.
286
+ assert_equal("2014-09-27T02:00:00+02:00", format(nil, false, "Europe/Paris"))
287
+ end
288
+
289
+ def test_default_utc_timezone_5
290
+ # Europe/Paris has daylight saving time. Its UTC offset is +01:00 and its
291
+ # UTC offset in DST is +02:00. In January, Europe/Paris is not in DST.
292
+ @time = Time.new(2014, 1, 24, 0, 0, 0, 0).to_i
293
+ assert_equal("2014-01-24T01:00:00+01:00", format(nil, false, "Europe/Paris"))
294
+ end
295
+
296
+ def test_default_utc_invalid
297
+ assert_equal("2014-09-27T00:00:00Z", format(nil, false, "Invalid"))
298
+ end
299
+
300
+ def test_default_localtime_nil_1
301
+ with_timezone("UTC-04") do
302
+ assert_equal("2014-09-27T04:00:00+04:00", format(nil, true, nil))
303
+ end
304
+ end
305
+
306
+ def test_default_localtime_nil_2
307
+ with_timezone("UTC+05") do
308
+ assert_equal("2014-09-26T19:00:00-05:00", format(nil, true, nil))
309
+ end
310
+ end
311
+
312
+ def test_default_localtime_timezone
313
+ # 'timezone' takes precedence over 'localtime'.
314
+ with_timezone("UTC-06") do
315
+ assert_equal("2014-09-27T07:00:00+07:00", format(nil, true, "+07"))
316
+ end
317
+ end
318
+
319
+ def test_specific_utc_nil
320
+ assert_equal("20140927 0000+0000", format(@fmt, false, nil))
321
+ end
322
+
323
+ def test_specific_utc_pHH_MM
324
+ assert_equal("20140927 0830+0830", format(@fmt, false, "+08:30"))
325
+ end
326
+
327
+ def test_specific_utc_nHH_MM
328
+ assert_equal("20140926 1430-0930", format(@fmt, false, "-09:30"))
329
+ end
330
+
331
+ def test_specific_utc_pHHMM
332
+ assert_equal("20140927 1030+1030", format(@fmt, false, "+1030"))
333
+ end
334
+
335
+ def test_specific_utc_nHHMM
336
+ assert_equal("20140926 1230-1130", format(@fmt, false, "-1130"))
337
+ end
338
+
339
+ def test_specific_utc_pHH
340
+ assert_equal("20140927 1200+1200", format(@fmt, false, "+12"))
341
+ end
342
+
343
+ def test_specific_utc_nHH
344
+ assert_equal("20140926 1100-1300", format(@fmt, false, "-13"))
345
+ end
346
+
347
+ def test_specific_utc_timezone_1
348
+ # Europe/Moscow (+04:00) does not have daylight saving time.
349
+ assert_equal("20140927 0400+0400", format(@fmt, false, "Europe/Moscow"))
350
+ end
351
+
352
+ def test_specific_utc_timezone_2
353
+ # Pacific/Galapagos (-06:00) does not have daylight saving time.
354
+ assert_equal("20140926 1800-0600", format(@fmt, false, "Pacific/Galapagos"))
355
+ end
356
+
357
+ def test_specific_utc_timezone_3
358
+ # America/Argentina/Buenos_Aires (-03:00) does not have daylight saving time.
359
+ assert_equal("20140926 2100-0300", format(@fmt, false, "America/Argentina/Buenos_Aires"))
360
+ end
361
+
362
+ def test_specific_utc_timezone_4
363
+ # America/Los_Angeles has daylight saving time. Its UTC offset is -08:00 and its
364
+ # UTC offset in DST is -07:00. In September, America/Los_Angeles is in DST.
365
+ assert_equal("20140926 1700-0700", format(@fmt, false, "America/Los_Angeles"))
366
+ end
367
+
368
+ def test_specific_utc_timezone_5
369
+ # America/Los_Angeles has daylight saving time. Its UTC offset is -08:00 and its
370
+ # UTC offset in DST is -07:00. In January, America/Los_Angeles is not in DST.
371
+ @time = Time.new(2014, 1, 24, 0, 0, 0, 0).to_i
372
+ assert_equal("20140123 1600-0800", format(@fmt, false, "America/Los_Angeles"))
373
+ end
374
+
375
+ def test_specific_utc_invalid
376
+ assert_equal("20140927 0000+0000", format(@fmt, false, "Invalid"))
377
+ end
378
+
379
+ def test_specific_localtime_nil_1
380
+ with_timezone("UTC-07") do
381
+ assert_equal("20140927 0700+0700", format(@fmt, true, nil))
382
+ end
383
+ end
384
+
385
+ def test_specific_localtime_nil_2
386
+ with_timezone("UTC+08") do
387
+ assert_equal("20140926 1600-0800", format(@fmt, true, nil))
388
+ end
389
+ end
390
+
391
+ def test_specific_localtime_timezone
392
+ # 'timezone' takes precedence over 'localtime'.
393
+ with_timezone("UTC-09") do
394
+ assert_equal("20140926 1400-1000", format(@fmt, true, "-10"))
395
+ end
396
+ end
397
+ end
398
+
399
+ class TimeConfigTest < ::Test::Unit::TestCase
400
+ include FormatterTest
401
+
402
+ def setup
403
+ @formatter = TextFormatter::LabeledTSVFormatter.new
404
+ @time = Time.new(2014, 9, 27, 0, 0, 0, 0).to_i
405
+ end
406
+
407
+ def format(conf)
408
+ @formatter.configure({'include_time_key' => true}.merge(conf))
409
+ formatted = @formatter.format("tag", @time, {})
410
+ # Drop the leading "time:" and the trailing "\n".
411
+ formatted[5..-2]
412
+ end
413
+
414
+ def test_none
415
+ with_timezone("UTC-01") do
416
+ # 'localtime' is true by default.
417
+ assert_equal("2014-09-27T01:00:00+01:00", format({}))
418
+ end
419
+ end
420
+
421
+ def test_utc
422
+ with_timezone("UTC-01") do
423
+ # 'utc' takes precedence over 'localtime'.
424
+ assert_equal("2014-09-27T00:00:00Z", format("utc" => true))
425
+ end
426
+ end
427
+
428
+ def test_timezone
429
+ with_timezone("UTC-01") do
430
+ # 'timezone' takes precedence over 'localtime'.
431
+ assert_equal("2014-09-27T02:00:00+02:00", format("timezone" => "+02"))
432
+ end
433
+ end
434
+
435
+ def test_utc_timezone
436
+ with_timezone("UTC-01") do
437
+ # 'timezone' takes precedence over 'utc'.
438
+ assert_equal("2014-09-27T09:00:00+09:00", format("utc" => true, "timezone" => "Asia/Tokyo"))
439
+ end
440
+ end
441
+ end
219
442
  end
@@ -27,15 +27,17 @@ module MixinTest
27
27
  end
28
28
 
29
29
  @@num = 0
30
+
30
31
  def create_register_output_name
31
- "mixin_text_#{@@num+=1}"
32
+ @@num += 1
33
+ "mixin_text_#{@@num}"
32
34
  end
33
35
 
34
36
  def format_check(hash, tagname = 'test')
35
37
  mock(Checker).format_check(tagname, @time.to_i, hash)
36
38
  end
37
39
 
38
- def create_driver(include_klass, conf = '', tag = "test")
40
+ def create_driver(include_klass, conf = '', tag = "test", &block)
39
41
  register_output_name = create_register_output_name
40
42
  include_klasses = [include_klass].flatten
41
43
 
@@ -51,6 +53,11 @@ module MixinTest
51
53
  def write(chunk); end
52
54
  }
53
55
 
56
+ if block
57
+ Utils.const_set("MixinTestClass#{@@num}", klass)
58
+ klass.module_eval(&block)
59
+ end
60
+
54
61
  Fluent::Test::BufferedOutputTestDriver.new(klass, tag) {
55
62
  }.configure("type #{register_output_name}" + conf)
56
63
  end
@@ -110,6 +117,19 @@ module MixinTest
110
117
  d.emit({'a' => 1})
111
118
  d.run
112
119
  end
120
+
121
+ sub_test_case "mixin" do
122
+ data(
123
+ 'true' => true,
124
+ 'false' => false)
125
+ test 'include_tag_key' do |param|
126
+ d = create_driver(Fluent::SetTagKeyMixin) {
127
+ config_set_default :include_tag_key, param
128
+ }
129
+
130
+ assert_equal(param, d.instance.include_tag_key)
131
+ end
132
+ end
113
133
  end
114
134
 
115
135
  class SetTimeKeyMixinText < Test::Unit::TestCase
@@ -155,6 +175,58 @@ module MixinTest
155
175
  d.emit({'a' => 1})
156
176
  d.run
157
177
  end
178
+
179
+ def test_timezone_1
180
+ format_check({
181
+ 'time' => "2010-05-03T17:02:01-10:00",
182
+ 'a' => 1
183
+ })
184
+
185
+ d = create_driver(Fluent::SetTimeKeyMixin, %[
186
+ include_time_key true
187
+ timezone Pacific/Honolulu
188
+ ])
189
+
190
+ d.emit({'a' => 1})
191
+ d.run
192
+ end
193
+
194
+ def test_timezone_2
195
+ format_check({
196
+ 'time' => "2010-05-04T08:32:01+05:30",
197
+ 'a' => 1
198
+ })
199
+
200
+ d = create_driver(Fluent::SetTimeKeyMixin, %[
201
+ include_time_key true
202
+ timezone +05:30
203
+ ])
204
+
205
+ d.emit({'a' => 1})
206
+ d.run
207
+ end
208
+
209
+ def test_timezone_invalid
210
+ assert_raise(Fluent::ConfigError) do
211
+ d = create_driver(Fluent::SetTimeKeyMixin, %[
212
+ include_time_key true
213
+ timezone Invalid/Invalid
214
+ ])
215
+ end
216
+ end
217
+
218
+ sub_test_case "mixin" do
219
+ data(
220
+ 'true' => true,
221
+ 'false' => false)
222
+ test 'include_time_key' do |param|
223
+ d = create_driver(Fluent::SetTimeKeyMixin) {
224
+ config_set_default :include_time_key, param
225
+ }
226
+
227
+ assert_equal(param, d.instance.include_time_key)
228
+ end
229
+ end
158
230
  end
159
231
 
160
232
  class HandleTagMixinTest < Test::Unit::TestCase
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.55
4
+ version: 0.10.56
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-10-16 00:00:00.000000000 Z
11
+ date: 2014-10-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -142,6 +142,34 @@ dependencies:
142
142
  - - "~>"
143
143
  - !ruby/object:Gem::Version
144
144
  version: 0.2.2
145
+ - !ruby/object:Gem::Dependency
146
+ name: tzinfo
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: 1.0.0
152
+ type: :runtime
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: 1.0.0
159
+ - !ruby/object:Gem::Dependency
160
+ name: tzinfo-data
161
+ requirement: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: 1.0.0
166
+ type: :runtime
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: 1.0.0
145
173
  - !ruby/object:Gem::Dependency
146
174
  name: rake
147
175
  requirement: !ruby/object:Gem::Requirement
@@ -333,6 +361,7 @@ files:
333
361
  - lib/fluent/test/base.rb
334
362
  - lib/fluent/test/input_test.rb
335
363
  - lib/fluent/test/output_test.rb
364
+ - lib/fluent/timezone.rb
336
365
  - lib/fluent/version.rb
337
366
  - spec/spec_helper.rb
338
367
  - test/config/assertions.rb