fluentd 0.10.38 → 0.10.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of fluentd might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +4 -0
- data/ChangeLog +10 -0
- data/Rakefile +7 -0
- data/fluentd.gemspec +1 -0
- data/lib/fluent/buffer.rb +8 -4
- data/lib/fluent/command/fluentd.rb +4 -0
- data/lib/fluent/config_dsl.rb +46 -33
- data/lib/fluent/engine.rb +10 -2
- data/lib/fluent/event.rb +17 -0
- data/lib/fluent/output.rb +12 -0
- data/lib/fluent/parser.rb +71 -12
- data/lib/fluent/plugin/buf_file.rb +5 -2
- data/lib/fluent/plugin/in_tail.rb +7 -5
- data/lib/fluent/plugin/out_copy.rb +9 -1
- data/lib/fluent/plugin/out_file.rb +2 -7
- data/lib/fluent/supervisor.rb +14 -1
- data/lib/fluent/version.rb +1 -1
- data/test/config.rb +1 -1
- data/test/configdsl.rb +32 -2
- data/test/helper.rb +5 -2
- data/test/parser.rb +58 -1
- data/test/plugin/in_forward.rb +5 -4
- data/test/plugin/in_http.rb +6 -4
- data/test/plugin/in_stream.rb +6 -6
- data/test/plugin/in_syslog.rb +6 -5
- data/test/plugin/in_tail.rb +1 -1
- data/test/plugin/out_copy.rb +78 -0
- data/test/plugin/out_exec.rb +1 -1
- data/test/plugin/out_file.rb +24 -12
- data/test/plugin/out_stream.rb +5 -4
- metadata +16 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 14f93577d21ab248d08466b142442d503ba9ad55
         | 
| 4 | 
            +
              data.tar.gz: 9036d89bf55c57a454120dc766c3da6fe445fbf8
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 5c4ae2365e4e3a59cc22e7089203ea57b3cf7bc89d759915e4f02b795312903116484dd65f43a7e07ed9e98a1da13f5e1aa6112a0448d03706e4171cd3dad63a
         | 
| 7 | 
            +
              data.tar.gz: 806d690bccc9674f2bd45d693eb523a07e06d0aa4e2dc63e42396421d34ce8f27977bba119b0e5470d8844ee62c140cd1cf8c4bff1b8ce2aa16bd8d40e7fb419
         | 
    
        data/.travis.yml
    CHANGED
    
    
    
        data/ChangeLog
    CHANGED
    
    | @@ -1,3 +1,13 @@ | |
| 1 | 
            +
            Release 0.10.39 - 2013/09/18
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            * out_file: Improve symlink handling with buf_file
         | 
| 4 | 
            +
            * out_copy: Add deep_copy parameter for actual record copy
         | 
| 5 | 
            +
            * in_tail/parser: Add none format for supporting non-parse tailing like fluent-agent-lite
         | 
| 6 | 
            +
            * in_tail/parser: Improve performance using parsed time caching
         | 
| 7 | 
            +
            * Engine: Fix signal related exception in trap context at Ruby 2.0
         | 
| 8 | 
            +
            * buffer: Fix race condition when remove flushed chunk
         | 
| 9 | 
            +
            * add --suppress-config-dump option to disable dump configuration at start
         | 
| 10 | 
            +
             | 
| 1 11 | 
             
            Release 0.10.38 - 2013/08/29
         | 
| 2 12 |  | 
| 3 13 | 
             
            * Fix require related problem in running test
         | 
    
        data/Rakefile
    CHANGED
    
    | @@ -1,6 +1,7 @@ | |
| 1 1 | 
             
            #!/usr/bin/env rake
         | 
| 2 2 | 
             
            require "bundler/gem_tasks"
         | 
| 3 3 |  | 
| 4 | 
            +
            require 'fileutils'
         | 
| 4 5 | 
             
            require 'rake/testtask'
         | 
| 5 6 | 
             
            require 'rake/clean'
         | 
| 6 7 |  | 
| @@ -13,4 +14,10 @@ Rake::TestTask.new(:base_test) do |t| | |
| 13 14 | 
             
              #t.warning = true
         | 
| 14 15 | 
             
            end
         | 
| 15 16 |  | 
| 17 | 
            +
            task :parallel_test do
         | 
| 18 | 
            +
              FileUtils.rm_rf('./test/tmp')
         | 
| 19 | 
            +
              sh("parallel_test ./test/*.rb ./test/plugin/*.rb")
         | 
| 20 | 
            +
              FileUtils.rm_rf('./test/tmp')
         | 
| 21 | 
            +
            end
         | 
| 22 | 
            +
             | 
| 16 23 | 
             
            task :default => [:test, :build]
         | 
    
        data/fluentd.gemspec
    CHANGED
    
    | @@ -25,6 +25,7 @@ Gem::Specification.new do |gem| | |
| 25 25 | 
             
              gem.add_runtime_dependency(%q<http_parser.rb>, ["~> 0.5.1"])
         | 
| 26 26 |  | 
| 27 27 | 
             
              gem.add_development_dependency(%q<rake>, [">= 0.9.2"])
         | 
| 28 | 
            +
              gem.add_development_dependency(%q<parallel_tests>, [">= 0.15.3"])
         | 
| 28 29 | 
             
              gem.add_development_dependency(%q<rr>, [">= 1.0.0"])
         | 
| 29 30 | 
             
              gem.add_development_dependency(%q<timecop>, [">= 0.3.0"])
         | 
| 30 31 | 
             
            end
         | 
    
        data/lib/fluent/buffer.rb
    CHANGED
    
    | @@ -272,13 +272,17 @@ module Fluent | |
| 272 272 | 
             
                      write_chunk(chunk, out)
         | 
| 273 273 | 
             
                    end
         | 
| 274 274 |  | 
| 275 | 
            -
                     | 
| 276 | 
            -
             | 
| 277 | 
            -
             | 
| 275 | 
            +
                    empty = false
         | 
| 276 | 
            +
                    @queue.synchronize do
         | 
| 277 | 
            +
                      @queue.delete_if {|c|
         | 
| 278 | 
            +
                        c.object_id == chunk.object_id
         | 
| 279 | 
            +
                      }
         | 
| 280 | 
            +
                      empty = @queue.empty?
         | 
| 281 | 
            +
                    end
         | 
| 278 282 |  | 
| 279 283 | 
             
                    chunk.purge
         | 
| 280 284 |  | 
| 281 | 
            -
                    return  | 
| 285 | 
            +
                    return !empty
         | 
| 282 286 | 
             
                  ensure
         | 
| 283 287 | 
             
                    chunk.mon_exit
         | 
| 284 288 | 
             
                  end
         | 
| @@ -98,6 +98,10 @@ op.on('-q', '--quiet', "decrease verbose level (-q: warn, -qq: error)", TrueClas | |
| 98 98 | 
             
              end
         | 
| 99 99 | 
             
            }
         | 
| 100 100 |  | 
| 101 | 
            +
            op.on('--suppress-config-dump', "suppress config dumping when fluentd starts", TrueClass) {|b|
         | 
| 102 | 
            +
              opts[:suppress_config_dump] = b
         | 
| 103 | 
            +
            }
         | 
| 104 | 
            +
             | 
| 101 105 | 
             
            (class<<self;self;end).module_eval do
         | 
| 102 106 | 
             
              define_method(:usage) do |msg|
         | 
| 103 107 | 
             
                puts op.to_s
         | 
    
        data/lib/fluent/config_dsl.rb
    CHANGED
    
    | @@ -3,7 +3,7 @@ require 'fluent/config' | |
| 3 3 | 
             
            module Fluent
         | 
| 4 4 | 
             
              module Config
         | 
| 5 5 | 
             
                module DSL
         | 
| 6 | 
            -
                  module  | 
| 6 | 
            +
                  module Parser
         | 
| 7 7 | 
             
                    def self.read(path)
         | 
| 8 8 | 
             
                      path = File.expand_path(path)
         | 
| 9 9 | 
             
                      data = File.read(path)
         | 
| @@ -11,62 +11,75 @@ module Fluent | |
| 11 11 | 
             
                    end
         | 
| 12 12 |  | 
| 13 13 | 
             
                    def self.parse(source, source_path="config.rb")
         | 
| 14 | 
            -
                       | 
| 14 | 
            +
                      Proxy.new('ROOT', nil).eval(source, source_path).to_config_element
         | 
| 15 15 | 
             
                    end
         | 
| 16 16 | 
             
                  end
         | 
| 17 17 |  | 
| 18 | 
            -
                  class  | 
| 18 | 
            +
                  class Proxy
         | 
| 19 19 | 
             
                    def initialize(name, arg)
         | 
| 20 | 
            -
                      @ | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 20 | 
            +
                      @element = Element.new(name, arg, self)
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                    def element
         | 
| 24 | 
            +
                      @element
         | 
| 24 25 | 
             
                    end
         | 
| 25 26 |  | 
| 26 | 
            -
                    def  | 
| 27 | 
            -
                      instance_eval(source, source_path)
         | 
| 27 | 
            +
                    def eval(source, source_path)
         | 
| 28 | 
            +
                      @element.instance_eval(source, source_path)
         | 
| 28 29 | 
             
                      self
         | 
| 29 30 | 
             
                    end
         | 
| 30 31 |  | 
| 31 | 
            -
                    def  | 
| 32 | 
            -
                       | 
| 32 | 
            +
                    def to_config_element
         | 
| 33 | 
            +
                      @element.instance_eval do
         | 
| 34 | 
            +
                        Config::Element.new(@name, @arg, @attrs, @elements)
         | 
| 35 | 
            +
                      end
         | 
| 36 | 
            +
                    end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                    def add_element(name, arg, block)
         | 
| 39 | 
            +
                      ::Kernel.raise ::ArgumentError, "#{name} block must be specified" if block.nil?
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                      proxy = self.class.new(name.to_s, arg)
         | 
| 42 | 
            +
                      proxy.element.instance_exec(&block)
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                      @element.instance_eval do
         | 
| 45 | 
            +
                        @elements.push(proxy.to_config_element)
         | 
| 46 | 
            +
                      end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                      self
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  class Element < BasicObject
         | 
| 53 | 
            +
                    def initialize(name, arg, proxy)
         | 
| 54 | 
            +
                      @name     = name
         | 
| 55 | 
            +
                      @arg      = arg || ''
         | 
| 56 | 
            +
                      @attrs    = {}
         | 
| 57 | 
            +
                      @elements = []
         | 
| 58 | 
            +
                      @proxy    = proxy
         | 
| 33 59 | 
             
                    end
         | 
| 34 60 |  | 
| 35 61 | 
             
                    def method_missing(name, *args, &block)
         | 
| 36 | 
            -
                      raise ArgumentError, "Configuration DSL Syntax Error: only one argument allowed" if args.size > 1
         | 
| 62 | 
            +
                      ::Kernel.raise ::ArgumentError, "Configuration DSL Syntax Error: only one argument allowed" if args.size > 1
         | 
| 37 63 | 
             
                      value = args.first
         | 
| 64 | 
            +
             | 
| 38 65 | 
             
                      if block
         | 
| 39 | 
            -
                         | 
| 40 | 
            -
                        element.instance_exec(&block)
         | 
| 41 | 
            -
                        @elements.push( | 
| 66 | 
            +
                        proxy = Proxy.new(name.to_s, value)
         | 
| 67 | 
            +
                        proxy.element.instance_exec(&block)
         | 
| 68 | 
            +
                        @elements.push(proxy.to_config_element)
         | 
| 42 69 | 
             
                      else
         | 
| 43 | 
            -
                        # @attrs[name.to_s] = value.is_a?(::Symbol) ? value.to_s : value
         | 
| 44 70 | 
             
                        @attrs[name.to_s] = value.to_s
         | 
| 45 71 | 
             
                      end
         | 
| 72 | 
            +
             | 
| 46 73 | 
             
                      self
         | 
| 47 74 | 
             
                    end
         | 
| 48 75 |  | 
| 49 76 | 
             
                    def source(&block)
         | 
| 50 | 
            -
                       | 
| 77 | 
            +
                      @proxy.add_element('source', nil, block)
         | 
| 51 78 | 
             
                    end
         | 
| 52 79 |  | 
| 53 80 | 
             
                    def match(*args, &block)
         | 
| 54 | 
            -
                       | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
                    private
         | 
| 58 | 
            -
             | 
| 59 | 
            -
                    def __element(name, arg, block)
         | 
| 60 | 
            -
                      raise ArgumentError, "#{name} block must be specified" if block.nil?
         | 
| 61 | 
            -
                      element = DSLElement.new(name.to_s, arg)
         | 
| 62 | 
            -
                      element.instance_exec(&block)
         | 
| 63 | 
            -
                      @elements.push(element.__to_config_element)
         | 
| 64 | 
            -
                      self
         | 
| 65 | 
            -
                    end
         | 
| 66 | 
            -
             | 
| 67 | 
            -
                    def __need_arg(name, args)
         | 
| 68 | 
            -
                      raise ArgumentError, "#{name} block requires arguments for match pattern" if args.nil? || args.size != 1
         | 
| 69 | 
            -
                      true
         | 
| 81 | 
            +
                      ::Kernel.raise ::ArgumentError, "#{name} block requires arguments for match pattern" if args.nil? || args.size != 1
         | 
| 82 | 
            +
                      @proxy.add_element('match', args.first, block)
         | 
| 70 83 | 
             
                    end
         | 
| 71 84 | 
             
                  end
         | 
| 72 85 | 
             
                end
         | 
    
        data/lib/fluent/engine.rb
    CHANGED
    
    | @@ -31,6 +31,8 @@ module Fluent | |
| 31 31 |  | 
| 32 32 | 
             
                  @suppress_emit_error_log_interval = 0
         | 
| 33 33 | 
             
                  @next_emit_error_log_time = nil
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  @suppress_config_dump = false
         | 
| 34 36 | 
             
                end
         | 
| 35 37 |  | 
| 36 38 | 
             
                MATCH_CACHE_SIZE = 1024
         | 
| @@ -54,6 +56,10 @@ module Fluent | |
| 54 56 | 
             
                  @next_emit_error_log_time = Time.now.to_i
         | 
| 55 57 | 
             
                end
         | 
| 56 58 |  | 
| 59 | 
            +
                def suppress_config_dump=(flag)
         | 
| 60 | 
            +
                  @suppress_config_dump = flag
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 57 63 | 
             
                def read_config(path)
         | 
| 58 64 | 
             
                  $log.info "reading config file", :path=>path
         | 
| 59 65 | 
             
                  File.open(path) {|io|
         | 
| @@ -63,7 +69,7 @@ module Fluent | |
| 63 69 |  | 
| 64 70 | 
             
                def parse_config(io, fname, basepath=Dir.pwd)
         | 
| 65 71 | 
             
                  conf = if fname =~ /\.rb$/
         | 
| 66 | 
            -
                           Config::DSL:: | 
| 72 | 
            +
                           Config::DSL::Parser.parse(io, File.join(basepath, fname))
         | 
| 67 73 | 
             
                         else
         | 
| 68 74 | 
             
                           Config.parse(io, fname, basepath)
         | 
| 69 75 | 
             
                         end
         | 
| @@ -74,7 +80,9 @@ module Fluent | |
| 74 80 | 
             
                end
         | 
| 75 81 |  | 
| 76 82 | 
             
                def configure(conf)
         | 
| 77 | 
            -
                   | 
| 83 | 
            +
                  unless @suppress_config_dump
         | 
| 84 | 
            +
                    $log.info "using configuration file: #{conf.to_s.rstrip}"
         | 
| 85 | 
            +
                  end
         | 
| 78 86 |  | 
| 79 87 | 
             
                  conf.elements.select {|e|
         | 
| 80 88 | 
             
                    e.name == 'source'
         | 
    
        data/lib/fluent/event.rb
    CHANGED
    
    | @@ -42,6 +42,10 @@ module Fluent | |
| 42 42 | 
             
                  @record = record
         | 
| 43 43 | 
             
                end
         | 
| 44 44 |  | 
| 45 | 
            +
                def dup
         | 
| 46 | 
            +
                  OneEventStream.new(@time, @record.dup)
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 45 49 | 
             
                def repeatable?
         | 
| 46 50 | 
             
                  true
         | 
| 47 51 | 
             
                end
         | 
| @@ -58,6 +62,11 @@ module Fluent | |
| 58 62 | 
             
                  @entries = entries
         | 
| 59 63 | 
             
                end
         | 
| 60 64 |  | 
| 65 | 
            +
                def dup
         | 
| 66 | 
            +
                  entries = @entries.map(:dup)
         | 
| 67 | 
            +
                  ArrayEventStream.new(entries)
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 61 70 | 
             
                def repeatable?
         | 
| 62 71 | 
             
                  true
         | 
| 63 72 | 
             
                end
         | 
| @@ -85,6 +94,14 @@ module Fluent | |
| 85 94 | 
             
                  @record_array = []
         | 
| 86 95 | 
             
                end
         | 
| 87 96 |  | 
| 97 | 
            +
                def dup
         | 
| 98 | 
            +
                  es = MultiEventStream.new
         | 
| 99 | 
            +
                  @time_array.zip(@record_array).each { |time, record|
         | 
| 100 | 
            +
                    es.add(time, record.dup)
         | 
| 101 | 
            +
                  }
         | 
| 102 | 
            +
                  es
         | 
| 103 | 
            +
                end
         | 
| 104 | 
            +
             | 
| 88 105 | 
             
                def add(time, record)
         | 
| 89 106 | 
             
                  @time_array << time
         | 
| 90 107 | 
             
                  @record_array << record
         | 
    
        data/lib/fluent/output.rb
    CHANGED
    
    | @@ -35,6 +35,18 @@ module Fluent | |
| 35 35 | 
             
                end
         | 
| 36 36 | 
             
              end
         | 
| 37 37 |  | 
| 38 | 
            +
              class CopyOutputChain < OutputChain
         | 
| 39 | 
            +
                def next
         | 
| 40 | 
            +
                  if @array.length <= @offset
         | 
| 41 | 
            +
                    return @chain.next
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
                  @offset += 1
         | 
| 44 | 
            +
                  es = @array.length > @offset ? @es.dup : @es
         | 
| 45 | 
            +
                  result = @array[@offset-1].emit(@tag, es, self)
         | 
| 46 | 
            +
                  result
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
             | 
| 38 50 | 
             
              class NullOutputChain
         | 
| 39 51 | 
             
                require 'singleton'
         | 
| 40 52 | 
             
                include Singleton
         | 
    
        data/lib/fluent/parser.rb
    CHANGED
    
    | @@ -17,6 +17,40 @@ | |
| 17 17 | 
             
            #
         | 
| 18 18 | 
             
            module Fluent
         | 
| 19 19 | 
             
              class TextParser
         | 
| 20 | 
            +
                class TimeParser
         | 
| 21 | 
            +
                  def initialize(time_format)
         | 
| 22 | 
            +
                    @cache1_key = nil
         | 
| 23 | 
            +
                    @cache1_time = nil
         | 
| 24 | 
            +
                    @cache2_key = nil
         | 
| 25 | 
            +
                    @cache2_time = nil
         | 
| 26 | 
            +
                    @parser =
         | 
| 27 | 
            +
                      if time_format
         | 
| 28 | 
            +
                        Proc.new { |value| Time.strptime(value, time_format) }
         | 
| 29 | 
            +
                      else
         | 
| 30 | 
            +
                        Time.method(:parse)
         | 
| 31 | 
            +
                      end
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  def parse(value)
         | 
| 35 | 
            +
                    unless value.is_a?(String)
         | 
| 36 | 
            +
                      raise ArgumentError, "Value must be string: #{value}"
         | 
| 37 | 
            +
                    end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                    if @cache1_key == value
         | 
| 40 | 
            +
                      return @cache1_time
         | 
| 41 | 
            +
                    elsif @cache2_key == value
         | 
| 42 | 
            +
                      return @cache2_time
         | 
| 43 | 
            +
                    else
         | 
| 44 | 
            +
                      time = @parser.call(value).to_i
         | 
| 45 | 
            +
                      @cache1_key = @cache2_key
         | 
| 46 | 
            +
                      @cache1_time = @cache2_time
         | 
| 47 | 
            +
                      @cache2_key = value
         | 
| 48 | 
            +
                      @cache2_time = time
         | 
| 49 | 
            +
                      return time
         | 
| 50 | 
            +
                    end
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 20 54 | 
             
                class RegexpParser
         | 
| 21 55 | 
             
                  include Configurable
         | 
| 22 56 |  | 
| @@ -28,6 +62,9 @@ module Fluent | |
| 28 62 | 
             
                    unless conf.empty?
         | 
| 29 63 | 
             
                      configure(conf)
         | 
| 30 64 | 
             
                    end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                    @time_parser = TimeParser.new(@time_format)
         | 
| 67 | 
            +
                    @mutex = Mutex.new
         | 
| 31 68 | 
             
                  end
         | 
| 32 69 |  | 
| 33 70 | 
             
                  def call(text)
         | 
| @@ -44,11 +81,7 @@ module Fluent | |
| 44 81 | 
             
                      if value = m[name]
         | 
| 45 82 | 
             
                        case name
         | 
| 46 83 | 
             
                        when "time"
         | 
| 47 | 
            -
                           | 
| 48 | 
            -
                            time = Time.strptime(value, @time_format).to_i
         | 
| 49 | 
            -
                          else
         | 
| 50 | 
            -
                            time = Time.parse(value).to_i
         | 
| 51 | 
            -
                          end
         | 
| 84 | 
            +
                          time = @mutex.synchronize { @time_parser.parse(value) }
         | 
| 52 85 | 
             
                        else
         | 
| 53 86 | 
             
                          record[name] = value
         | 
| 54 87 | 
             
                        end
         | 
| @@ -67,12 +100,21 @@ module Fluent | |
| 67 100 | 
             
                  config_param :time_key, :string, :default => 'time'
         | 
| 68 101 | 
             
                  config_param :time_format, :string, :default => nil
         | 
| 69 102 |  | 
| 103 | 
            +
                  def configure(conf)
         | 
| 104 | 
            +
                    super
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                    unless @time_format.nil?
         | 
| 107 | 
            +
                      @time_parser = TimeParser.new(@time_format)
         | 
| 108 | 
            +
                      @mutex = Mutex.new
         | 
| 109 | 
            +
                    end
         | 
| 110 | 
            +
                  end
         | 
| 111 | 
            +
             | 
| 70 112 | 
             
                  def call(text)
         | 
| 71 113 | 
             
                    record = Yajl.load(text)
         | 
| 72 114 |  | 
| 73 115 | 
             
                    if value = record.delete(@time_key)
         | 
| 74 116 | 
             
                      if @time_format
         | 
| 75 | 
            -
                        time =  | 
| 117 | 
            +
                        time = @mutex.synchronize { @time_parser.parse(value) }
         | 
| 76 118 | 
             
                      else
         | 
| 77 119 | 
             
                        time = value.to_i
         | 
| 78 120 | 
             
                      end
         | 
| @@ -106,6 +148,9 @@ module Fluent | |
| 106 148 | 
             
                    if @time_format && !@time_key
         | 
| 107 149 | 
             
                      raise ConfigError, "time_format parameter is ignored because time_key parameter is not set. at #{conf.inspect}"
         | 
| 108 150 | 
             
                    end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                    @time_parser = TimeParser.new(@time_format)
         | 
| 153 | 
            +
                    @mutex = Mutex.new
         | 
| 109 154 | 
             
                  end
         | 
| 110 155 |  | 
| 111 156 | 
             
                  def values_map(values)
         | 
| @@ -113,11 +158,7 @@ module Fluent | |
| 113 158 |  | 
| 114 159 | 
             
                    if @time_key
         | 
| 115 160 | 
             
                      value = record.delete(@time_key)
         | 
| 116 | 
            -
                       | 
| 117 | 
            -
                        time = Time.strptime(value, @time_format).to_i
         | 
| 118 | 
            -
                      else
         | 
| 119 | 
            -
                        time = Time.parse(value).to_i
         | 
| 120 | 
            -
                      end
         | 
| 161 | 
            +
                      time = @mutex.synchronize { @time_parser.parse(value) }
         | 
| 121 162 | 
             
                    else
         | 
| 122 163 | 
             
                      time = Engine.now
         | 
| 123 164 | 
             
                    end
         | 
| @@ -169,11 +210,28 @@ module Fluent | |
| 169 210 | 
             
                  end
         | 
| 170 211 | 
             
                end
         | 
| 171 212 |  | 
| 213 | 
            +
                class NoneParser
         | 
| 214 | 
            +
                  include Configurable
         | 
| 215 | 
            +
             | 
| 216 | 
            +
                  config_param :message_key, :string, :default => 'message'
         | 
| 217 | 
            +
             | 
| 218 | 
            +
                  def call(text)
         | 
| 219 | 
            +
                    record = {}
         | 
| 220 | 
            +
                    record[@message_key] = text
         | 
| 221 | 
            +
                    return Engine.now, record
         | 
| 222 | 
            +
                  end
         | 
| 223 | 
            +
                end
         | 
| 224 | 
            +
             | 
| 172 225 | 
             
                class ApacheParser
         | 
| 173 226 | 
             
                  include Configurable
         | 
| 174 227 |  | 
| 175 228 | 
             
                  REGEXP = /^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$/
         | 
| 176 229 |  | 
| 230 | 
            +
                  def initialize
         | 
| 231 | 
            +
                    @time_parser = TimeParser.new("%d/%b/%Y:%H:%M:%S %z")
         | 
| 232 | 
            +
                    @mutex = Mutex.new
         | 
| 233 | 
            +
                  end
         | 
| 234 | 
            +
             | 
| 177 235 | 
             
                  def call(text)
         | 
| 178 236 | 
             
                    m = REGEXP.match(text)
         | 
| 179 237 | 
             
                    unless m
         | 
| @@ -188,7 +246,7 @@ module Fluent | |
| 188 246 | 
             
                    user = (user == '-') ? nil : user
         | 
| 189 247 |  | 
| 190 248 | 
             
                    time = m['time']
         | 
| 191 | 
            -
                    time =  | 
| 249 | 
            +
                    time = @mutex.synchronize { @time_parser.parse(time) }
         | 
| 192 250 |  | 
| 193 251 | 
             
                    method = m['method']
         | 
| 194 252 | 
             
                    path = m['path']
         | 
| @@ -229,6 +287,7 @@ module Fluent | |
| 229 287 | 
             
                  'ltsv' => Proc.new { LabeledTSVParser.new },
         | 
| 230 288 | 
             
                  'csv' => Proc.new { CSVParser.new },
         | 
| 231 289 | 
             
                  'nginx' => Proc.new { RegexpParser.new(/^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$/,  {'time_format'=>"%d/%b/%Y:%H:%M:%S %z"}) },
         | 
| 290 | 
            +
                  'none' => Proc.new { NoneParser.new },
         | 
| 232 291 | 
             
                }
         | 
| 233 292 |  | 
| 234 293 | 
             
                def self.register_template(name, regexp_or_proc, time_format=nil)
         | 
| @@ -17,13 +17,14 @@ | |
| 17 17 | 
             
            #
         | 
| 18 18 | 
             
            module Fluent
         | 
| 19 19 | 
             
              class FileBufferChunk < BufferChunk
         | 
| 20 | 
            -
                def initialize(key, path, unique_id, mode="a+")
         | 
| 20 | 
            +
                def initialize(key, path, unique_id, mode="a+", symlink_path = nil)
         | 
| 21 21 | 
             
                  super(key)
         | 
| 22 22 | 
             
                  @path = path
         | 
| 23 23 | 
             
                  @unique_id = unique_id
         | 
| 24 24 | 
             
                  @file = File.open(@path, mode, DEFAULT_FILE_PERMISSION)
         | 
| 25 25 | 
             
                  @file.sync = true
         | 
| 26 26 | 
             
                  @size = @file.stat.size
         | 
| 27 | 
            +
                  FileUtils.ln_sf(@path, symlink_path) if symlink_path
         | 
| 27 28 | 
             
                end
         | 
| 28 29 |  | 
| 29 30 | 
             
                attr_reader :unique_id
         | 
| @@ -84,6 +85,8 @@ module Fluent | |
| 84 85 |  | 
| 85 86 | 
             
                config_param :buffer_path, :string
         | 
| 86 87 |  | 
| 88 | 
            +
                attr_accessor :symlink_path
         | 
| 89 | 
            +
             | 
| 87 90 | 
             
                def configure(conf)
         | 
| 88 91 | 
             
                  super
         | 
| 89 92 |  | 
| @@ -119,7 +122,7 @@ module Fluent | |
| 119 122 | 
             
                  encoded_key = encode_key(key)
         | 
| 120 123 | 
             
                  path, tsuffix = make_path(encoded_key, "b")
         | 
| 121 124 | 
             
                  unique_id = tsuffix_to_unique_id(tsuffix)
         | 
| 122 | 
            -
                  FileBufferChunk.new(key, path, unique_id)
         | 
| 125 | 
            +
                  FileBufferChunk.new(key, path, unique_id, "a+", @symlink_path)
         | 
| 123 126 | 
             
                end
         | 
| 124 127 |  | 
| 125 128 | 
             
                def resume
         | 
| @@ -39,11 +39,7 @@ module Fluent | |
| 39 39 | 
             
                    raise ConfigError, "tail: 'path' parameter is required on tail input"
         | 
| 40 40 | 
             
                  end
         | 
| 41 41 |  | 
| 42 | 
            -
                   | 
| 43 | 
            -
                    @pf_file = File.open(@pos_file, File::RDWR|File::CREAT, DEFAULT_FILE_PERMISSION)
         | 
| 44 | 
            -
                    @pf_file.sync = true
         | 
| 45 | 
            -
                    @pf = PositionFile.parse(@pf_file)
         | 
| 46 | 
            -
                  else
         | 
| 42 | 
            +
                  unless @pos_file
         | 
| 47 43 | 
             
                    $log.warn "'pos_file PATH' parameter is not set to a 'tail' source."
         | 
| 48 44 | 
             
                    $log.warn "this parameter is highly recommended to save the position to resume tailing."
         | 
| 49 45 | 
             
                  end
         | 
| @@ -57,6 +53,12 @@ module Fluent | |
| 57 53 | 
             
                end
         | 
| 58 54 |  | 
| 59 55 | 
             
                def start
         | 
| 56 | 
            +
                  if @pos_file
         | 
| 57 | 
            +
                    @pf_file = File.open(@pos_file, File::RDWR|File::CREAT, DEFAULT_FILE_PERMISSION)
         | 
| 58 | 
            +
                    @pf_file.sync = true
         | 
| 59 | 
            +
                    @pf = PositionFile.parse(@pf_file)
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
             | 
| 60 62 | 
             
                  @loop = Coolio::Loop.new
         | 
| 61 63 | 
             
                  @tails = @paths.map {|path|
         | 
| 62 64 | 
             
                    pe = @pf ? @pf[path] : MemoryPositionEntry.new
         | 
| @@ -19,13 +19,17 @@ module Fluent | |
| 19 19 | 
             
              class CopyOutput < MultiOutput
         | 
| 20 20 | 
             
                Plugin.register_output('copy', self)
         | 
| 21 21 |  | 
| 22 | 
            +
                config_param :deep_copy, :bool, :default => false
         | 
| 23 | 
            +
             | 
| 22 24 | 
             
                def initialize
         | 
| 25 | 
            +
                  super
         | 
| 23 26 | 
             
                  @outputs = []
         | 
| 24 27 | 
             
                end
         | 
| 25 28 |  | 
| 26 29 | 
             
                attr_reader :outputs
         | 
| 27 30 |  | 
| 28 31 | 
             
                def configure(conf)
         | 
| 32 | 
            +
                  super
         | 
| 29 33 | 
             
                  conf.elements.select {|e|
         | 
| 30 34 | 
             
                    e.name == 'store'
         | 
| 31 35 | 
             
                  }.each {|e|
         | 
| @@ -61,7 +65,11 @@ module Fluent | |
| 61 65 | 
             
                    }
         | 
| 62 66 | 
             
                    es = m
         | 
| 63 67 | 
             
                  end
         | 
| 64 | 
            -
                   | 
| 68 | 
            +
                  if @deep_copy
         | 
| 69 | 
            +
                    chain = CopyOutputChain.new(@outputs, tag, es, chain)
         | 
| 70 | 
            +
                  else
         | 
| 71 | 
            +
                    chain = OutputChain.new(@outputs, tag, es, chain)
         | 
| 72 | 
            +
                  end
         | 
| 65 73 | 
             
                  chain.next
         | 
| 66 74 | 
             
                end
         | 
| 67 75 | 
             
              end
         | 
| @@ -65,6 +65,8 @@ module Fluent | |
| 65 65 | 
             
                  super
         | 
| 66 66 |  | 
| 67 67 | 
             
                  @timef = TimeFormatter.new(@time_format, @localtime)
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  @buffer.symlink_path = @symlink_path if @symlink_path
         | 
| 68 70 | 
             
                end
         | 
| 69 71 |  | 
| 70 72 | 
             
                def format(tag, time, record)
         | 
| @@ -97,7 +99,6 @@ module Fluent | |
| 97 99 | 
             
                      chunk.write_to(f)
         | 
| 98 100 | 
             
                    }
         | 
| 99 101 | 
             
                  end
         | 
| 100 | 
            -
                  create_symlink(path, suffix) if @symlink_path
         | 
| 101 102 |  | 
| 102 103 | 
             
                  return path  # for test
         | 
| 103 104 | 
             
                end
         | 
| @@ -105,11 +106,5 @@ module Fluent | |
| 105 106 | 
             
                def secondary_init(primary)
         | 
| 106 107 | 
             
                  # don't warn even if primary.class is not FileOutput
         | 
| 107 108 | 
             
                end
         | 
| 108 | 
            -
             | 
| 109 | 
            -
                private
         | 
| 110 | 
            -
             | 
| 111 | 
            -
                def create_symlink(path, suffix)
         | 
| 112 | 
            -
                  FileUtils.ln_sf(path, "#{@symlink_path}#{suffix}")
         | 
| 113 | 
            -
                end
         | 
| 114 109 | 
             
              end
         | 
| 115 110 | 
             
            end
         | 
    
        data/lib/fluent/supervisor.rb
    CHANGED
    
    | @@ -67,6 +67,7 @@ module Fluent | |
| 67 67 | 
             
                  @inline_config = opt[:inline_config]
         | 
| 68 68 | 
             
                  @suppress_interval = opt[:suppress_interval]
         | 
| 69 69 | 
             
                  @dry_run = opt[:dry_run]
         | 
| 70 | 
            +
                  @suppress_config_dump = opt[:suppress_config_dump]
         | 
| 70 71 |  | 
| 71 72 | 
             
                  @log = LoggerInitializer.new(@log_path, @log_level, @chuser, @chgroup)
         | 
| 72 73 | 
             
                  @finished = false
         | 
| @@ -320,6 +321,8 @@ module Fluent | |
| 320 321 | 
             
                    Fluent::Engine.suppress_interval(@suppress_interval)
         | 
| 321 322 | 
             
                  end
         | 
| 322 323 |  | 
| 324 | 
            +
                  Fluent::Engine.suppress_config_dump = @suppress_config_dump
         | 
| 325 | 
            +
             | 
| 323 326 | 
             
                  @libs.each {|lib|
         | 
| 324 327 | 
             
                    require lib
         | 
| 325 328 | 
             
                  }
         | 
| @@ -363,7 +366,17 @@ module Fluent | |
| 363 366 | 
             
                    $log.debug "fluentd main process get SIGUSR1"
         | 
| 364 367 | 
             
                    $log.info "force flushing buffered events"
         | 
| 365 368 | 
             
                    @log.reopen!
         | 
| 366 | 
            -
             | 
| 369 | 
            +
             | 
| 370 | 
            +
                    # Creating new thread due to mutex can't lock
         | 
| 371 | 
            +
                    # in main thread during trap context
         | 
| 372 | 
            +
                    Thread.new {
         | 
| 373 | 
            +
                      begin
         | 
| 374 | 
            +
                        Fluent::Engine.flush!
         | 
| 375 | 
            +
                        $log.debug "flushing thread: flushed"
         | 
| 376 | 
            +
                      rescue Exception => e
         | 
| 377 | 
            +
                        $log.warn "flushing thread error: #{e}"
         | 
| 378 | 
            +
                      end
         | 
| 379 | 
            +
                    }.run
         | 
| 367 380 | 
             
                  end
         | 
| 368 381 | 
             
                end
         | 
| 369 382 |  | 
    
        data/lib/fluent/version.rb
    CHANGED
    
    
    
        data/test/config.rb
    CHANGED
    
    | @@ -7,7 +7,7 @@ require 'fileutils' | |
| 7 7 | 
             
            class ConfigTest < Test::Unit::TestCase
         | 
| 8 8 | 
             
              include Fluent
         | 
| 9 9 |  | 
| 10 | 
            -
              TMP_DIR = File.dirname(__FILE__) + "/tmp"
         | 
| 10 | 
            +
              TMP_DIR = File.dirname(__FILE__) + "/tmp/config#{ENV['TEST_ENV_NUMBER']}"
         | 
| 11 11 |  | 
| 12 12 | 
             
              def prepare_config
         | 
| 13 13 | 
             
                write_config "#{TMP_DIR}/config_test_1.conf", %[
         | 
    
        data/test/configdsl.rb
    CHANGED
    
    | @@ -1,4 +1,6 @@ | |
| 1 1 | 
             
            require 'fluent/config_dsl'
         | 
| 2 | 
            +
            require 'fluent/test'
         | 
| 3 | 
            +
            require 'helper'
         | 
| 2 4 |  | 
| 3 5 | 
             
            class ConfigDSLTest < Test::Unit::TestCase
         | 
| 4 6 | 
             
              # TEST_CONFIG1 = %[
         | 
| @@ -38,10 +40,24 @@ match('test.**') { | |
| 38 40 |  | 
| 39 41 | 
             
              TEST_DSL_CONFIG2 = %q[
         | 
| 40 42 | 
             
            v = [0, 1, 2]
         | 
| 43 | 
            +
            ]
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              TEST_DSL_CONFIG3 = %q[
         | 
| 46 | 
            +
            match
         | 
| 47 | 
            +
            ]
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              TEST_DSL_CONFIG4 = %q[
         | 
| 50 | 
            +
            match('aa', 'bb'){
         | 
| 51 | 
            +
              type :null
         | 
| 52 | 
            +
            }
         | 
| 53 | 
            +
            ]
         | 
| 54 | 
            +
             | 
| 55 | 
            +
              TEST_DSL_CONFIG5 = %q[
         | 
| 56 | 
            +
            match('aa')
         | 
| 41 57 | 
             
            ]
         | 
| 42 58 |  | 
| 43 59 | 
             
              def test_parse
         | 
| 44 | 
            -
                root = Fluent::Config::DSL:: | 
| 60 | 
            +
                root = Fluent::Config::DSL::Parser.parse(TEST_DSL_CONFIG1)
         | 
| 45 61 |  | 
| 46 62 | 
             
                assert_equal 0, root.keys.size
         | 
| 47 63 | 
             
                assert_equal 2, root.elements.size
         | 
| @@ -69,9 +85,23 @@ v = [0, 1, 2] | |
| 69 85 | 
             
              end
         | 
| 70 86 |  | 
| 71 87 | 
             
              def test_parse2
         | 
| 72 | 
            -
                root = Fluent::Config::DSL:: | 
| 88 | 
            +
                root = Fluent::Config::DSL::Parser.parse(TEST_DSL_CONFIG2)
         | 
| 73 89 |  | 
| 74 90 | 
             
                assert_equal 0, root.keys.size
         | 
| 75 91 | 
             
                assert_equal 0, root.elements.size
         | 
| 76 92 | 
             
              end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
              def test_config_error
         | 
| 95 | 
            +
                assert_raise(ArgumentError) {
         | 
| 96 | 
            +
                  Fluent::Config::DSL::Parser.parse(TEST_DSL_CONFIG3)
         | 
| 97 | 
            +
                }
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                assert_raise(ArgumentError) {
         | 
| 100 | 
            +
                  Fluent::Config::DSL::Parser.parse(TEST_DSL_CONFIG4)
         | 
| 101 | 
            +
                }
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                assert_raise(ArgumentError) {
         | 
| 104 | 
            +
                  Fluent::Config::DSL::Parser.parse(TEST_DSL_CONFIG5)
         | 
| 105 | 
            +
                }
         | 
| 106 | 
            +
              end
         | 
| 77 107 | 
             
            end
         | 
    
        data/test/helper.rb
    CHANGED
    
    
    
        data/test/parser.rb
    CHANGED
    
    | @@ -9,7 +9,35 @@ module ParserTest | |
| 9 9 | 
             
                if format
         | 
| 10 10 | 
             
                  Time.strptime(str_time, format).to_i
         | 
| 11 11 | 
             
                else
         | 
| 12 | 
            -
                  Time.parse(str_time)
         | 
| 12 | 
            +
                  Time.parse(str_time).to_i
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              class TimeParserTest < ::Test::Unit::TestCase
         | 
| 17 | 
            +
                include ParserTest
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def test_call_with_parse
         | 
| 20 | 
            +
                  parser = TextParser::TimeParser.new(nil)
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  time = str2time('2013-09-18 12:00:00 +0900')
         | 
| 23 | 
            +
                  assert_equal(time, parser.parse('2013-09-18 12:00:00 +0900'))
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def test_call_with_strptime
         | 
| 27 | 
            +
                  parser = TextParser::TimeParser.new('%d/%b/%Y:%H:%M:%S %z')
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  time = str2time('28/Feb/2013:12:00:00 +0900', '%d/%b/%Y:%H:%M:%S %z')
         | 
| 30 | 
            +
                  assert_equal(time, parser.parse('28/Feb/2013:12:00:00 +0900'))
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def test_call_with_invalid_argument
         | 
| 34 | 
            +
                  parser = TextParser::TimeParser.new(nil)
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  [[], {}, nil, true, 10000].each { |v|
         | 
| 37 | 
            +
                    assert_raise ArgumentError do
         | 
| 38 | 
            +
                      parser.parse(v)
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
                  }
         | 
| 13 41 | 
             
                end
         | 
| 14 42 | 
             
              end
         | 
| 15 43 |  | 
| @@ -151,6 +179,7 @@ module ParserTest | |
| 151 179 |  | 
| 152 180 | 
             
                def test_call
         | 
| 153 181 | 
             
                  parser = TextParser::LabeledTSVParser.new
         | 
| 182 | 
            +
                  parser.configure({})
         | 
| 154 183 | 
             
                  time, record = parser.call("time:2013/02/28 12:00:00\thost:192.168.0.1\treq_id:111")
         | 
| 155 184 |  | 
| 156 185 | 
             
                  assert_equal(str2time('2013/02/28 12:00:00', '%Y/%m/%d %H:%M:%S'), time)
         | 
| @@ -190,4 +219,32 @@ module ParserTest | |
| 190 219 | 
             
                  }, record)
         | 
| 191 220 | 
             
                end
         | 
| 192 221 | 
             
              end
         | 
| 222 | 
            +
             | 
| 223 | 
            +
              class NoneParserTest < ::Test::Unit::TestCase
         | 
| 224 | 
            +
                include ParserTest
         | 
| 225 | 
            +
             | 
| 226 | 
            +
                def test_config_params
         | 
| 227 | 
            +
                  parser = TextParser::NoneParser.new
         | 
| 228 | 
            +
                  assert_equal "message", parser.message_key
         | 
| 229 | 
            +
             | 
| 230 | 
            +
                  parser.configure('message_key' => 'foobar')
         | 
| 231 | 
            +
                  assert_equal "foobar", parser.message_key
         | 
| 232 | 
            +
                end
         | 
| 233 | 
            +
             | 
| 234 | 
            +
                def test_call
         | 
| 235 | 
            +
                  parser = TextParser::TEMPLATE_FACTORIES['none'].call
         | 
| 236 | 
            +
                  time, record = parser.call('log message!')
         | 
| 237 | 
            +
             | 
| 238 | 
            +
                  assert_equal({'message' => 'log message!'}, record)
         | 
| 239 | 
            +
                end
         | 
| 240 | 
            +
             | 
| 241 | 
            +
                def test_call_with_message_key
         | 
| 242 | 
            +
                  parser = TextParser::NoneParser.new
         | 
| 243 | 
            +
                  parser.configure('message_key' => 'foobar')
         | 
| 244 | 
            +
                  time, record = parser.call('log message!')
         | 
| 245 | 
            +
             | 
| 246 | 
            +
                  assert_equal({'foobar' => 'log message!'}, record)
         | 
| 247 | 
            +
                end
         | 
| 248 | 
            +
              end
         | 
| 249 | 
            +
             | 
| 193 250 | 
             
            end
         | 
    
        data/test/plugin/in_forward.rb
    CHANGED
    
    | @@ -1,12 +1,14 @@ | |
| 1 1 | 
             
            require 'fluent/test'
         | 
| 2 | 
            +
            require 'helper'
         | 
| 2 3 |  | 
| 3 4 | 
             
            class ForwardInputTest < Test::Unit::TestCase
         | 
| 4 5 | 
             
              def setup
         | 
| 5 6 | 
             
                Fluent::Test.setup
         | 
| 6 7 | 
             
              end
         | 
| 7 8 |  | 
| 9 | 
            +
              PORT = unused_port
         | 
| 8 10 | 
             
              CONFIG = %[
         | 
| 9 | 
            -
                port  | 
| 11 | 
            +
                port #{PORT}
         | 
| 10 12 | 
             
                bind 127.0.0.1
         | 
| 11 13 | 
             
              ]
         | 
| 12 14 |  | 
| @@ -16,12 +18,12 @@ class ForwardInputTest < Test::Unit::TestCase | |
| 16 18 |  | 
| 17 19 | 
             
              def test_configure
         | 
| 18 20 | 
             
                d = create_driver
         | 
| 19 | 
            -
                assert_equal  | 
| 21 | 
            +
                assert_equal PORT, d.instance.port
         | 
| 20 22 | 
             
                assert_equal '127.0.0.1', d.instance.bind
         | 
| 21 23 | 
             
              end
         | 
| 22 24 |  | 
| 23 25 | 
             
              def connect
         | 
| 24 | 
            -
                TCPSocket.new('127.0.0.1',  | 
| 26 | 
            +
                TCPSocket.new('127.0.0.1', PORT)
         | 
| 25 27 | 
             
              end
         | 
| 26 28 |  | 
| 27 29 | 
             
              def test_time
         | 
| @@ -120,4 +122,3 @@ class ForwardInputTest < Test::Unit::TestCase | |
| 120 122 |  | 
| 121 123 | 
             
              # TODO heartbeat
         | 
| 122 124 | 
             
            end
         | 
| 123 | 
            -
             | 
    
        data/test/plugin/in_http.rb
    CHANGED
    
    | @@ -1,4 +1,5 @@ | |
| 1 1 | 
             
            require 'fluent/test'
         | 
| 2 | 
            +
            require 'helper'
         | 
| 2 3 | 
             
            require 'net/http'
         | 
| 3 4 |  | 
| 4 5 | 
             
            class HttpInputTest < Test::Unit::TestCase
         | 
| @@ -6,8 +7,9 @@ class HttpInputTest < Test::Unit::TestCase | |
| 6 7 | 
             
                Fluent::Test.setup
         | 
| 7 8 | 
             
              end
         | 
| 8 9 |  | 
| 10 | 
            +
              PORT = unused_port
         | 
| 9 11 | 
             
              CONFIG = %[
         | 
| 10 | 
            -
                port  | 
| 12 | 
            +
                port #{PORT}
         | 
| 11 13 | 
             
                bind 127.0.0.1
         | 
| 12 14 | 
             
                body_size_limit 10m
         | 
| 13 15 | 
             
                keepalive_timeout 5
         | 
| @@ -19,7 +21,7 @@ class HttpInputTest < Test::Unit::TestCase | |
| 19 21 |  | 
| 20 22 | 
             
              def test_configure
         | 
| 21 23 | 
             
                d = create_driver
         | 
| 22 | 
            -
                assert_equal  | 
| 24 | 
            +
                assert_equal PORT, d.instance.port
         | 
| 23 25 | 
             
                assert_equal '127.0.0.1', d.instance.bind
         | 
| 24 26 | 
             
                assert_equal 10*1024*1024, d.instance.body_size_limit
         | 
| 25 27 | 
             
                assert_equal 5, d.instance.keepalive_timeout
         | 
| @@ -68,7 +70,7 @@ class HttpInputTest < Test::Unit::TestCase | |
| 68 70 |  | 
| 69 71 | 
             
                d.run do
         | 
| 70 72 | 
             
                  d.expected_emits.each {|tag,time,record|
         | 
| 71 | 
            -
                    http = Net::HTTP.new("127.0.0.1",  | 
| 73 | 
            +
                    http = Net::HTTP.new("127.0.0.1", PORT)
         | 
| 72 74 | 
             
                    req = Net::HTTP::Post.new("/#{tag}?time=#{time.to_s}", {"content-type"=>"application/json; charset=utf-8"})
         | 
| 73 75 | 
             
                    req.body = record.to_json
         | 
| 74 76 | 
             
                    res = http.request(req)
         | 
| @@ -94,7 +96,7 @@ class HttpInputTest < Test::Unit::TestCase | |
| 94 96 | 
             
              end
         | 
| 95 97 |  | 
| 96 98 | 
             
              def post(path, params)
         | 
| 97 | 
            -
                http = Net::HTTP.new("127.0.0.1",  | 
| 99 | 
            +
                http = Net::HTTP.new("127.0.0.1", PORT)
         | 
| 98 100 | 
             
                req = Net::HTTP::Post.new(path, {})
         | 
| 99 101 | 
             
                req.set_form_data(params)
         | 
| 100 102 | 
             
                http.request(req)
         | 
    
        data/test/plugin/in_stream.rb
    CHANGED
    
    | @@ -1,4 +1,5 @@ | |
| 1 1 | 
             
            require 'fluent/test'
         | 
| 2 | 
            +
            require 'helper'
         | 
| 2 3 |  | 
| 3 4 | 
             
            module StreamInputTest
         | 
| 4 5 | 
             
              def setup
         | 
| @@ -107,8 +108,9 @@ end | |
| 107 108 | 
             
            class TcpInputTest < Test::Unit::TestCase
         | 
| 108 109 | 
             
              include StreamInputTest
         | 
| 109 110 |  | 
| 111 | 
            +
              PORT = unused_port
         | 
| 110 112 | 
             
              CONFIG = %[
         | 
| 111 | 
            -
                port  | 
| 113 | 
            +
                port #{PORT}
         | 
| 112 114 | 
             
                bind 127.0.0.1
         | 
| 113 115 | 
             
              ]
         | 
| 114 116 |  | 
| @@ -118,20 +120,19 @@ class TcpInputTest < Test::Unit::TestCase | |
| 118 120 |  | 
| 119 121 | 
             
              def test_configure
         | 
| 120 122 | 
             
                d = create_driver
         | 
| 121 | 
            -
                assert_equal  | 
| 123 | 
            +
                assert_equal PORT, d.instance.port
         | 
| 122 124 | 
             
                assert_equal '127.0.0.1', d.instance.bind
         | 
| 123 125 | 
             
              end
         | 
| 124 126 |  | 
| 125 127 | 
             
              def connect
         | 
| 126 | 
            -
                TCPSocket.new('127.0.0.1',  | 
| 128 | 
            +
                TCPSocket.new('127.0.0.1', PORT)
         | 
| 127 129 | 
             
              end
         | 
| 128 130 | 
             
            end
         | 
| 129 131 |  | 
| 130 132 | 
             
            class UnixInputTest < Test::Unit::TestCase
         | 
| 131 133 | 
             
              include StreamInputTest
         | 
| 132 134 |  | 
| 133 | 
            -
              TMP_DIR = File.dirname(__FILE__) + "/../tmp"
         | 
| 134 | 
            -
             | 
| 135 | 
            +
              TMP_DIR = File.dirname(__FILE__) + "/../tmp/in_unix#{ENV['TEST_ENV_NUMBER']}"
         | 
| 135 136 | 
             
              CONFIG = %[
         | 
| 136 137 | 
             
                path #{TMP_DIR}/unix
         | 
| 137 138 | 
             
                backlog 1000
         | 
| @@ -151,4 +152,3 @@ class UnixInputTest < Test::Unit::TestCase | |
| 151 152 | 
             
                UNIXSocket.new("#{TMP_DIR}/unix")
         | 
| 152 153 | 
             
              end
         | 
| 153 154 | 
             
            end
         | 
| 154 | 
            -
             | 
    
        data/test/plugin/in_syslog.rb
    CHANGED
    
    | @@ -7,14 +7,15 @@ class SyslogInputTest < Test::Unit::TestCase | |
| 7 7 | 
             
                require 'fluent/plugin/socket_util'
         | 
| 8 8 | 
             
              end
         | 
| 9 9 |  | 
| 10 | 
            +
              PORT = unused_port
         | 
| 10 11 | 
             
              CONFIG = %[
         | 
| 11 | 
            -
                port  | 
| 12 | 
            +
                port #{PORT}
         | 
| 12 13 | 
             
                bind 127.0.0.1
         | 
| 13 14 | 
             
                tag syslog
         | 
| 14 15 | 
             
              ]
         | 
| 15 16 |  | 
| 16 17 | 
             
              IPv6_CONFIG = %[
         | 
| 17 | 
            -
                port  | 
| 18 | 
            +
                port #{PORT}
         | 
| 18 19 | 
             
                bind ::1
         | 
| 19 20 | 
             
                tag syslog
         | 
| 20 21 | 
             
              ]
         | 
| @@ -29,7 +30,7 @@ class SyslogInputTest < Test::Unit::TestCase | |
| 29 30 |  | 
| 30 31 | 
             
                configs.each_pair { |k, v|
         | 
| 31 32 | 
             
                  d = create_driver(v)
         | 
| 32 | 
            -
                  assert_equal  | 
| 33 | 
            +
                  assert_equal PORT, d.instance.port
         | 
| 33 34 | 
             
                  assert_equal k, d.instance.bind
         | 
| 34 35 | 
             
                }
         | 
| 35 36 | 
             
              end
         | 
| @@ -48,7 +49,7 @@ class SyslogInputTest < Test::Unit::TestCase | |
| 48 49 |  | 
| 49 50 | 
             
                  d.run do
         | 
| 50 51 | 
             
                    u = Fluent::SocketUtil.create_udp_socket(k)
         | 
| 51 | 
            -
                    u.connect(k,  | 
| 52 | 
            +
                    u.connect(k, PORT)
         | 
| 52 53 | 
             
                    tests.each {|test|
         | 
| 53 54 | 
             
                      u.send(test['msg'], 0)
         | 
| 54 55 | 
             
                    }
         | 
| @@ -72,7 +73,7 @@ class SyslogInputTest < Test::Unit::TestCase | |
| 72 73 |  | 
| 73 74 | 
             
                d.run do
         | 
| 74 75 | 
             
                  u = UDPSocket.new
         | 
| 75 | 
            -
                  u.connect('127.0.0.1',  | 
| 76 | 
            +
                  u.connect('127.0.0.1', PORT)
         | 
| 76 77 | 
             
                  tests.each {|test|
         | 
| 77 78 | 
             
                    u.send(test['msg'], 0)
         | 
| 78 79 | 
             
                  }
         | 
    
        data/test/plugin/in_tail.rb
    CHANGED
    
    
    
        data/test/plugin/out_copy.rb
    CHANGED
    
    | @@ -88,5 +88,83 @@ class CopyOutputTest < Test::Unit::TestCase | |
| 88 88 | 
             
                  ], o.events
         | 
| 89 89 | 
             
                }
         | 
| 90 90 | 
             
              end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
              def create_event_test_driver(is_deep_copy = false)
         | 
| 93 | 
            +
                deep_copy_config = %[
         | 
| 94 | 
            +
            deep_copy true
         | 
| 95 | 
            +
            ]
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                output1 = Fluent::Plugin.new_output('test')
         | 
| 98 | 
            +
                output1.configure('name' => 'output1')
         | 
| 99 | 
            +
                output1.define_singleton_method(:emit) do |tag, es, chain|
         | 
| 100 | 
            +
                  es.each do |time, record|
         | 
| 101 | 
            +
                    record['foo'] = 'bar'
         | 
| 102 | 
            +
                    super(tag, [[time, record]], chain)
         | 
| 103 | 
            +
                  end
         | 
| 104 | 
            +
                end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                output2 = Fluent::Plugin.new_output('test')
         | 
| 107 | 
            +
                output2.configure('name' => 'output2')
         | 
| 108 | 
            +
                output2.define_singleton_method(:emit) do |tag, es, chain|
         | 
| 109 | 
            +
                  es.each do |time, record|
         | 
| 110 | 
            +
                    super(tag, [[time, record]], chain)
         | 
| 111 | 
            +
                  end
         | 
| 112 | 
            +
                end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                outputs = [output1, output2]
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                d = Fluent::Test::OutputTestDriver.new(Fluent::CopyOutput)
         | 
| 117 | 
            +
                d = d.configure(deep_copy_config) if is_deep_copy
         | 
| 118 | 
            +
                d.instance.instance_eval { @outputs = outputs }
         | 
| 119 | 
            +
                d
         | 
| 120 | 
            +
              end
         | 
| 121 | 
            +
             | 
| 122 | 
            +
              def test_one_event
         | 
| 123 | 
            +
                time = Time.parse("2013-05-26 06:37:22 UTC").to_i
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                d = create_event_test_driver(false)
         | 
| 126 | 
            +
                es = Fluent::OneEventStream.new(time, {"a" => 1})
         | 
| 127 | 
            +
                d.instance.emit('test', es, Fluent::NullOutputChain.instance)
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                assert_equal [
         | 
| 130 | 
            +
                  [[time, {"a"=>1, "foo"=>"bar"}]],
         | 
| 131 | 
            +
                  [[time, {"a"=>1, "foo"=>"bar"}]]
         | 
| 132 | 
            +
                ], d.instance.outputs.map{ |o| o.events }
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                d = create_event_test_driver(true)
         | 
| 135 | 
            +
                es = Fluent::OneEventStream.new(time, {"a" => 1})
         | 
| 136 | 
            +
                d.instance.emit('test', es, Fluent::NullOutputChain.instance)
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                assert_equal [
         | 
| 139 | 
            +
                  [[time, {"a"=>1, "foo"=>"bar"}]],
         | 
| 140 | 
            +
                  [[time, {"a"=>1}]]
         | 
| 141 | 
            +
                ], d.instance.outputs.map{ |o| o.events }
         | 
| 142 | 
            +
              end
         | 
| 143 | 
            +
             | 
| 144 | 
            +
              def test_multi_event
         | 
| 145 | 
            +
                time = Time.parse("2013-05-26 06:37:22 UTC").to_i
         | 
| 146 | 
            +
             | 
| 147 | 
            +
                d = create_event_test_driver(false)
         | 
| 148 | 
            +
                es = Fluent::MultiEventStream.new
         | 
| 149 | 
            +
                es.add(time, {"a" => 1})
         | 
| 150 | 
            +
                es.add(time, {"b" => 2})
         | 
| 151 | 
            +
                d.instance.emit('test', es, Fluent::NullOutputChain.instance)
         | 
| 152 | 
            +
             | 
| 153 | 
            +
                assert_equal [
         | 
| 154 | 
            +
                  [[time, {"a"=>1, "foo"=>"bar"}], [time, {"b"=>2, "foo"=>"bar"}]],
         | 
| 155 | 
            +
                  [[time, {"a"=>1, "foo"=>"bar"}], [time, {"b"=>2, "foo"=>"bar"}]]
         | 
| 156 | 
            +
                ], d.instance.outputs.map{ |o| o.events }
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                d = create_event_test_driver(true)
         | 
| 159 | 
            +
                es = Fluent::MultiEventStream.new
         | 
| 160 | 
            +
                es.add(time, {"a" => 1})
         | 
| 161 | 
            +
                es.add(time, {"b" => 2})
         | 
| 162 | 
            +
                d.instance.emit('test', es, Fluent::NullOutputChain.instance)
         | 
| 163 | 
            +
             | 
| 164 | 
            +
                assert_equal [
         | 
| 165 | 
            +
                  [[time, {"a"=>1, "foo"=>"bar"}], [time, {"b"=>2, "foo"=>"bar"}]],
         | 
| 166 | 
            +
                  [[time, {"a"=>1}], [time, {"b"=>2}]]
         | 
| 167 | 
            +
                ], d.instance.outputs.map{ |o| o.events }
         | 
| 168 | 
            +
              end
         | 
| 91 169 | 
             
            end
         | 
| 92 170 |  | 
    
        data/test/plugin/out_exec.rb
    CHANGED
    
    
    
        data/test/plugin/out_file.rb
    CHANGED
    
    | @@ -9,7 +9,7 @@ class FileOutputTest < Test::Unit::TestCase | |
| 9 9 | 
             
                FileUtils.mkdir_p(TMP_DIR)
         | 
| 10 10 | 
             
              end
         | 
| 11 11 |  | 
| 12 | 
            -
              TMP_DIR = File.expand_path(File.dirname(__FILE__) + "/../tmp")
         | 
| 12 | 
            +
              TMP_DIR = File.expand_path(File.dirname(__FILE__) + "/../tmp/out_file#{ENV['TEST_ENV_NUMBER']}")
         | 
| 13 13 | 
             
              SYMLINK_PATH = File.expand_path("#{TMP_DIR}/current")
         | 
| 14 14 |  | 
| 15 15 | 
             
              CONFIG = %[
         | 
| @@ -81,20 +81,32 @@ class FileOutputTest < Test::Unit::TestCase | |
| 81 81 | 
             
              end
         | 
| 82 82 |  | 
| 83 83 | 
             
              def test_write_with_symlink
         | 
| 84 | 
            -
                 | 
| 84 | 
            +
                conf = CONFIG + %[
         | 
| 85 85 | 
             
                  symlink_path #{SYMLINK_PATH}
         | 
| 86 | 
            -
                ] | 
| 87 | 
            -
                symlink_path = "#{SYMLINK_PATH} | 
| 86 | 
            +
                ]
         | 
| 87 | 
            +
                symlink_path = "#{SYMLINK_PATH}"
         | 
| 88 88 |  | 
| 89 | 
            -
                 | 
| 90 | 
            -
                d. | 
| 89 | 
            +
                Fluent::FileBuffer.clear_buffer_paths
         | 
| 90 | 
            +
                d = Fluent::Test::TestDriver.new(Fluent::FileOutput).configure(conf)
         | 
| 91 91 |  | 
| 92 | 
            -
                 | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 92 | 
            +
                begin
         | 
| 93 | 
            +
                  d.instance.start
         | 
| 94 | 
            +
                  10.times { sleep 0.05 }
         | 
| 95 | 
            +
                  time = Time.parse("2011-01-02 13:14:15 UTC").to_i
         | 
| 96 | 
            +
                  es = Fluent::OneEventStream.new(time, {"a"=>1})
         | 
| 97 | 
            +
                  d.instance.emit('tag', es, Fluent::NullOutputChain.instance)
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  assert File.exists?(symlink_path)
         | 
| 100 | 
            +
                  assert File.symlink?(symlink_path)
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                  d.instance.enqueue_buffer
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                  assert !File.exists?(symlink_path)
         | 
| 105 | 
            +
                  assert File.symlink?(symlink_path)
         | 
| 106 | 
            +
                ensure
         | 
| 107 | 
            +
                  d.instance.shutdown
         | 
| 108 | 
            +
                  FileUtils.rm_rf(symlink_path)
         | 
| 109 | 
            +
                end
         | 
| 98 110 | 
             
              end
         | 
| 99 111 | 
             
            end
         | 
| 100 112 |  | 
    
        data/test/plugin/out_stream.rb
    CHANGED
    
    | @@ -1,4 +1,5 @@ | |
| 1 1 | 
             
            require 'fluent/test'
         | 
| 2 | 
            +
            require 'helper'
         | 
| 2 3 |  | 
| 3 4 | 
             
            module StreamOutputTest
         | 
| 4 5 | 
             
              def setup
         | 
| @@ -33,8 +34,9 @@ end | |
| 33 34 | 
             
            class TcpOutputTest < Test::Unit::TestCase
         | 
| 34 35 | 
             
              include StreamOutputTest
         | 
| 35 36 |  | 
| 37 | 
            +
              PORT = unused_port
         | 
| 36 38 | 
             
              CONFIG = %[
         | 
| 37 | 
            -
                port  | 
| 39 | 
            +
                port #{PORT}
         | 
| 38 40 | 
             
                host 127.0.0.1
         | 
| 39 41 | 
             
                send_timeout 51
         | 
| 40 42 | 
             
              ]
         | 
| @@ -45,7 +47,7 @@ class TcpOutputTest < Test::Unit::TestCase | |
| 45 47 |  | 
| 46 48 | 
             
              def test_configure
         | 
| 47 49 | 
             
                d = create_driver
         | 
| 48 | 
            -
                assert_equal  | 
| 50 | 
            +
                assert_equal PORT, d.instance.port
         | 
| 49 51 | 
             
                assert_equal '127.0.0.1', d.instance.host
         | 
| 50 52 | 
             
                assert_equal 51, d.instance.send_timeout
         | 
| 51 53 | 
             
              end
         | 
| @@ -54,8 +56,7 @@ end | |
| 54 56 | 
             
            class UnixOutputTest < Test::Unit::TestCase
         | 
| 55 57 | 
             
              include StreamOutputTest
         | 
| 56 58 |  | 
| 57 | 
            -
              TMP_DIR = File.dirname(__FILE__) + "/../tmp"
         | 
| 58 | 
            -
             | 
| 59 | 
            +
              TMP_DIR = File.dirname(__FILE__) + "/../tmp/out_unix#{ENV['TEST_ENV_NUMBER']}"
         | 
| 59 60 | 
             
              CONFIG = %[
         | 
| 60 61 | 
             
                path #{TMP_DIR}/unix
         | 
| 61 62 | 
             
                send_timeout 52
         | 
    
        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. | 
| 4 | 
            +
              version: 0.10.39
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Sadayuki Furuhashi
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2013- | 
| 11 | 
            +
            date: 2013-09-18 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: msgpack
         | 
| @@ -124,6 +124,20 @@ dependencies: | |
| 124 124 | 
             
                - - '>='
         | 
| 125 125 | 
             
                  - !ruby/object:Gem::Version
         | 
| 126 126 | 
             
                    version: 0.9.2
         | 
| 127 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 128 | 
            +
              name: parallel_tests
         | 
| 129 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 130 | 
            +
                requirements:
         | 
| 131 | 
            +
                - - '>='
         | 
| 132 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 133 | 
            +
                    version: 0.15.3
         | 
| 134 | 
            +
              type: :development
         | 
| 135 | 
            +
              prerelease: false
         | 
| 136 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 137 | 
            +
                requirements:
         | 
| 138 | 
            +
                - - '>='
         | 
| 139 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 140 | 
            +
                    version: 0.15.3
         | 
| 127 141 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 128 142 | 
             
              name: rr
         | 
| 129 143 | 
             
              requirement: !ruby/object:Gem::Requirement
         |