fluent-plugin-gcs 0.1.0
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 +9 -0
- data/.travis.yml +11 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +13 -0
- data/README.md +197 -0
- data/Rakefile +11 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/fluent-plugin-gcs.gemspec +32 -0
- data/lib/fluent/plugin/gcs/object_creator.rb +92 -0
- data/lib/fluent/plugin/gcs/version.rb +5 -0
- data/lib/fluent/plugin/out_gcs.rb +161 -0
- metadata +168 -0
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
data/.travis.yml
ADDED
data/Gemfile
ADDED
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
|
+
[](https://travis-ci.org/daichirata/fluent-plugin-gcs) [](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,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,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: []
|