fluent-plugin-gcs 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ac0dec9f5eadfcf591d969f57d8c0299e8f9060e
4
+ data.tar.gz: 6ca58b3c7a54526ac95d2711407491a7f8ccfed5
5
+ SHA512:
6
+ metadata.gz: f8e0681f28757ee42a811f623afdd987bcd59006574356cab3b64001f57c45ae6e64fdfb2cf6cd94eab258f554a886c79d50c52e18f8d38cc70d7f73a0980a57
7
+ data.tar.gz: cf27dad559db3e0306137cb395faf4268c96223d4da6dd2b06970ff2e060ecdc284a7cfaf7b4a5e158c855db6d59dbd903c337ad7ee9ec87ed7dcacb3cf85c61
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 2.1
5
+ - 2.2
6
+ - 2.3.0
7
+
8
+ before_install:
9
+ - gem update bundler
10
+
11
+ script: bundle exec rake test
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fluent-plugin-gcs.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2016 - Daichi HIRATA
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,197 @@
1
+ # fluent-plugin-gcs
2
+ [![Build Status](https://travis-ci.org/daichirata/fluent-plugin-gcs.svg?branch=master)](https://travis-ci.org/daichirata/fluent-plugin-gcs) [![Code Climate](https://codeclimate.com/github/daichirata/fluent-plugin-gcs/badges/gpa.svg)](https://codeclimate.com/github/daichirata/fluent-plugin-gcs)
3
+
4
+ Google Cloud Storage output plugin for [Fluentd](https://github.com/fluent/fluentd).
5
+
6
+ ## Installation
7
+
8
+ ``` shell
9
+ gem install fluent-plugin-gcs
10
+ ```
11
+
12
+ ## Examples
13
+
14
+ ```
15
+ <match pattern>
16
+ @type gcs
17
+
18
+ project YOUR_PROJECT
19
+ keyfile YOUR_KEYFILE_PATH
20
+ gcs_bucket YOUR_GCS_BUCKET_NAME
21
+ gcs_object_key_format %{path}%{time_slice}_%{index}.%{file_extension}
22
+ path logs/
23
+ buffer_path /var/log/fluent/gcs
24
+
25
+ time_slice_format %Y%m%d-%H
26
+ time_slice_wait 10m
27
+ utc
28
+ </match>
29
+ ```
30
+
31
+ ## Configuration
32
+
33
+ ### Authentication
34
+
35
+ You can provide the project and credential information to connect to the Storage
36
+ service, or if you are running on Google Compute Engine this configuration is taken care of for you.
37
+
38
+ **project**
39
+
40
+ Project identifier for GCS. Project are discovered in the following order:
41
+ * Specify project in `project`
42
+ * Discover project in environment variables `STORAGE_PROJECT`, `GOOGLE_CLOUD_PROJECT`, `GCLOUD_PROJECT`
43
+ * Discover GCE credentials
44
+
45
+ **keyfile**
46
+
47
+ Path of GCS service account credentials JSON file. Credentials are discovered in the following order:
48
+ * Specify credentials path in `keyfile`
49
+ * Discover credentials path in environment variables `GOOGLE_CLOUD_KEYFILE`, `GCLOUD_KEYFILE`
50
+ * Discover credentials JSON in environment variables `GOOGLE_CLOUD_KEYFILE_JSON`, `GCLOUD_KEYFILE_JSON`
51
+ * Discover credentials file in the Cloud SDK's path
52
+ * Discover GCE credentials
53
+
54
+ **client_retries**
55
+
56
+ Number of times to retry requests on server error.
57
+
58
+ **client_timeout**
59
+
60
+ Default timeout to use in requests.
61
+
62
+ **bucket (*required)**
63
+
64
+ GCS bucket name.
65
+
66
+ **store_as**
67
+
68
+ Archive format on GCS. You can use serveral format:
69
+
70
+ * gzip (default)
71
+ * json
72
+ * text
73
+
74
+ **path**
75
+
76
+ path prefix of the files on GCS. Default is "" (no prefix).
77
+
78
+ **object_key_format**
79
+
80
+ The format of GCS object keys. You can use several built-in variables:
81
+
82
+ * %{path}
83
+ * %{time_slice}
84
+ * %{index}
85
+ * %{file_extension}
86
+ * %{uuid_flush}
87
+ * %{hex_random}
88
+
89
+ to decide keys dynamically.
90
+
91
+ * `%{path}` is exactly the value of `path` configured in the configuration file. E.g., "logs/" in the example configuration above.
92
+ * `%{time_slice}` is the time-slice in text that are formatted with `time_slice_format`.
93
+ * `%{index}` is the sequential number starts from 0, increments when multiple files are uploaded to GCS in the same time slice.
94
+ * `%{file_extention}` is changed by the value of `store_as`.
95
+ * gzip - gz
96
+ * json - json
97
+ * text - txt
98
+ * `%{uuid_flush}` a uuid that is replaced everytime the buffer will be flushed
99
+ * `%{hex_random}` a random hex string that is replaced for each buffer chunk, not assured to be unique.
100
+ You can configure the length of string with a `hex_random_length` parameter (Default: 4).
101
+
102
+ The default format is `%{path}%{time_slice}_%{index}.%{file_extension}`.
103
+
104
+ **hex_random_length**
105
+
106
+ The length of `%{hex_random}` placeholder.
107
+
108
+ **transcoding**
109
+
110
+ Enable the decompressive form of transcoding.
111
+
112
+ See also [Transcoding of gzip-compressed files](https://cloud.google.com/storage/docs/transcoding).
113
+
114
+ **format**
115
+
116
+ Change one line format in the GCS object. You can use serveral format:
117
+
118
+ * out_file (default)
119
+ * json
120
+ * ltsv
121
+ * single_value
122
+
123
+ See also [official Formatter article](http://docs.fluentd.org/articles/formatter-plugin-overview).
124
+
125
+ **auto_create_bucket**
126
+
127
+ Create GCS bucket if it does not exists. Default is true.
128
+
129
+ TODO: rate limit
130
+
131
+ **acl**
132
+
133
+ Permission for the object in GCS. Acceptable values are:
134
+
135
+ * `auth_read` - File owner gets OWNER access, and allAuthenticatedUsers get READER access.
136
+ * `owner_full` - File owner gets OWNER access, and project team owners get OWNER access.
137
+ * `owner_read` - File owner gets OWNER access, and project team owners get READER access.
138
+ * `private` - File owner gets OWNER access.
139
+ * `project_private` - File owner gets OWNER access, and project team members get access according to their roles.
140
+ * `public_read` - File owner gets OWNER access, and allUsers get READER access.
141
+
142
+ Default is nil (bucket default object ACL). See also [official document](https://cloud.google.com/storage/docs/access-control/lists).
143
+
144
+ **encryption_key**, **encryption_key_sha256**
145
+
146
+ You can also choose to provide your own AES-256 key for server-side encryption. See also [Customer-supplied encryption keys](https://cloud.google.com/storage/docs/encryption#customer-supplied).
147
+
148
+ **overwrite**
149
+
150
+ Overwrite already existing path. Default is false, which raises an error
151
+ if a GCS object of the same path already exists, or increment the
152
+ `%{index}` placeholder until finding an absent path.
153
+
154
+ **buffer_path (*required)**
155
+
156
+ path prefix of the files to buffer logs.
157
+
158
+ **time_slice_format**
159
+
160
+ Format of the time used as the file name. Default is '%Y%m%d'. Use
161
+ '%Y%m%d%H' to split files hourly.
162
+
163
+ **time_slice_wait**
164
+
165
+ The time to wait old logs. Default is 10 minutes. Specify larger value if
166
+ old logs may reache.
167
+
168
+ **localtime**
169
+
170
+ Use Local time instead of UTC.
171
+
172
+ **utc**
173
+
174
+ Use UTC instead of local time.
175
+
176
+
177
+ And see [official Time Sliced Output article](http://docs.fluentd.org/articles/output-plugin-overview#time-sliced-output-parameters)
178
+
179
+ ### ObjectMetadata
180
+
181
+ User provided web-safe keys and arbitrary string values that will returned with requests for the file as "x-goog-meta-" response headers.
182
+
183
+ ```
184
+ <match *>
185
+ @type gcs
186
+
187
+ <object_metadata>
188
+ key KEY_DATA_1
189
+ value VALUE_DATA_1
190
+ </object_metadata>
191
+
192
+ <object_metadata>
193
+ key KEY_DATA_2
194
+ value VALUE_DATA_2
195
+ </object_metadata>
196
+ </match>
197
+ ```
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler"
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require "rake/testtask"
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.libs << "lib" << "test"
7
+ test.test_files = FileList["test/plugin/test_*.rb"]
8
+ test.verbose = true
9
+ end
10
+
11
+ task :default => [:test]
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "fluent/plugin/gcs"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,32 @@
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/gcs/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "fluent-plugin-gcs"
8
+ spec.version = Fluent::GCSPlugin::VERSION
9
+ spec.authors = ["Daichi HIRATA"]
10
+ spec.email = ["hirata.daichi@gmail.com"]
11
+ spec.summary = "Google Cloud Storage output plugin for Fluentd"
12
+ spec.description = "Google Cloud Storage output plugin for Fluentd"
13
+ spec.homepage = "https://github.com/daishirata/fluent-plugin-gcs"
14
+ spec.license = "Apache-2.0"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_runtime_dependency "fluentd", "~> 0.12.0"
24
+ spec.add_runtime_dependency "google-cloud-storage", "~> 0.21"
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.13"
27
+ spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "rr", "= 1.1.2"
29
+ spec.add_development_dependency "test-unit", ">= 3.0.8"
30
+ spec.add_development_dependency "test-unit-rr", ">= 1.0.3"
31
+ spec.add_development_dependency "timecop"
32
+ end
@@ -0,0 +1,92 @@
1
+ require "tempfile"
2
+ require "zlib"
3
+
4
+ module Fluent
5
+ module GCS
6
+ def self.discovered_object_creator(store_as, transcoding: nil)
7
+ case store_as
8
+ when :gzip
9
+ Fluent::GCS::GZipObjectCreator.new(transcoding)
10
+ when :json
11
+ Fluent::GCS::JSONObjectCreator.new
12
+ when :text
13
+ Fluent::GCS::TextObjectCreator.new
14
+ end
15
+ end
16
+
17
+ class ObjectCreator
18
+ def content_type
19
+ raise NotImplementedError
20
+ end
21
+
22
+ def content_encoding
23
+ nil
24
+ end
25
+
26
+ def file_extension
27
+ raise NotImplementedError
28
+ end
29
+
30
+ def write(chunk, io)
31
+ raise NotImplementedError
32
+ end
33
+
34
+ def create(chunk, &block)
35
+ Tempfile.create("fluent-plugin-gcs") do |f|
36
+ f.binmode
37
+ f.sync = true
38
+ write(chunk, f)
39
+ block.call(f)
40
+ end
41
+ end
42
+ end
43
+
44
+ class GZipObjectCreator < ObjectCreator
45
+ def initialize(transcoding)
46
+ @transcoding = transcoding
47
+ end
48
+
49
+ def content_type
50
+ @transcoding ? "text/plain" : "application/gzip"
51
+ end
52
+
53
+ def content_encoding
54
+ @transcoding ? "gzip" : nil
55
+ end
56
+
57
+ def file_extension
58
+ "gz"
59
+ end
60
+
61
+ def write(chunk, io)
62
+ writer = Zlib::GzipWriter.new(io)
63
+ chunk.write_to(writer)
64
+ writer.finish
65
+ end
66
+ end
67
+
68
+ class TextObjectCreator < ObjectCreator
69
+ def content_type
70
+ "text/plain"
71
+ end
72
+
73
+ def file_extension
74
+ "txt"
75
+ end
76
+
77
+ def write(chunk, io)
78
+ chunk.write_to(io)
79
+ end
80
+ end
81
+
82
+ class JSONObjectCreator < TextObjectCreator
83
+ def content_type
84
+ "application/json"
85
+ end
86
+
87
+ def file_extension
88
+ "json"
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,5 @@
1
+ module Fluent
2
+ module GCSPlugin
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,161 @@
1
+ require "securerandom"
2
+ require "digest"
3
+
4
+ require "fluent/plugin/gcs/object_creator"
5
+ require "fluent/plugin/gcs/version"
6
+
7
+ module Fluent
8
+ class GCSOutput < TimeSlicedOutput
9
+ Fluent::Plugin.register_output("gcs", self)
10
+
11
+ def initialize
12
+ super
13
+ require "google/cloud/storage"
14
+ end
15
+
16
+ config_param :project, :string, default: nil,
17
+ desc: "Project identifier for GCS"
18
+ config_param :keyfile, :string, default: nil,
19
+ desc: "Path of GCS service account credentials JSON file"
20
+ config_param :client_retries, :integer, default: nil,
21
+ desc: "Number of times to retry requests on server error"
22
+ config_param :client_timeout, :integer, default: nil,
23
+ desc: "Default timeout to use in requests"
24
+ config_param :bucket, :string,
25
+ desc: "Name of a GCS bucket"
26
+ config_param :object_key_format, :string, default: "%{path}%{time_slice}_%{index}.%{file_extension}",
27
+ desc: "Format of GCS object keys"
28
+ config_param :path, :string, default: "",
29
+ desc: "Path prefix of the files on GCS"
30
+ config_param :store_as, :enum, list: [:gzip, :json, :text], default: :gzip,
31
+ desc: "Archive format on GCS"
32
+ config_param :transcoding, :bool, default: false,
33
+ desc: "Enable the decompressive form of transcoding"
34
+ config_param :auto_create_bucket, :bool, default: true,
35
+ desc: "Create GCS bucket if it does not exists"
36
+ config_param :hex_random_length, :integer, default: 4,
37
+ desc: "Max length of `%{hex_random}` placeholder(4-16)"
38
+ config_param :overwrite, :bool, default: false,
39
+ desc: "Overwrite already existing path"
40
+ config_param :format, :string, default: "out_file",
41
+ desc: "Change one line format in the GCS object"
42
+ config_param :acl, :enum, list: [:auth_read, :owner_full, :owner_read, :private, :project_private, :public_read], default: nil,
43
+ desc: "Permission for the object in GCS"
44
+ config_param :encryption_key, :string, default: nil, secret: true,
45
+ desc: "Customer-supplied, AES-256 encryption key"
46
+ config_param :encryption_key_sha256, :string, default: nil, secret: true,
47
+ desc: "SHA256 hash of the customer-supplied, AES-256 encryption key"
48
+ config_section :object_metadata, required: false do
49
+ config_param :key, :string, default: ""
50
+ config_param :value, :string, default: ""
51
+ end
52
+ # TODO: gem "google-cloud-storage" does not support object lavel storage_class yet.
53
+ # config_param :storage_class, :string, default: "regional"
54
+
55
+ MAX_HEX_RANDOM_LENGTH = 32
56
+
57
+ def configure(conf)
58
+ super
59
+
60
+ if @encryption_key && @encryption_key_sha256.nil?
61
+ raise Fluent::ConfigError, "encryption_key_sha256 parameter must be provided if `encryption_key` is provided."
62
+ end
63
+
64
+ if @hex_random_length > MAX_HEX_RANDOM_LENGTH
65
+ raise Fluent::ConfigError, "hex_random_length parameter should be set to #{MAX_HEX_RANDOM_LENGTH} characters or less."
66
+ end
67
+
68
+ # The customer-supplied, AES-256 encryption key and hash used to encrypt the file.
69
+ @encryption_opts = {
70
+ encryption_key: @encryption_key,
71
+ encryption_key_sha256: @encryption_key_sha256
72
+ }
73
+
74
+ if @object_metadata
75
+ @object_metadata_hash = @object_metadata.map {|m| [m.key, m.value] }.to_h
76
+ end
77
+
78
+ @formatter = Fluent::Plugin.new_formatter(@format)
79
+ @formatter.configure(conf)
80
+
81
+ @object_creator = Fluent::GCS.discovered_object_creator(@store_as, transcoding: @transcoding)
82
+ end
83
+
84
+ def start
85
+ @gcs = Google::Cloud::Storage.new(
86
+ project: @project,
87
+ keyfile: @keyfile,
88
+ retries: @client_retries,
89
+ timeout: @client_timeout
90
+ )
91
+ @gcs_bucket = @gcs.bucket(@bucket)
92
+
93
+ ensure_bucket
94
+ super
95
+ end
96
+
97
+ def format(tag, time, record)
98
+ @formatter.format(tag, time, record)
99
+ end
100
+
101
+ def write(chunk)
102
+ path = generate_path(chunk)
103
+
104
+ @object_creator.create(chunk) do |obj|
105
+ opts = {
106
+ metadata: @object_metadata_hash,
107
+ acl: @acl,
108
+ content_type: @object_creator.content_type,
109
+ content_encoding: @object_creator.content_encoding,
110
+ }
111
+ opts.merge!(@encryption_opts)
112
+
113
+ log.debug { "out_gcs: upload chunk:#{chunk.key} to gcs://#{@bucket}/#{path} options: #{opts}" }
114
+ @gcs_bucket.upload_file(obj.path, path, opts)
115
+ end
116
+ end
117
+
118
+ private
119
+
120
+ def ensure_bucket
121
+ return unless @gcs_bucket.nil?
122
+
123
+ if !@auto_create_bucket
124
+ raise "bucket `#{@bucket}` does not exist"
125
+ end
126
+ log.info "creating bucket `#{@bucket}`"
127
+ @gcs_bucket = @gcs.create_bucket(@bucket)
128
+ end
129
+
130
+ def hex_random(chunk)
131
+ Digest::MD5.hexdigest(chunk.unique_id)[0...@hex_random_length]
132
+ end
133
+
134
+ def format_path(chunk)
135
+ now = Time.strptime(chunk.key, @time_slice_format)
136
+ (@localtime ? now : now.utc).strftime(@path)
137
+ end
138
+
139
+ def generate_path(chunk, i = 0, prev = nil)
140
+ tags = {
141
+ "%{file_extension}" => @object_creator.file_extension,
142
+ "%{hex_random}" => hex_random(chunk),
143
+ "%{index}" => i,
144
+ "%{path}" => format_path(chunk),
145
+ "%{time_slice}" => chunk.key,
146
+ "%{uuid_flush}" => SecureRandom.uuid,
147
+ }
148
+ path = @object_key_format.gsub(Regexp.union(tags.keys), tags)
149
+ return path unless @gcs_bucket.find_file(path, @encryption_opts)
150
+
151
+ if path == prev
152
+ if @overwrite
153
+ log.warn "object `#{path}` already exists but overwrites it"
154
+ return path
155
+ end
156
+ raise "object `#{path}` already exists"
157
+ end
158
+ generate_path(chunk, i + 1, path)
159
+ end
160
+ end
161
+ end
metadata ADDED
@@ -0,0 +1,168 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-gcs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Daichi HIRATA
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-11-27 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.12.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.12.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: google-cloud-storage
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.21'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.21'
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.13'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.13'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rr
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 1.1.2
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 1.1.2
83
+ - !ruby/object:Gem::Dependency
84
+ name: test-unit
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 3.0.8
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 3.0.8
97
+ - !ruby/object:Gem::Dependency
98
+ name: test-unit-rr
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 1.0.3
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 1.0.3
111
+ - !ruby/object:Gem::Dependency
112
+ name: timecop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: Google Cloud Storage output plugin for Fluentd
126
+ email:
127
+ - hirata.daichi@gmail.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".gitignore"
133
+ - ".travis.yml"
134
+ - Gemfile
135
+ - LICENSE.txt
136
+ - README.md
137
+ - Rakefile
138
+ - bin/console
139
+ - bin/setup
140
+ - fluent-plugin-gcs.gemspec
141
+ - lib/fluent/plugin/gcs/object_creator.rb
142
+ - lib/fluent/plugin/gcs/version.rb
143
+ - lib/fluent/plugin/out_gcs.rb
144
+ homepage: https://github.com/daishirata/fluent-plugin-gcs
145
+ licenses:
146
+ - Apache-2.0
147
+ metadata: {}
148
+ post_install_message:
149
+ rdoc_options: []
150
+ require_paths:
151
+ - lib
152
+ required_ruby_version: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - ">="
155
+ - !ruby/object:Gem::Version
156
+ version: '0'
157
+ required_rubygems_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: '0'
162
+ requirements: []
163
+ rubyforge_project:
164
+ rubygems_version: 2.5.1
165
+ signing_key:
166
+ specification_version: 4
167
+ summary: Google Cloud Storage output plugin for Fluentd
168
+ test_files: []