fluentd 0.14.6 → 0.14.7

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.

Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +46 -0
  3. data/bin/fluent-binlog-reader +7 -0
  4. data/example/in_dummy_with_compression.conf +23 -0
  5. data/lib/fluent/agent.rb +8 -12
  6. data/lib/fluent/command/binlog_reader.rb +234 -0
  7. data/lib/fluent/command/fluentd.rb +17 -1
  8. data/lib/fluent/compat/file_util.rb +1 -1
  9. data/lib/fluent/compat/output.rb +5 -1
  10. data/lib/fluent/config/configure_proxy.rb +18 -4
  11. data/lib/fluent/config/element.rb +1 -1
  12. data/lib/fluent/config/section.rb +1 -1
  13. data/lib/fluent/config/v1_parser.rb +1 -1
  14. data/lib/fluent/env.rb +1 -0
  15. data/lib/fluent/event.rb +49 -2
  16. data/lib/fluent/event_router.rb +6 -2
  17. data/lib/fluent/label.rb +8 -0
  18. data/lib/fluent/log.rb +30 -1
  19. data/lib/fluent/plugin.rb +1 -1
  20. data/lib/fluent/plugin/base.rb +3 -0
  21. data/lib/fluent/plugin/buf_file.rb +2 -2
  22. data/lib/fluent/plugin/buf_memory.rb +1 -1
  23. data/lib/fluent/plugin/buffer.rb +12 -2
  24. data/lib/fluent/plugin/buffer/chunk.rb +68 -7
  25. data/lib/fluent/plugin/buffer/file_chunk.rb +4 -4
  26. data/lib/fluent/plugin/buffer/memory_chunk.rb +4 -4
  27. data/lib/fluent/plugin/compressable.rb +91 -0
  28. data/lib/fluent/plugin/filter_grep.rb +4 -4
  29. data/lib/fluent/plugin/formatter.rb +2 -2
  30. data/lib/fluent/plugin/formatter_json.rb +2 -1
  31. data/lib/fluent/plugin/formatter_out_file.rb +3 -30
  32. data/lib/fluent/plugin/in_forward.rb +3 -2
  33. data/lib/fluent/plugin/in_monitor_agent.rb +7 -21
  34. data/lib/fluent/plugin/in_syslog.rb +1 -1
  35. data/lib/fluent/plugin/in_tail.rb +10 -2
  36. data/lib/fluent/plugin/multi_output.rb +63 -3
  37. data/lib/fluent/plugin/out_exec.rb +1 -1
  38. data/lib/fluent/plugin/out_file.rb +5 -1
  39. data/lib/fluent/plugin/out_forward.rb +17 -5
  40. data/lib/fluent/plugin/out_stdout.rb +2 -1
  41. data/lib/fluent/plugin/output.rb +205 -19
  42. data/lib/fluent/plugin/parser.rb +5 -49
  43. data/lib/fluent/plugin/parser_apache2.rb +1 -1
  44. data/lib/fluent/plugin/parser_json.rb +4 -4
  45. data/lib/fluent/plugin/parser_multiline.rb +5 -5
  46. data/lib/fluent/plugin/parser_regexp.rb +1 -2
  47. data/lib/fluent/plugin/parser_syslog.rb +2 -2
  48. data/lib/fluent/plugin/storage_local.rb +2 -1
  49. data/lib/fluent/plugin_helper.rb +1 -0
  50. data/lib/fluent/plugin_helper/compat_parameters.rb +39 -21
  51. data/lib/fluent/plugin_helper/extract.rb +92 -0
  52. data/lib/fluent/plugin_helper/inject.rb +10 -12
  53. data/lib/fluent/plugin_helper/thread.rb +23 -3
  54. data/lib/fluent/registry.rb +1 -1
  55. data/lib/fluent/root_agent.rb +2 -1
  56. data/lib/fluent/supervisor.rb +28 -8
  57. data/lib/fluent/test/base.rb +0 -7
  58. data/lib/fluent/test/driver/base.rb +1 -0
  59. data/lib/fluent/test/driver/output.rb +3 -0
  60. data/lib/fluent/test/helpers.rb +18 -0
  61. data/lib/fluent/test/input_test.rb +4 -2
  62. data/lib/fluent/test/log.rb +3 -1
  63. data/lib/fluent/time.rb +232 -1
  64. data/lib/fluent/timezone.rb +1 -1
  65. data/lib/fluent/version.rb +1 -1
  66. data/test/command/test_binlog_reader.rb +351 -0
  67. data/test/config/test_config_parser.rb +6 -0
  68. data/test/config/test_configurable.rb +47 -1
  69. data/test/helper.rb +0 -1
  70. data/test/plugin/test_buffer.rb +22 -2
  71. data/test/plugin/test_buffer_chunk.rb +34 -4
  72. data/test/plugin/test_buffer_file_chunk.rb +73 -0
  73. data/test/plugin/test_buffer_memory_chunk.rb +73 -0
  74. data/test/plugin/test_compressable.rb +81 -0
  75. data/test/plugin/test_formatter_json.rb +14 -1
  76. data/test/plugin/test_in_forward.rb +67 -3
  77. data/test/plugin/test_in_monitor_agent.rb +17 -1
  78. data/test/plugin/test_in_tail.rb +8 -8
  79. data/test/plugin/test_out_file.rb +0 -8
  80. data/test/plugin/test_out_forward.rb +85 -0
  81. data/test/plugin/test_out_secondary_file.rb +20 -12
  82. data/test/plugin/test_out_stdout.rb +11 -10
  83. data/test/plugin/test_output.rb +234 -0
  84. data/test/plugin/test_output_as_buffered.rb +223 -0
  85. data/test/plugin/test_output_as_buffered_compress.rb +165 -0
  86. data/test/plugin/test_parser_json.rb +8 -0
  87. data/test/plugin/test_parser_regexp.rb +1 -1
  88. data/test/plugin_helper/test_child_process.rb +2 -2
  89. data/test/plugin_helper/test_extract.rb +195 -0
  90. data/test/plugin_helper/test_inject.rb +0 -7
  91. data/test/scripts/fluent/plugin/formatter1/formatter_test1.rb +7 -0
  92. data/test/scripts/fluent/plugin/formatter2/formatter_test2.rb +7 -0
  93. data/test/test_event.rb +186 -0
  94. data/test/test_event_router.rb +1 -1
  95. data/test/test_formatter.rb +0 -7
  96. data/test/test_log.rb +121 -0
  97. data/test/test_plugin_classes.rb +62 -0
  98. data/test/test_root_agent.rb +125 -0
  99. data/test/test_supervisor.rb +25 -2
  100. data/test/test_time_formatter.rb +103 -7
  101. data/test/test_time_parser.rb +211 -0
  102. metadata +23 -4
  103. data/test/plugin/test_parser_time.rb +0 -46
@@ -23,6 +23,7 @@ module Fluent::Plugin
23
23
  helpers :inject, :formatter, :compat_parameters
24
24
 
25
25
  DEFAULT_FORMAT_TYPE = 'json'
26
+ TIME_FORMAT = '%Y-%m-%d %H:%M:%S.%9N %z'
26
27
 
27
28
  config_section :buffer do
28
29
  config_set_default :chunk_keys, ['tag']
@@ -69,7 +70,7 @@ module Fluent::Plugin
69
70
 
70
71
  def format(tag, time, record)
71
72
  record = inject_values_to_record(tag, time, record)
72
- "#{Time.at(time).localtime} #{tag}: #{@formatter.format(tag, time, record).chomp}\n"
73
+ "#{Time.at(time).localtime.strftime(TIME_FORMAT)} #{tag}: #{@formatter.format(tag, time, record).chomp}\n"
73
74
  end
74
75
 
75
76
  def write(chunk)
@@ -36,6 +36,7 @@ module Fluent
36
36
 
37
37
  CHUNK_KEY_PATTERN = /^[-_.@a-zA-Z0-9]+$/
38
38
  CHUNK_KEY_PLACEHOLDER_PATTERN = /\$\{[-_.@a-zA-Z0-9]+\}/
39
+ CHUNK_TAG_PLACEHOLDER_PATTERN = /\$\{(tag(?:\[\d+\])?)\}/
39
40
 
40
41
  CHUNKING_FIELD_WARN_NUM = 4
41
42
 
@@ -74,12 +75,12 @@ module Fluent
74
75
  config_param :retry_max_times, :integer, default: nil, desc: 'The maximum number of times to retry to flush while failing.'
75
76
 
76
77
  config_param :retry_secondary_threshold, :float, default: 0.8, desc: 'ratio of retry_timeout to switch to use secondary while failing.'
77
- # expornential backoff sequence will be initialized at the time of this threshold
78
+ # exponential backoff sequence will be initialized at the time of this threshold
78
79
 
79
80
  desc 'How to wait next retry to flush buffer.'
80
81
  config_param :retry_type, :enum, list: [:exponential_backoff, :periodic], default: :exponential_backoff
81
82
  ### Periodic -> fixed :retry_wait
82
- ### Exponencial backoff: k is number of retry times
83
+ ### Exponential backoff: k is number of retry times
83
84
  # c: constant factor, @retry_wait
84
85
  # b: base factor, @retry_exponential_backoff_base
85
86
  # k: times
@@ -118,6 +119,12 @@ module Fluent
118
119
  raise NotImplementedError, "BUG: output plugins MUST implement this method"
119
120
  end
120
121
 
122
+ def formatted_to_msgpack_binary
123
+ # To indicate custom format method (#format) returns msgpack binary or not.
124
+ # If #format returns msgpack binary, override this method to return true.
125
+ false
126
+ end
127
+
121
128
  def prefer_buffered_processing
122
129
  # override this method to return false only when all of these are true:
123
130
  # * plugin has both implementation for buffered and non-buffered methods
@@ -175,11 +182,13 @@ module Fluent
175
182
  @buffering = true
176
183
  end
177
184
  @custom_format = implement?(:custom_format)
185
+ @enable_msgpack_streamer = false # decided later
178
186
 
179
187
  @buffer = nil
180
188
  @secondary = nil
181
189
  @retry = nil
182
190
  @dequeued_chunks = nil
191
+ @output_enqueue_thread = nil
183
192
  @output_flush_threads = nil
184
193
 
185
194
  @simple_chunking = nil
@@ -326,6 +335,9 @@ module Fluent
326
335
  @buffering = prefer_buffered_processing
327
336
  if !@buffering && @buffer
328
337
  @buffer.terminate # it's not started, so terminate will be enough
338
+ # At here, this plugin works as non-buffered plugin.
339
+ # Un-assign @buffer not to show buffering metrics (e.g., in_monitor_agent)
340
+ @buffer = nil
329
341
  end
330
342
  end
331
343
 
@@ -336,6 +348,7 @@ module Fluent
336
348
  end
337
349
 
338
350
  @custom_format = implement?(:custom_format)
351
+ @enable_msgpack_streamer = @custom_format ? formatted_to_msgpack_binary : true
339
352
  @delayed_commit = if implement?(:buffered) && implement?(:delayed_commit)
340
353
  prefer_delayed_commit
341
354
  else
@@ -355,6 +368,9 @@ module Fluent
355
368
 
356
369
  @buffer.start
357
370
 
371
+ @output_enqueue_thread = nil
372
+ @output_enqueue_thread_running = true
373
+
358
374
  @output_flush_threads = []
359
375
  @output_flush_threads_mutex = Mutex.new
360
376
  @output_flush_threads_running = true
@@ -385,7 +401,7 @@ module Fluent
385
401
 
386
402
  unless @in_tests
387
403
  if @flush_mode == :interval || @chunk_key_time
388
- thread_create(:enqueue_thread, &method(:enqueue_thread_run))
404
+ @output_enqueue_thread = thread_create(:enqueue_thread, &method(:enqueue_thread_run))
389
405
  end
390
406
  end
391
407
  end
@@ -412,6 +428,12 @@ module Fluent
412
428
  force_flush
413
429
  end
414
430
  @buffer.before_shutdown
431
+ # Need to ensure to stop enqueueing ... after #shutdown, we cannot write any data
432
+ @output_enqueue_thread_running = false
433
+ if @output_enqueue_thread && @output_enqueue_thread.alive?
434
+ @output_enqueue_thread.wakeup
435
+ @output_enqueue_thread.join
436
+ end
415
437
  end
416
438
 
417
439
  super
@@ -483,12 +505,146 @@ module Fluent
483
505
  end
484
506
  end
485
507
 
508
+ def placeholder_validate!(name, str)
509
+ placeholder_validators(name, str).each do |v|
510
+ v.validate!
511
+ end
512
+ end
513
+
514
+ def placeholder_validators(name, str, time_key = (@chunk_key_time && @buffer_config.timekey), tag_key = @chunk_key_tag, chunk_keys = @chunk_keys)
515
+ validators = []
516
+
517
+ sec, title, example = get_placeholders_time(str)
518
+ if sec || time_key
519
+ validators << PlaceholderValidator.new(name, str, :time, {sec: sec, title: title, example: example, timekey: time_key})
520
+ end
521
+
522
+ parts = get_placeholders_tag(str)
523
+ if tag_key || !parts.empty?
524
+ validators << PlaceholderValidator.new(name, str, :tag, {parts: parts, tagkey: tag_key})
525
+ end
526
+
527
+ keys = get_placeholders_keys(str)
528
+ if chunk_keys && !chunk_keys.empty? || !keys.empty?
529
+ validators << PlaceholderValidator.new(name, str, :keys, {keys: keys, chunkkeys: chunk_keys})
530
+ end
531
+
532
+ validators
533
+ end
534
+
535
+ class PlaceholderValidator
536
+ attr_reader :name, :string, :type, :argument
537
+
538
+ def initialize(name, str, type, arg)
539
+ @name = name
540
+ @string = str
541
+ @type = type
542
+ raise ArgumentError, "invalid type:#{type}" if @type != :time && @type != :tag && @type != :keys
543
+ @argument = arg
544
+ end
545
+
546
+ def time?
547
+ @type == :time
548
+ end
549
+
550
+ def tag?
551
+ @type == :tag
552
+ end
553
+
554
+ def keys?
555
+ @type == :keys
556
+ end
557
+
558
+ def validate!
559
+ case @type
560
+ when :time then validate_time!
561
+ when :tag then validate_tag!
562
+ when :keys then validate_keys!
563
+ end
564
+ end
565
+
566
+ def validate_time!
567
+ sec = @argument[:sec]
568
+ title = @argument[:title]
569
+ example = @argument[:example]
570
+ timekey = @argument[:timekey]
571
+ if !sec && timekey
572
+ raise Fluent::ConfigError, "Parameter '#{name}' doesn't have timestamp placeholders for timekey #{timekey.to_i}"
573
+ end
574
+ if sec && !timekey
575
+ raise Fluent::ConfigError, "Parameter '#{name}' has timestamp placeholders, but chunk key 'time' is not configured"
576
+ end
577
+ if sec && timekey && timekey < sec
578
+ raise Fluent::ConfigError, "Parameter '#{@name}' doesn't have timestamp placeholder for #{title}('#{example}') for timekey #{timekey.to_i}"
579
+ end
580
+ end
581
+
582
+ def validate_tag!
583
+ parts = @argument[:parts]
584
+ tagkey = @argument[:tagkey]
585
+ if tagkey && parts.empty?
586
+ raise Fluent::ConfigError, "Parameter '#{@name}' doesn't have tag placeholder"
587
+ end
588
+ if !tagkey && !parts.empty?
589
+ raise Fluent::ConfigError, "Parameter '#{@name}' has tag placeholders, but chunk key 'tag' is not configured"
590
+ end
591
+ end
592
+
593
+ def validate_keys!
594
+ keys = @argument[:keys]
595
+ chunk_keys = @argument[:chunkkeys]
596
+ if (chunk_keys - keys).size > 0
597
+ not_specified = (chunk_keys - keys).sort
598
+ raise Fluent::ConfigError, "Parameter '#{@name}' doesn't have enough placeholders for keys #{not_specified.join(',')}"
599
+ end
600
+ if (keys - chunk_keys).size > 0
601
+ not_satisfied = (keys - chunk_keys).sort
602
+ raise Fluent::ConfigError, "Parameter '#{@name}' has placeholders, but chunk keys doesn't have keys #{not_satisfied.join(',')}"
603
+ end
604
+ end
605
+ end
606
+
607
+ TIME_KEY_PLACEHOLDER_THRESHOLDS = [
608
+ [1, :second, '%S'],
609
+ [60, :minute, '%M'],
610
+ [3600, :hour, '%H'],
611
+ [86400, :day, '%d'],
612
+ ]
613
+ TIMESTAMP_CHECK_BASE_TIME = Time.parse("2016-01-01 00:00:00 UTC")
614
+ # it's not validated to use timekey larger than 1 day
615
+ def get_placeholders_time(str)
616
+ base_str = TIMESTAMP_CHECK_BASE_TIME.strftime(str)
617
+ TIME_KEY_PLACEHOLDER_THRESHOLDS.each do |triple|
618
+ sec = triple.first
619
+ return triple if (TIMESTAMP_CHECK_BASE_TIME + sec).strftime(str) != base_str
620
+ end
621
+ nil
622
+ end
623
+
624
+ # -1 means whole tag
625
+ def get_placeholders_tag(str)
626
+ # [["tag"],["tag[0]"]]
627
+ parts = []
628
+ str.scan(CHUNK_TAG_PLACEHOLDER_PATTERN).map(&:first).each do |ph|
629
+ if ph == "tag"
630
+ parts << -1
631
+ elsif ph =~ /^tag\[(\d+)\]$/
632
+ parts << $1.to_i
633
+ end
634
+ end
635
+ parts.sort
636
+ end
637
+
638
+ def get_placeholders_keys(str)
639
+ str.scan(CHUNK_KEY_PLACEHOLDER_PATTERN).map{|ph| ph[2..-2]}.reject{|s| s == "tag"}.sort
640
+ end
641
+
486
642
  # TODO: optimize this code
487
643
  def extract_placeholders(str, metadata)
488
644
  if metadata.empty?
489
645
  str
490
646
  else
491
- rvalue = str
647
+ rvalue = str.dup
492
648
  # strftime formatting
493
649
  if @chunk_key_time # this section MUST be earlier than rest to use raw 'str'
494
650
  @output_time_formatter_cache[str] ||= Fluent::Timezone.formatter(@timekey_zone, str)
@@ -496,14 +652,18 @@ module Fluent
496
652
  end
497
653
  # ${tag}, ${tag[0]}, ${tag[1]}, ...
498
654
  if @chunk_key_tag
499
- if str =~ /\$\{tag\[\d+\]\}/
500
- hash = {'${tag}' => metadata.tag}
655
+ if str.include?('${tag}')
656
+ rvalue = rvalue.gsub('${tag}', metadata.tag)
657
+ end
658
+ if str =~ CHUNK_TAG_PLACEHOLDER_PATTERN
659
+ hash = {}
501
660
  metadata.tag.split('.').each_with_index do |part, i|
502
661
  hash["${tag[#{i}]}"] = part
503
662
  end
504
- rvalue = rvalue.gsub(/\$\{tag(\[\d+\])?\}/, hash)
505
- elsif str.include?('${tag}')
506
- rvalue = rvalue.gsub('${tag}', metadata.tag)
663
+ rvalue = rvalue.gsub(CHUNK_TAG_PLACEHOLDER_PATTERN, hash)
664
+ end
665
+ if rvalue =~ CHUNK_TAG_PLACEHOLDER_PATTERN
666
+ log.warn "tag placeholder '#{$1}' not replaced. tag:#{metadata.tag}, template:#{str}"
507
667
  end
508
668
  end
509
669
  # ${a_chunk_key}, ...
@@ -514,6 +674,9 @@ module Fluent
514
674
  end
515
675
  rvalue = rvalue.gsub(CHUNK_KEY_PLACEHOLDER_PATTERN, hash)
516
676
  end
677
+ if rvalue =~ CHUNK_KEY_PLACEHOLDER_PATTERN
678
+ log.warn "chunk key placeholder '#{$1}' not replaced. templace:#{str}"
679
+ end
517
680
  rvalue
518
681
  end
519
682
  end
@@ -595,6 +758,13 @@ module Fluent
595
758
  end
596
759
  end
597
760
 
761
+ def metadata_for_test(tag, time, record)
762
+ raise "BUG: #metadata_for_test is available only when no actual metadata exists" unless @buffer.metadata_list.empty?
763
+ m = metadata(tag, time, record)
764
+ @buffer.metadata_list_clear!
765
+ m
766
+ end
767
+
598
768
  def execute_chunking(tag, es, enqueue: false)
599
769
  if @simple_chunking
600
770
  handle_stream_simple(tag, es, enqueue: enqueue)
@@ -641,7 +811,17 @@ module Fluent
641
811
  end
642
812
 
643
813
  FORMAT_MSGPACK_STREAM = ->(e){ e.to_msgpack_stream }
814
+ FORMAT_COMPRESSED_MSGPACK_STREAM = ->(e){ e.to_compressed_msgpack_stream }
644
815
  FORMAT_MSGPACK_STREAM_TIME_INT = ->(e){ e.to_msgpack_stream(time_int: true) }
816
+ FORMAT_COMPRESSED_MSGPACK_STREAM_TIME_INT = ->(e){ e.to_compressed_msgpack_stream(time_int: true) }
817
+
818
+ def generate_format_proc
819
+ if @buffer && @buffer.compress == :gzip
820
+ @time_as_integer ? FORMAT_COMPRESSED_MSGPACK_STREAM_TIME_INT : FORMAT_COMPRESSED_MSGPACK_STREAM
821
+ else
822
+ @time_as_integer ? FORMAT_MSGPACK_STREAM_TIME_INT : FORMAT_MSGPACK_STREAM
823
+ end
824
+ end
645
825
 
646
826
  # metadata_and_data is a Hash of:
647
827
  # (standard format) metadata => event stream
@@ -651,7 +831,7 @@ module Fluent
651
831
  # `@buffer.write` will do this splitting.
652
832
  # For custom format, formatting will be done here. Custom formatting always requires
653
833
  # iteration of event stream, and it should be done just once even if total event stream size
654
- # is biggar than chunk_limit_size because of performance.
834
+ # is bigger than chunk_limit_size because of performance.
655
835
  def handle_stream_with_custom_format(tag, es, enqueue: false)
656
836
  meta_and_data = {}
657
837
  records = 0
@@ -669,7 +849,7 @@ module Fluent
669
849
  end
670
850
 
671
851
  def handle_stream_with_standard_format(tag, es, enqueue: false)
672
- format_proc = @time_as_integer ? FORMAT_MSGPACK_STREAM_TIME_INT : FORMAT_MSGPACK_STREAM
852
+ format_proc = generate_format_proc
673
853
  meta_and_data = {}
674
854
  records = 0
675
855
  es.each do |time, record|
@@ -697,7 +877,7 @@ module Fluent
697
877
  records += 1
698
878
  end
699
879
  else
700
- format_proc = @time_as_integer ? FORMAT_MSGPACK_STREAM_TIME_INT : FORMAT_MSGPACK_STREAM
880
+ format_proc = generate_format_proc
701
881
  data = es
702
882
  end
703
883
  write_guard do
@@ -793,7 +973,7 @@ module Fluent
793
973
  using_secondary = true
794
974
  end
795
975
 
796
- unless @custom_format
976
+ if @enable_msgpack_streamer
797
977
  chunk.extend ChunkMessagePackEventStreamer
798
978
  end
799
979
 
@@ -821,6 +1001,10 @@ module Fluent
821
1001
  log.debug "taking back chunk for errors.", plugin_id: plugin_id, chunk: dump_unique_id_hex(chunk.unique_id)
822
1002
  @buffer.takeback_chunk(chunk.unique_id)
823
1003
 
1004
+ if @under_plugin_development
1005
+ raise
1006
+ end
1007
+
824
1008
  @retry_mutex.synchronize do
825
1009
  if @retry
826
1010
  @counters_monitor.synchronize{ @num_errors += 1 }
@@ -941,7 +1125,7 @@ module Fluent
941
1125
  log.debug "enqueue_thread actually running"
942
1126
 
943
1127
  begin
944
- while @output_flush_threads_running
1128
+ while @output_enqueue_thread_running
945
1129
  now_int = Time.now.to_i
946
1130
  if @output_flush_interrupted
947
1131
  sleep interval
@@ -965,16 +1149,18 @@ module Fluent
965
1149
  @buffer.enqueue_all{ |metadata, chunk| metadata.timekey < current_timekey && metadata.timekey + timekey_unit + timekey_wait <= now_int }
966
1150
  end
967
1151
  rescue => e
968
- log.error "unexpected error while checking flushed chunks. ignored.", plugin_id: plugin_id, error_class: e.class, error: e
1152
+ raise if @under_plugin_development
1153
+ log.error "unexpected error while checking flushed chunks. ignored.", plugin_id: plugin_id, error: e
969
1154
  log.error_backtrace
1155
+ ensure
1156
+ @output_enqueue_thread_waiting = false
1157
+ @output_enqueue_thread_mutex.unlock
970
1158
  end
971
- @output_enqueue_thread_waiting = false
972
- @output_enqueue_thread_mutex.unlock
973
1159
  sleep interval
974
1160
  end
975
1161
  rescue => e
976
1162
  # normal errors are rescued by inner begin-rescue clause.
977
- log.error "error on enqueue thread", plugin_id: plugin_id, error_class: e.class, error: e
1163
+ log.error "error on enqueue thread", plugin_id: plugin_id, error: e
978
1164
  log.error_backtrace
979
1165
  raise
980
1166
  end
@@ -1003,7 +1189,7 @@ module Fluent
1003
1189
  # next_flush_interval uses flush_thread_interval or flush_thread_burst_interval (or retrying)
1004
1190
  interval = next_flush_time.to_f - Time.now.to_f
1005
1191
  # TODO: if secondary && delayed-commit, next_flush_time will be much longer than expected (because @retry still exists)
1006
- # @retry should be cleard if delayed commit is enabled? Or any other solution?
1192
+ # @retry should be cleared if delayed commit is enabled? Or any other solution?
1007
1193
  state.next_time = Process.clock_gettime(clock_id) + interval
1008
1194
  end
1009
1195
 
@@ -21,12 +21,11 @@ require 'fluent/mixin' # for TypeConverter
21
21
  require 'fluent/time'
22
22
  require 'fluent/plugin/string_util'
23
23
 
24
- require 'strptime'
25
-
26
24
  module Fluent
27
25
  module Plugin
28
26
  class Parser < Base
29
27
  include OwnedByMixin
28
+ include TimeMixin::Parser
30
29
 
31
30
  class ParserError < StandardError; end
32
31
 
@@ -52,49 +51,7 @@ module Fluent
52
51
  parse(*a, &b)
53
52
  end
54
53
 
55
- class TimeParser
56
- def initialize(time_format)
57
- @cache1_key = nil
58
- @cache1_time = nil
59
- @cache2_key = nil
60
- @cache2_time = nil
61
- @parser =
62
- if time_format
63
- begin
64
- strptime = Strptime.new(time_format)
65
- Proc.new { |value| Fluent::EventTime.from_time(strptime.exec(value)) }
66
- rescue
67
- Proc.new { |value| Fluent::EventTime.from_time(Time.strptime(value, time_format)) }
68
- end
69
- else
70
- Proc.new { |value| Fluent::EventTime.parse(value) }
71
- end
72
- end
73
-
74
- # TODO: new cache mechanism using format string
75
- def parse(value)
76
- unless value.is_a?(String)
77
- raise ParserError, "value must be string: #{value}"
78
- end
79
-
80
- if @cache1_key == value
81
- return @cache1_time
82
- elsif @cache2_key == value
83
- return @cache2_time
84
- else
85
- begin
86
- time = @parser.call(value)
87
- rescue => e
88
- raise ParserError, "invalid time format: value = #{value}, error_class = #{e.class.name}, error = #{e.message}"
89
- end
90
- @cache1_key = @cache2_key
91
- @cache1_time = @cache2_time
92
- @cache2_key = value
93
- @cache2_time = time
94
- return time
95
- end
96
- end
97
- end
54
+ TimeParser = Fluent::TimeParser
98
55
  end
99
56
 
100
57
  class ValuesParser < Parser
@@ -102,7 +59,6 @@ module Fluent
102
59
 
103
60
  config_param :keys, :array, default: []
104
61
  config_param :time_key, :string, default: nil
105
- config_param :time_format, :string, default: nil
106
62
  config_param :null_value_pattern, :string, default: nil
107
63
  config_param :null_empty_string, :bool, default: false
108
64
 
@@ -110,14 +66,14 @@ module Fluent
110
66
  super
111
67
 
112
68
  if @time_key && !@keys.include?(@time_key) && @estimate_current_event
113
- raise ConfigError, "time_key (#{@time_key.inspect}) is not included in keys (#{@keys.inspect})"
69
+ raise Fluent::ConfigError, "time_key (#{@time_key.inspect}) is not included in keys (#{@keys.inspect})"
114
70
  end
115
71
 
116
72
  if @time_format && !@time_key
117
- raise ConfigError, "time_format parameter is ignored because time_key parameter is not set. at #{conf.inspect}"
73
+ raise Fluent::ConfigError, "time_format parameter is ignored because time_key parameter is not set. at #{conf.inspect}"
118
74
  end
119
75
 
120
- @time_parser = TimeParser.new(@time_format)
76
+ @time_parser = time_parser_create
121
77
 
122
78
  if @null_value_pattern
123
79
  @null_value_pattern = Regexp.new(@null_value_pattern)