fluent-plugin-cloudwatch-logs 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +86 -0
- data/Rakefile +9 -0
- data/example/fluentd.conf +24 -0
- data/fluent-plugin-cloudwatch-logs.gemspec +25 -0
- data/lib/fluent/plugin/cloudwatch/logs.rb +11 -0
- data/lib/fluent/plugin/cloudwatch/logs/version.rb +9 -0
- data/lib/fluent/plugin/in_cloudwatch_logs.rb +70 -0
- data/lib/fluent/plugin/out_cloudwatch_logs.rb +81 -0
- data/test/plugin/test_in_cloudwatch_logs.rb +68 -0
- data/test/plugin/test_out_cloudwatch_logs.rb +73 -0
- data/test/test_helper.rb +60 -0
- metadata +117 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA1:
         | 
| 3 | 
            +
              metadata.gz: 82f4aa50c7c50dd4fb39644824405fe597e44dbc
         | 
| 4 | 
            +
              data.tar.gz: 7af64b0786713b5afaa6aa9e15c4a5c2b14cf41e
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: 0e96bd6e04ce768e9b5ace8492ff5e77d8de77f8203416711a4acb7efdfe5ddea805503c875434884d6e8b6cbebab991b19b7f492c7c9fce2fdb53a3a7ac8370
         | 
| 7 | 
            +
              data.tar.gz: c204752a267e1083c8ff1e5ff2237611fc44a2293d59247761242fc8c5d1ffaddc9da64773ecd2f00cbe21506604b5ec072d14b2d17aca733b5af69fba9126d9
         | 
    
        data/.gitignore
    ADDED
    
    | @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            *.gem
         | 
| 2 | 
            +
            *.rbc
         | 
| 3 | 
            +
            .bundle
         | 
| 4 | 
            +
            .config
         | 
| 5 | 
            +
            .yardoc
         | 
| 6 | 
            +
            Gemfile.lock
         | 
| 7 | 
            +
            InstalledFiles
         | 
| 8 | 
            +
            _yardoc
         | 
| 9 | 
            +
            coverage
         | 
| 10 | 
            +
            doc/
         | 
| 11 | 
            +
            lib/bundler/man
         | 
| 12 | 
            +
            pkg
         | 
| 13 | 
            +
            rdoc
         | 
| 14 | 
            +
            spec/reports
         | 
| 15 | 
            +
            test/tmp
         | 
| 16 | 
            +
            test/version_tmp
         | 
| 17 | 
            +
            tmp
         | 
| 18 | 
            +
            *.bundle
         | 
| 19 | 
            +
            *.so
         | 
| 20 | 
            +
            *.o
         | 
| 21 | 
            +
            *.a
         | 
| 22 | 
            +
            mkmf.log
         | 
    
        data/Gemfile
    ADDED
    
    
    
        data/LICENSE.txt
    ADDED
    
    | @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            Copyright (c) 2014 Ryota Arai
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            MIT License
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining
         | 
| 6 | 
            +
            a copy of this software and associated documentation files (the
         | 
| 7 | 
            +
            "Software"), to deal in the Software without restriction, including
         | 
| 8 | 
            +
            without limitation the rights to use, copy, modify, merge, publish,
         | 
| 9 | 
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         | 
| 10 | 
            +
            permit persons to whom the Software is furnished to do so, subject to
         | 
| 11 | 
            +
            the following conditions:
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            The above copyright notice and this permission notice shall be
         | 
| 14 | 
            +
            included in all copies or substantial portions of the Software.
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         | 
| 17 | 
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         | 
| 18 | 
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         | 
| 19 | 
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         | 
| 20 | 
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         | 
| 21 | 
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         | 
| 22 | 
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         | 
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,86 @@ | |
| 1 | 
            +
            # fluent-plugin-cloudwatch-logs
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            CloudWatch Logs Plugin for Fluentd
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ## Installation
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                $ gem install fluent-plugin-cloudwatch-logs
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            ## Example
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            Start fluentd:
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            ```
         | 
| 14 | 
            +
            $ fluentd -c example/fluentd.conf
         | 
| 15 | 
            +
            ```
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            Send sample log to CloudWatch Logs:
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            ```
         | 
| 20 | 
            +
            $ echo '{"hello":"world"}' | fluent-cat test.cloudwatch_logs.out
         | 
| 21 | 
            +
            ```
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            Fetch sample log from CloudWatch Logs:
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            ```
         | 
| 26 | 
            +
            # stdout
         | 
| 27 | 
            +
            2014-07-17 00:28:02 +0900 test.cloudwatch_logs.in: {"hello":"world"}
         | 
| 28 | 
            +
            ```
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            ## out_cloudwatch_logs
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            ```
         | 
| 33 | 
            +
            <match tag>
         | 
| 34 | 
            +
              type cloudwatch_logs
         | 
| 35 | 
            +
              log_group_name log-group-name
         | 
| 36 | 
            +
              log_stream_name log-stream-name
         | 
| 37 | 
            +
              sequence_token_file /var/lib/fluent/group_stream.out.seq
         | 
| 38 | 
            +
              auto_create_stream true
         | 
| 39 | 
            +
            </match>
         | 
| 40 | 
            +
            ```
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            ## in_cloudwatch_logs
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            ```
         | 
| 45 | 
            +
            <source>
         | 
| 46 | 
            +
              type cloudwatch_logs
         | 
| 47 | 
            +
              tag cloudwatch.in
         | 
| 48 | 
            +
              log_group_name group
         | 
| 49 | 
            +
              log_stream_name stream
         | 
| 50 | 
            +
              state_file /var/lib/fluent/group_stream.in.state
         | 
| 51 | 
            +
            </source>
         | 
| 52 | 
            +
            ```
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            ## Test
         | 
| 55 | 
            +
             | 
| 56 | 
            +
            Set credentials:
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            ```
         | 
| 59 | 
            +
            $ export AWS_REGION=us-east-1
         | 
| 60 | 
            +
            $ export AWS_ACCESS_KEY_ID="YOUR_ACCESS_KEY"
         | 
| 61 | 
            +
            $ export AWS_SECRET_ACCESS_KEY="YOUR_SECRET_KEY"
         | 
| 62 | 
            +
            ```
         | 
| 63 | 
            +
             | 
| 64 | 
            +
            Run tests:
         | 
| 65 | 
            +
             | 
| 66 | 
            +
            ```
         | 
| 67 | 
            +
            $ rake test
         | 
| 68 | 
            +
            ```
         | 
| 69 | 
            +
             | 
| 70 | 
            +
            ## TODO
         | 
| 71 | 
            +
             | 
| 72 | 
            +
            * out_cloudwatch_logs
         | 
| 73 | 
            +
              * if the data is too big for API, split into multiple requests
         | 
| 74 | 
            +
              * format
         | 
| 75 | 
            +
              * check data size
         | 
| 76 | 
            +
            * in_cloudwatch_logs
         | 
| 77 | 
            +
              * format
         | 
| 78 | 
            +
              * fallback to start_time because next_token expires after 24 hours
         | 
| 79 | 
            +
             | 
| 80 | 
            +
            ## Contributing
         | 
| 81 | 
            +
             | 
| 82 | 
            +
            1. Fork it ( https://github.com/[my-github-username]/fluent-plugin-cloudwatch-logs/fork )
         | 
| 83 | 
            +
            2. Create your feature branch (`git checkout -b my-new-feature`)
         | 
| 84 | 
            +
            3. Commit your changes (`git commit -am 'Add some feature'`)
         | 
| 85 | 
            +
            4. Push to the branch (`git push origin my-new-feature`)
         | 
| 86 | 
            +
            5. Create a new Pull Request
         | 
    
        data/Rakefile
    ADDED
    
    
| @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            <source>
         | 
| 2 | 
            +
              type forward
         | 
| 3 | 
            +
            </source>
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            <source>
         | 
| 6 | 
            +
              type cloudwatch_logs
         | 
| 7 | 
            +
              tag test.cloudwatch_logs.in
         | 
| 8 | 
            +
              log_group_name fluent-plugin-cloudwatch-example
         | 
| 9 | 
            +
              log_stream_name fluent-plugin-cloudwatch-example
         | 
| 10 | 
            +
              state_file /tmp/fluent-plugin-cloudwatch-example.state
         | 
| 11 | 
            +
            </source>
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            <match test.cloudwatch_logs.out>
         | 
| 14 | 
            +
              type cloudwatch_logs
         | 
| 15 | 
            +
              log_group_name fluent-plugin-cloudwatch-example
         | 
| 16 | 
            +
              log_stream_name fluent-plugin-cloudwatch-example
         | 
| 17 | 
            +
              sequence_token_file /tmp/fluent-plugin-cloudwatch-example.seq
         | 
| 18 | 
            +
              auto_create_stream true
         | 
| 19 | 
            +
            </match>
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            <match test.cloudwatch_logs.in>
         | 
| 22 | 
            +
              type stdout
         | 
| 23 | 
            +
            </match>
         | 
| 24 | 
            +
             | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            # coding: utf-8
         | 
| 2 | 
            +
            lib = File.expand_path('../lib', __FILE__)
         | 
| 3 | 
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 4 | 
            +
            require 'fluent/plugin/cloudwatch/logs/version'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Gem::Specification.new do |spec|
         | 
| 7 | 
            +
              spec.name          = "fluent-plugin-cloudwatch-logs"
         | 
| 8 | 
            +
              spec.version       = Fluent::Plugin::Cloudwatch::Logs::VERSION
         | 
| 9 | 
            +
              spec.authors       = ["Ryota Arai"]
         | 
| 10 | 
            +
              spec.email         = ["ryota.arai@gmail.com"]
         | 
| 11 | 
            +
              spec.summary       = %q{CloudWatch Logs Plugin for Fluentd}
         | 
| 12 | 
            +
              spec.homepage      = "https://github.com/ryotarai/fluent-plugin-cloudwatch-logs"
         | 
| 13 | 
            +
              spec.license       = "MIT"
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              spec.files         = `git ls-files -z`.split("\x0")
         | 
| 16 | 
            +
              spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
         | 
| 17 | 
            +
              spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
         | 
| 18 | 
            +
              spec.require_paths = ["lib"]
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              spec.add_dependency 'fluentd'
         | 
| 21 | 
            +
              spec.add_dependency 'aws-sdk-core', '2.0.0.rc12'
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              spec.add_development_dependency "bundler", "~> 1.6"
         | 
| 24 | 
            +
              spec.add_development_dependency "rake"
         | 
| 25 | 
            +
            end
         | 
| @@ -0,0 +1,70 @@ | |
| 1 | 
            +
            module Fluent
         | 
| 2 | 
            +
              class CloudwatchLogsInput < Input
         | 
| 3 | 
            +
                Plugin.register_input('cloudwatch_logs', self)
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                config_param :tag, :string
         | 
| 6 | 
            +
                config_param :log_group_name, :string
         | 
| 7 | 
            +
                config_param :log_stream_name, :string
         | 
| 8 | 
            +
                config_param :state_file, :string
         | 
| 9 | 
            +
                config_param :fetch_interval, :time, default: 60
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def initialize
         | 
| 12 | 
            +
                  super
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  require 'aws-sdk-core'
         | 
| 15 | 
            +
                  @logs = Aws::CloudWatchLogs.new
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                def start
         | 
| 19 | 
            +
                  @finished = false
         | 
| 20 | 
            +
                  @thread = Thread.new(&method(:run))
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def shutdown
         | 
| 24 | 
            +
                  @finished = true
         | 
| 25 | 
            +
                  @thread.join
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                private
         | 
| 29 | 
            +
                def next_token
         | 
| 30 | 
            +
                  return nil unless File.exist?(@state_file)
         | 
| 31 | 
            +
                  File.read(@state_file).chomp
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def store_next_token(token)
         | 
| 35 | 
            +
                  open(@state_file, 'w') do |f|
         | 
| 36 | 
            +
                    f.write token
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                def run
         | 
| 41 | 
            +
                  @next_fetch_time = Time.now
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  until @finished
         | 
| 44 | 
            +
                    if Time.now > @next_fetch_time
         | 
| 45 | 
            +
                      @next_fetch_time += @fetch_interval
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                      events = get_events
         | 
| 48 | 
            +
                      events.each do |event|
         | 
| 49 | 
            +
                        time = (event.timestamp / 1000).floor
         | 
| 50 | 
            +
                        record = JSON.parse(event.message)
         | 
| 51 | 
            +
                        Engine.emit(@tag, time, record)
         | 
| 52 | 
            +
                      end
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
                    sleep 1
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                def get_events
         | 
| 59 | 
            +
                  request = {
         | 
| 60 | 
            +
                    log_group_name: @log_group_name,
         | 
| 61 | 
            +
                    log_stream_name: @log_stream_name,
         | 
| 62 | 
            +
                  }
         | 
| 63 | 
            +
                  request[:next_token] = next_token if next_token
         | 
| 64 | 
            +
                  response = @logs.get_log_events(request)
         | 
| 65 | 
            +
                  store_next_token(response.next_forward_token)
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  response.events
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
            end
         | 
| @@ -0,0 +1,81 @@ | |
| 1 | 
            +
            module Fluent
         | 
| 2 | 
            +
              class CloudwatchLogsOutput < BufferedOutput
         | 
| 3 | 
            +
                Plugin.register_output('cloudwatch_logs', self)
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                config_param :log_group_name, :string
         | 
| 6 | 
            +
                config_param :log_stream_name, :string
         | 
| 7 | 
            +
                config_param :sequence_token_file, :string
         | 
| 8 | 
            +
                config_param :auto_create_stream, :bool, default: false
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                unless method_defined?(:log)
         | 
| 11 | 
            +
                  define_method(:log) { $log }
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def initialize
         | 
| 15 | 
            +
                  super
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  require 'aws-sdk-core'
         | 
| 18 | 
            +
                  @logs = Aws::CloudWatchLogs.new
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def configure(conf)
         | 
| 22 | 
            +
                  super
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  create_stream if @auto_create_stream
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def format(tag, time, record)
         | 
| 28 | 
            +
                  [tag, time, record].to_msgpack
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def write(chunk)
         | 
| 32 | 
            +
                  events = []
         | 
| 33 | 
            +
                  chunk.msgpack_each do |tag, time, record|
         | 
| 34 | 
            +
                    time_ms = time * 1000
         | 
| 35 | 
            +
                    events << {timestamp: time_ms, message: record.to_json}
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
                  put_events(events)
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                private
         | 
| 41 | 
            +
                def next_sequence_token
         | 
| 42 | 
            +
                  return nil unless File.exist?(@sequence_token_file)
         | 
| 43 | 
            +
                  open(@sequence_token_file) {|f| f.read }.chomp
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def store_next_sequence_token(token)
         | 
| 47 | 
            +
                  open(@sequence_token_file, 'w') do |f|
         | 
| 48 | 
            +
                    f.write token
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                def put_events(events)
         | 
| 53 | 
            +
                  args = {
         | 
| 54 | 
            +
                    log_events: events,
         | 
| 55 | 
            +
                    log_group_name: @log_group_name,
         | 
| 56 | 
            +
                    log_stream_name: @log_stream_name,
         | 
| 57 | 
            +
                  }
         | 
| 58 | 
            +
                  args[:sequence_token] = next_sequence_token if next_sequence_token
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  response = @logs.put_log_events(args)
         | 
| 61 | 
            +
                  store_next_sequence_token(response.next_sequence_token)
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                def create_stream
         | 
| 65 | 
            +
                  log.debug "Creating log stream '#{@log_stream_name}' in log group '#{@log_group_name}'"
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  begin
         | 
| 68 | 
            +
                    @logs.create_log_group(log_group_name: @log_group_name)
         | 
| 69 | 
            +
                  rescue Aws::CloudWatchLogs::Errors::ResourceAlreadyExistsException
         | 
| 70 | 
            +
                    log.debug "Log group '#{@log_group_name}' already exists"
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  begin
         | 
| 74 | 
            +
                    @logs.create_log_stream(log_group_name: @log_group_name, log_stream_name: @log_stream_name)
         | 
| 75 | 
            +
                  rescue Aws::CloudWatchLogs::Errors::ResourceAlreadyExistsException
         | 
| 76 | 
            +
                    log.debug "Log stream '#{@log_stream_name}' already exists"
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
              end
         | 
| 80 | 
            +
            end
         | 
| 81 | 
            +
             | 
| @@ -0,0 +1,68 @@ | |
| 1 | 
            +
            require 'test_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class CloudwatchLogsInputTest < Test::Unit::TestCase
         | 
| 4 | 
            +
              include CloudwatchLogsTestHelper
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              def setup
         | 
| 7 | 
            +
                Fluent::Test.setup
         | 
| 8 | 
            +
                require 'fluent/plugin/in_cloudwatch_logs'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              def teardown
         | 
| 13 | 
            +
                clear_log_group
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              def test_configure
         | 
| 17 | 
            +
                d = create_driver(<<-EOC)
         | 
| 18 | 
            +
                  type cloudwatch_logs
         | 
| 19 | 
            +
                  tag test
         | 
| 20 | 
            +
                  log_group_name group
         | 
| 21 | 
            +
                  log_stream_name stream
         | 
| 22 | 
            +
                  state_file /tmp/state
         | 
| 23 | 
            +
                EOC
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                assert_equal('test', d.instance.tag)
         | 
| 26 | 
            +
                assert_equal('group', d.instance.log_group_name)
         | 
| 27 | 
            +
                assert_equal('stream', d.instance.log_stream_name)
         | 
| 28 | 
            +
                assert_equal('/tmp/state', d.instance.state_file)
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              def test_emit
         | 
| 32 | 
            +
                create_log_stream
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                time_ms = (Time.now.to_f * 1000).floor
         | 
| 35 | 
            +
                put_log_events([
         | 
| 36 | 
            +
                  {timestamp: time_ms, message: '{"cloudwatch":"logs1"}'},
         | 
| 37 | 
            +
                  {timestamp: time_ms, message: '{"cloudwatch":"logs2"}'},
         | 
| 38 | 
            +
                ])
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                sleep 5
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                d = create_driver
         | 
| 43 | 
            +
                d.run do
         | 
| 44 | 
            +
                  sleep 5
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
                
         | 
| 47 | 
            +
                emits = d.emits
         | 
| 48 | 
            +
                assert_equal(2, emits.size)
         | 
| 49 | 
            +
                assert_equal(['test', (time_ms / 1000).floor, {'cloudwatch' => 'logs1'}], emits[0])
         | 
| 50 | 
            +
                assert_equal(['test', (time_ms / 1000).floor, {'cloudwatch' => 'logs2'}], emits[1])
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              private
         | 
| 54 | 
            +
              def default_config
         | 
| 55 | 
            +
                <<-EOC
         | 
| 56 | 
            +
                  tag test
         | 
| 57 | 
            +
                  type cloudwatch_logs
         | 
| 58 | 
            +
                  log_group_name #{log_group_name}
         | 
| 59 | 
            +
                  log_stream_name #{log_stream_name}
         | 
| 60 | 
            +
                  state_file /tmp/state
         | 
| 61 | 
            +
                EOC
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
              def create_driver(conf = default_config)
         | 
| 65 | 
            +
                Fluent::Test::InputTestDriver.new(Fluent::CloudwatchLogsInput).configure(conf)
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
            end
         | 
| 68 | 
            +
             | 
| @@ -0,0 +1,73 @@ | |
| 1 | 
            +
            require 'test_helper'
         | 
| 2 | 
            +
            require 'fileutils'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            class CloudwatchLogsOutputTest < Test::Unit::TestCase
         | 
| 5 | 
            +
              include CloudwatchLogsTestHelper
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              def setup
         | 
| 8 | 
            +
                Fluent::Test.setup
         | 
| 9 | 
            +
                require 'fluent/plugin/out_cloudwatch_logs'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                @logs = Aws::CloudWatchLogs.new
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              def teardown
         | 
| 15 | 
            +
                clear_log_group
         | 
| 16 | 
            +
                FileUtils.rm_f(sequence_token_file)
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
              
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              def test_configure
         | 
| 21 | 
            +
                d = create_driver(<<-EOC)
         | 
| 22 | 
            +
                  type cloudwatch_logs
         | 
| 23 | 
            +
                  log_group_name test_group
         | 
| 24 | 
            +
                  log_stream_name test_stream
         | 
| 25 | 
            +
                  sequence_token_file /tmp/sq
         | 
| 26 | 
            +
                  auto_create_stream false
         | 
| 27 | 
            +
                EOC
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                assert_equal('test_group', d.instance.log_group_name)
         | 
| 30 | 
            +
                assert_equal('test_stream', d.instance.log_stream_name)
         | 
| 31 | 
            +
                assert_equal('/tmp/sq', d.instance.sequence_token_file)
         | 
| 32 | 
            +
                assert_equal(false, d.instance.auto_create_stream)
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              def test_write
         | 
| 36 | 
            +
                new_log_stream
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                d = create_driver
         | 
| 39 | 
            +
                time = Time.now
         | 
| 40 | 
            +
                d.emit({'cloudwatch' => 'logs1'}, time.to_i)
         | 
| 41 | 
            +
                d.emit({'cloudwatch' => 'logs2'}, time.to_i + 1)
         | 
| 42 | 
            +
                d.run
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                sleep 5
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                events = get_log_events
         | 
| 47 | 
            +
                assert_equal(2, events.size)
         | 
| 48 | 
            +
                assert_equal(time.to_i * 1000, events[0].timestamp)
         | 
| 49 | 
            +
                assert_equal('{"cloudwatch":"logs1"}', events[0].message)
         | 
| 50 | 
            +
                assert_equal((time.to_i + 1) * 1000, events[1].timestamp)
         | 
| 51 | 
            +
                assert_equal('{"cloudwatch":"logs2"}', events[1].message)
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              private
         | 
| 55 | 
            +
              def default_config
         | 
| 56 | 
            +
                <<-EOC
         | 
| 57 | 
            +
                type cloudwatch_logs
         | 
| 58 | 
            +
                log_group_name #{log_group_name}
         | 
| 59 | 
            +
                log_stream_name #{log_stream_name}
         | 
| 60 | 
            +
                sequence_token_file #{sequence_token_file}
         | 
| 61 | 
            +
                auto_create_stream true
         | 
| 62 | 
            +
                EOC
         | 
| 63 | 
            +
              end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
              def sequence_token_file
         | 
| 66 | 
            +
                File.expand_path('../../tmp/sequence_token', __FILE__)
         | 
| 67 | 
            +
              end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
             | 
| 70 | 
            +
              def create_driver(conf = default_config)
         | 
| 71 | 
            +
                Fluent::Test::BufferedOutputTestDriver.new(Fluent::CloudwatchLogsOutput).configure(conf)
         | 
| 72 | 
            +
              end
         | 
| 73 | 
            +
            end
         | 
    
        data/test/test_helper.rb
    ADDED
    
    | @@ -0,0 +1,60 @@ | |
| 1 | 
            +
            require 'test/unit'
         | 
| 2 | 
            +
            require 'fluent/test'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require 'aws-sdk-core'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module CloudwatchLogsTestHelper
         | 
| 7 | 
            +
              private
         | 
| 8 | 
            +
              def logs
         | 
| 9 | 
            +
                @logs ||= Aws::CloudWatchLogs.new
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              def log_group_name
         | 
| 13 | 
            +
                @log_group_name ||= "fluent-plugin-cloudwatch-test-#{Time.now.to_f}"
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              def log_stream_name
         | 
| 17 | 
            +
                if !@log_stream_name
         | 
| 18 | 
            +
                  new_log_stream
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
                @log_stream_name
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              def new_log_stream
         | 
| 24 | 
            +
                @log_stream_name = Time.now.to_f.to_s
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              def clear_log_group
         | 
| 28 | 
            +
                logs.delete_log_group(log_group_name: log_group_name)
         | 
| 29 | 
            +
              rescue Aws::CloudWatchLogs::Errors::ResourceNotFoundException
         | 
| 30 | 
            +
                # pass
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              def create_log_stream
         | 
| 34 | 
            +
                begin
         | 
| 35 | 
            +
                  logs.create_log_group(log_group_name: log_group_name)
         | 
| 36 | 
            +
                rescue Aws::CloudWatchLogs::Errors::ResourceAlreadyExistsException
         | 
| 37 | 
            +
                  # pass
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                begin
         | 
| 41 | 
            +
                  logs.create_log_stream(log_group_name: log_group_name, log_stream_name: log_stream_name)
         | 
| 42 | 
            +
                rescue Aws::CloudWatchLogs::Errors::ResourceAlreadyExistsException
         | 
| 43 | 
            +
                  # pass
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              def get_log_events
         | 
| 48 | 
            +
                logs.get_log_events(log_group_name: log_group_name, log_stream_name: log_stream_name).events
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              def put_log_events(events)
         | 
| 52 | 
            +
                args = {
         | 
| 53 | 
            +
                  log_events: events,
         | 
| 54 | 
            +
                  log_group_name: log_group_name,
         | 
| 55 | 
            +
                  log_stream_name: log_stream_name,
         | 
| 56 | 
            +
                }
         | 
| 57 | 
            +
                logs.put_log_events(args)
         | 
| 58 | 
            +
              end
         | 
| 59 | 
            +
            end
         | 
| 60 | 
            +
             | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,117 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: fluent-plugin-cloudwatch-logs
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.0.1
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Ryota Arai
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2014-07-16 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: fluentd
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - ">="
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '0'
         | 
| 20 | 
            +
              type: :runtime
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - ">="
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: '0'
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: aws-sdk-core
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - '='
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: 2.0.0.rc12
         | 
| 34 | 
            +
              type: :runtime
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - '='
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: 2.0.0.rc12
         | 
| 41 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            +
              name: bundler
         | 
| 43 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            +
                requirements:
         | 
| 45 | 
            +
                - - "~>"
         | 
| 46 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            +
                    version: '1.6'
         | 
| 48 | 
            +
              type: :development
         | 
| 49 | 
            +
              prerelease: false
         | 
| 50 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            +
                requirements:
         | 
| 52 | 
            +
                - - "~>"
         | 
| 53 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                    version: '1.6'
         | 
| 55 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            +
              name: rake
         | 
| 57 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - ">="
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: '0'
         | 
| 62 | 
            +
              type: :development
         | 
| 63 | 
            +
              prerelease: false
         | 
| 64 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
                requirements:
         | 
| 66 | 
            +
                - - ">="
         | 
| 67 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                    version: '0'
         | 
| 69 | 
            +
            description: 
         | 
| 70 | 
            +
            email:
         | 
| 71 | 
            +
            - ryota.arai@gmail.com
         | 
| 72 | 
            +
            executables: []
         | 
| 73 | 
            +
            extensions: []
         | 
| 74 | 
            +
            extra_rdoc_files: []
         | 
| 75 | 
            +
            files:
         | 
| 76 | 
            +
            - ".gitignore"
         | 
| 77 | 
            +
            - Gemfile
         | 
| 78 | 
            +
            - LICENSE.txt
         | 
| 79 | 
            +
            - README.md
         | 
| 80 | 
            +
            - Rakefile
         | 
| 81 | 
            +
            - example/fluentd.conf
         | 
| 82 | 
            +
            - fluent-plugin-cloudwatch-logs.gemspec
         | 
| 83 | 
            +
            - lib/fluent/plugin/cloudwatch/logs.rb
         | 
| 84 | 
            +
            - lib/fluent/plugin/cloudwatch/logs/version.rb
         | 
| 85 | 
            +
            - lib/fluent/plugin/in_cloudwatch_logs.rb
         | 
| 86 | 
            +
            - lib/fluent/plugin/out_cloudwatch_logs.rb
         | 
| 87 | 
            +
            - test/plugin/test_in_cloudwatch_logs.rb
         | 
| 88 | 
            +
            - test/plugin/test_out_cloudwatch_logs.rb
         | 
| 89 | 
            +
            - test/test_helper.rb
         | 
| 90 | 
            +
            homepage: https://github.com/ryotarai/fluent-plugin-cloudwatch-logs
         | 
| 91 | 
            +
            licenses:
         | 
| 92 | 
            +
            - MIT
         | 
| 93 | 
            +
            metadata: {}
         | 
| 94 | 
            +
            post_install_message: 
         | 
| 95 | 
            +
            rdoc_options: []
         | 
| 96 | 
            +
            require_paths:
         | 
| 97 | 
            +
            - lib
         | 
| 98 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 99 | 
            +
              requirements:
         | 
| 100 | 
            +
              - - ">="
         | 
| 101 | 
            +
                - !ruby/object:Gem::Version
         | 
| 102 | 
            +
                  version: '0'
         | 
| 103 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 104 | 
            +
              requirements:
         | 
| 105 | 
            +
              - - ">="
         | 
| 106 | 
            +
                - !ruby/object:Gem::Version
         | 
| 107 | 
            +
                  version: '0'
         | 
| 108 | 
            +
            requirements: []
         | 
| 109 | 
            +
            rubyforge_project: 
         | 
| 110 | 
            +
            rubygems_version: 2.2.2
         | 
| 111 | 
            +
            signing_key: 
         | 
| 112 | 
            +
            specification_version: 4
         | 
| 113 | 
            +
            summary: CloudWatch Logs Plugin for Fluentd
         | 
| 114 | 
            +
            test_files:
         | 
| 115 | 
            +
            - test/plugin/test_in_cloudwatch_logs.rb
         | 
| 116 | 
            +
            - test/plugin/test_out_cloudwatch_logs.rb
         | 
| 117 | 
            +
            - test/test_helper.rb
         |