fluent-plugin-td 1.1.0 → 1.2.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 +4 -4
- data/.circleci/config.yml +51 -0
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/codeql-analysis.yml +31 -0
- data/.gitignore +1 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +95 -0
- data/fluent-plugin-td.gemspec +17 -17
- data/lib/fluent/plugin/out_tdlog.rb +15 -11
- data/lib/fluent/plugin/td_plugin_version.rb +1 -1
- data/test/plugin/test_out_tdlog.rb +35 -3
- data/test/test_helper.rb +2 -1
- metadata +51 -25
- data/.travis.yml +0 -18
- data/Gemfile.msgpack.0.4 +0 -5
- data/Gemfile.v0.12 +0 -6
- data/lib/fluent/plugin/td_plugin_util.rb +0 -107
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a08410b0e8078a20d2150bacc0cde7cc14cfb70be600fbcc86309b5df1b7076c
|
|
4
|
+
data.tar.gz: 4aca6ca191fa4401f198b323cd0ae12c1616de67e640bc8111237af6eca8f976
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a776e4f86f5793451a04e76a9db1eb746ffb762d53e3781f1f20c8187663dcd8c575ef9814207c546831bd6192674661c6c38041998928f98ec159bbcd40d85c
|
|
7
|
+
data.tar.gz: 03a5a89b24a49813255dbe340b84b9dcd3abba74373dbb655d2220f3803f6beac8dbe6e9211312750ef00f59cf0f0b7e794c68810321b00aab20d4124d1997e3
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
version: 2.1
|
|
2
|
+
orbs:
|
|
3
|
+
ruby: circleci/ruby@1.8
|
|
4
|
+
jobs:
|
|
5
|
+
test:
|
|
6
|
+
parameters:
|
|
7
|
+
ruby-version:
|
|
8
|
+
type: string
|
|
9
|
+
docker:
|
|
10
|
+
- image: cimg/ruby:<< parameters.ruby-version >>
|
|
11
|
+
steps:
|
|
12
|
+
- checkout
|
|
13
|
+
- ruby/install-deps
|
|
14
|
+
- run:
|
|
15
|
+
name: Run tests
|
|
16
|
+
command: bundle exec rake test
|
|
17
|
+
publish:
|
|
18
|
+
docker:
|
|
19
|
+
- image: cimg/ruby:2.4
|
|
20
|
+
steps:
|
|
21
|
+
- checkout
|
|
22
|
+
- ruby/install-deps
|
|
23
|
+
- run:
|
|
24
|
+
name: Publish gem
|
|
25
|
+
command: |
|
|
26
|
+
mkdir -p $HOME/.gem
|
|
27
|
+
touch $HOME/.gem/credentials
|
|
28
|
+
chmod 0600 $HOME/.gem/credentials
|
|
29
|
+
printf -- "---\n:rubygems_api_key: ${RUBYGEMS_AUTH_TOKEN}\n" > $HOME/.gem/credentials
|
|
30
|
+
gem build *.gemspec
|
|
31
|
+
gem push *.gem
|
|
32
|
+
workflows:
|
|
33
|
+
version: 2
|
|
34
|
+
test:
|
|
35
|
+
jobs:
|
|
36
|
+
- test:
|
|
37
|
+
matrix:
|
|
38
|
+
parameters:
|
|
39
|
+
ruby-version: [ "2.4", "2.5", "2.6", "2.7", "3.0", "3.1" ]
|
|
40
|
+
filters:
|
|
41
|
+
tags:
|
|
42
|
+
only: /v[0-9]+(\.[0-9]+)*/
|
|
43
|
+
- publish:
|
|
44
|
+
context: rubygems
|
|
45
|
+
requires:
|
|
46
|
+
- test
|
|
47
|
+
filters:
|
|
48
|
+
branches:
|
|
49
|
+
ignore: /.*/
|
|
50
|
+
tags:
|
|
51
|
+
only: /v[0-9]+(\.[0-9]+)*/
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: "CodeQL"
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [ master ]
|
|
5
|
+
pull_request:
|
|
6
|
+
branches: [ master ]
|
|
7
|
+
schedule:
|
|
8
|
+
- cron: '37 9 * * 3'
|
|
9
|
+
jobs:
|
|
10
|
+
analyze:
|
|
11
|
+
name: Analyze
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
permissions:
|
|
14
|
+
actions: read
|
|
15
|
+
contents: read
|
|
16
|
+
security-events: write
|
|
17
|
+
strategy:
|
|
18
|
+
fail-fast: false
|
|
19
|
+
matrix:
|
|
20
|
+
language: [ 'ruby' ]
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout repository
|
|
23
|
+
uses: actions/checkout@v3
|
|
24
|
+
- name: Initialize CodeQL
|
|
25
|
+
uses: github/codeql-action/init@v2
|
|
26
|
+
with:
|
|
27
|
+
languages: ${{ matrix.language }}
|
|
28
|
+
- name: Autobuild
|
|
29
|
+
uses: github/codeql-action/autobuild@v2
|
|
30
|
+
- name: Perform CodeQL Analysis
|
|
31
|
+
uses: github/codeql-action/analyze@v2
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
fluent-plugin-td (1.2.0)
|
|
5
|
+
fluentd (>= 0.14.13, < 2)
|
|
6
|
+
td-client (>= 1.0.8)
|
|
7
|
+
|
|
8
|
+
GEM
|
|
9
|
+
remote: https://rubygems.org/
|
|
10
|
+
specs:
|
|
11
|
+
addressable (2.8.0)
|
|
12
|
+
public_suffix (>= 2.0.2, < 5.0)
|
|
13
|
+
ast (2.4.2)
|
|
14
|
+
concurrent-ruby (1.1.10)
|
|
15
|
+
cool.io (1.7.1)
|
|
16
|
+
crack (0.4.5)
|
|
17
|
+
rexml
|
|
18
|
+
fluentd (1.14.6)
|
|
19
|
+
bundler
|
|
20
|
+
cool.io (>= 1.4.5, < 2.0.0)
|
|
21
|
+
http_parser.rb (>= 0.5.1, < 0.9.0)
|
|
22
|
+
msgpack (>= 1.3.1, < 2.0.0)
|
|
23
|
+
serverengine (>= 2.2.5, < 3.0.0)
|
|
24
|
+
sigdump (~> 0.2.2)
|
|
25
|
+
strptime (>= 0.2.4, < 1.0.0)
|
|
26
|
+
tzinfo (>= 1.0, < 3.0)
|
|
27
|
+
tzinfo-data (~> 1.0)
|
|
28
|
+
webrick (>= 1.4.2, < 1.8.0)
|
|
29
|
+
yajl-ruby (~> 1.0)
|
|
30
|
+
hashdiff (1.0.1)
|
|
31
|
+
http_parser.rb (0.8.0)
|
|
32
|
+
httpclient (2.8.3)
|
|
33
|
+
msgpack (1.5.1)
|
|
34
|
+
parallel (1.20.1)
|
|
35
|
+
parser (3.1.2.0)
|
|
36
|
+
ast (~> 2.4.1)
|
|
37
|
+
power_assert (2.0.1)
|
|
38
|
+
public_suffix (4.0.7)
|
|
39
|
+
rainbow (3.1.1)
|
|
40
|
+
rake (13.0.6)
|
|
41
|
+
regexp_parser (2.4.0)
|
|
42
|
+
rexml (3.2.5)
|
|
43
|
+
rr (3.0.9)
|
|
44
|
+
rubocop (1.12.1)
|
|
45
|
+
parallel (~> 1.10)
|
|
46
|
+
parser (>= 3.0.0.0)
|
|
47
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
48
|
+
regexp_parser (>= 1.8, < 3.0)
|
|
49
|
+
rexml
|
|
50
|
+
rubocop-ast (>= 1.2.0, < 2.0)
|
|
51
|
+
ruby-progressbar (~> 1.7)
|
|
52
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
|
53
|
+
rubocop-ast (1.4.1)
|
|
54
|
+
parser (>= 2.7.1.5)
|
|
55
|
+
rubocop-rake (0.5.1)
|
|
56
|
+
rubocop
|
|
57
|
+
ruby-progressbar (1.11.0)
|
|
58
|
+
serverengine (2.2.5)
|
|
59
|
+
sigdump (~> 0.2.2)
|
|
60
|
+
sigdump (0.2.4)
|
|
61
|
+
strptime (0.2.5)
|
|
62
|
+
td-client (1.0.8)
|
|
63
|
+
httpclient (>= 2.7)
|
|
64
|
+
msgpack (>= 0.5.6, < 2)
|
|
65
|
+
test-unit (3.5.3)
|
|
66
|
+
power_assert
|
|
67
|
+
test-unit-rr (1.0.5)
|
|
68
|
+
rr (>= 1.1.1)
|
|
69
|
+
test-unit (>= 2.5.2)
|
|
70
|
+
tzinfo (2.0.4)
|
|
71
|
+
concurrent-ruby (~> 1.0)
|
|
72
|
+
tzinfo-data (1.2022.1)
|
|
73
|
+
tzinfo (>= 1.0.0)
|
|
74
|
+
unicode-display_width (2.1.0)
|
|
75
|
+
webmock (3.14.0)
|
|
76
|
+
addressable (>= 2.8.0)
|
|
77
|
+
crack (>= 0.3.2)
|
|
78
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
|
79
|
+
webrick (1.7.0)
|
|
80
|
+
yajl-ruby (1.4.1)
|
|
81
|
+
|
|
82
|
+
PLATFORMS
|
|
83
|
+
ruby
|
|
84
|
+
|
|
85
|
+
DEPENDENCIES
|
|
86
|
+
fluent-plugin-td!
|
|
87
|
+
rake (>= 0.9.2)
|
|
88
|
+
rubocop
|
|
89
|
+
rubocop-rake
|
|
90
|
+
test-unit (~> 3.5.3)
|
|
91
|
+
test-unit-rr (~> 1.0.5)
|
|
92
|
+
webmock (~> 3.14.0)
|
|
93
|
+
|
|
94
|
+
BUNDLED WITH
|
|
95
|
+
2.1.4
|
data/fluent-plugin-td.gemspec
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
$:.push File.expand_path('../lib', __FILE__)
|
|
3
|
-
require 'fluent/plugin/td_plugin_version'
|
|
1
|
+
require File.expand_path('../lib/fluent/plugin/td_plugin_version', __FILE__)
|
|
4
2
|
|
|
5
3
|
Gem::Specification.new do |gem|
|
|
6
|
-
gem.name =
|
|
7
|
-
gem.description =
|
|
8
|
-
gem.homepage =
|
|
4
|
+
gem.name = 'fluent-plugin-td'
|
|
5
|
+
gem.description = 'Treasure Data Cloud Data Service plugin for Fluentd'
|
|
6
|
+
gem.homepage = 'https://www.treasuredata.com/'
|
|
9
7
|
gem.summary = gem.description
|
|
10
8
|
gem.version = Fluent::Plugin::TreasureDataPlugin::VERSION
|
|
11
|
-
gem.authors = [
|
|
12
|
-
gem.email =
|
|
13
|
-
#gem.platform = Gem::Platform::RUBY
|
|
9
|
+
gem.authors = ['Treasure Data, Inc.']
|
|
10
|
+
gem.email = 'support@treasure-data.com'
|
|
14
11
|
gem.files = `git ls-files`.split("\n")
|
|
15
12
|
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
16
|
-
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
13
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
|
17
14
|
gem.require_paths = ['lib']
|
|
18
|
-
gem.license =
|
|
15
|
+
gem.license = 'Apache-2.0'
|
|
19
16
|
|
|
20
|
-
gem.
|
|
21
|
-
gem.add_dependency
|
|
22
|
-
gem.
|
|
23
|
-
gem.add_development_dependency
|
|
24
|
-
gem.add_development_dependency
|
|
25
|
-
gem.add_development_dependency
|
|
17
|
+
gem.required_ruby_version = '>= 2.4'
|
|
18
|
+
gem.add_dependency 'fluentd', ['>= 0.14.13', '< 2']
|
|
19
|
+
gem.add_dependency 'td-client', '>= 1.0.8'
|
|
20
|
+
gem.add_development_dependency 'rake', '>= 0.9.2'
|
|
21
|
+
gem.add_development_dependency 'rubocop'
|
|
22
|
+
gem.add_development_dependency 'rubocop-rake'
|
|
23
|
+
gem.add_development_dependency 'test-unit', '~> 3.5.3'
|
|
24
|
+
gem.add_development_dependency 'test-unit-rr', '~> 1.0.5'
|
|
25
|
+
gem.add_development_dependency 'webmock', '~> 3.14.0'
|
|
26
26
|
end
|
|
@@ -4,6 +4,7 @@ require 'zlib'
|
|
|
4
4
|
require 'stringio'
|
|
5
5
|
require 'td-client'
|
|
6
6
|
|
|
7
|
+
require 'fluent/error'
|
|
7
8
|
require 'fluent/plugin/output'
|
|
8
9
|
require 'fluent/plugin/td_plugin_version'
|
|
9
10
|
|
|
@@ -12,6 +13,7 @@ module Fluent::Plugin
|
|
|
12
13
|
Fluent::Plugin.register_output('tdlog', self)
|
|
13
14
|
|
|
14
15
|
IMPORT_SIZE_LIMIT = 32 * 1024 * 1024
|
|
16
|
+
IMPORT_RECORDS_LIMIT = 8096
|
|
15
17
|
UPLOAD_EXT = 'msgpack.gz'.freeze
|
|
16
18
|
|
|
17
19
|
helpers :event_emitter, :compat_parameters
|
|
@@ -36,13 +38,14 @@ module Fluent::Plugin
|
|
|
36
38
|
config_set_default :chunk_keys, ['tag']
|
|
37
39
|
config_set_default :flush_interval, 300
|
|
38
40
|
config_set_default :chunk_limit_size, IMPORT_SIZE_LIMIT
|
|
41
|
+
config_set_default :chunk_limit_records, IMPORT_RECORDS_LIMIT
|
|
39
42
|
end
|
|
40
43
|
|
|
41
44
|
def initialize
|
|
42
45
|
super
|
|
43
46
|
@key = nil
|
|
44
|
-
@key_num_limit = 512
|
|
45
|
-
@record_size_limit = 32 * 1024 * 1024
|
|
47
|
+
@key_num_limit = 512
|
|
48
|
+
@record_size_limit = 32 * 1024 * 1024
|
|
46
49
|
@table_list = {}
|
|
47
50
|
@empty_gz_data = TreasureData::API.create_empty_gz_data
|
|
48
51
|
@user_agent = "fluent-plugin-td: #{TreasureDataPlugin::VERSION}".freeze
|
|
@@ -107,7 +110,6 @@ module Fluent::Plugin
|
|
|
107
110
|
record.delete(:time) if record.has_key?(:time)
|
|
108
111
|
|
|
109
112
|
if record.size > @key_num_limit
|
|
110
|
-
# TODO include summary of the record
|
|
111
113
|
router.emit_error_event(tag, time, record, RuntimeError.new("too many number of keys (#{record.size} keys)"))
|
|
112
114
|
return nil
|
|
113
115
|
end
|
|
@@ -168,7 +170,6 @@ module Fluent::Plugin
|
|
|
168
170
|
f.close(true) if f
|
|
169
171
|
end
|
|
170
172
|
|
|
171
|
-
# TODO: Share this routine with s3 compressors
|
|
172
173
|
def gzip_by_command(chunk, tmp)
|
|
173
174
|
chunk_is_file = @buffer_config['@type'] == 'file'
|
|
174
175
|
path = if chunk_is_file
|
|
@@ -183,10 +184,8 @@ module Fluent::Plugin
|
|
|
183
184
|
res = system "gzip -c #{path} > #{tmp.path}"
|
|
184
185
|
unless res
|
|
185
186
|
log.warn "failed to execute gzip command. Fallback to GzipWriter. status = #{$?}"
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return gzip_by_writer(chunk, tmp)
|
|
189
|
-
end
|
|
187
|
+
tmp.truncate(0)
|
|
188
|
+
return gzip_by_writer(chunk, tmp)
|
|
190
189
|
end
|
|
191
190
|
File.size(tmp.path)
|
|
192
191
|
ensure
|
|
@@ -211,18 +210,22 @@ module Fluent::Plugin
|
|
|
211
210
|
unique_str = unique_id.unpack('C*').map { |x| "%02x" % x }.join
|
|
212
211
|
log.trace { "uploading logs to Treasure Data database=#{database} table=#{table} (#{size}bytes)" }
|
|
213
212
|
|
|
213
|
+
start = Time.now
|
|
214
214
|
begin
|
|
215
215
|
begin
|
|
216
|
-
start = Time.now
|
|
217
216
|
@client.import(database, table, UPLOAD_EXT, io, size, unique_str)
|
|
218
|
-
rescue TreasureData::NotFoundError
|
|
217
|
+
rescue TreasureData::NotFoundError
|
|
219
218
|
unless @auto_create_table
|
|
220
|
-
raise
|
|
219
|
+
raise
|
|
221
220
|
end
|
|
222
221
|
ensure_database_and_table(database, table)
|
|
223
222
|
io.pos = 0
|
|
224
223
|
retry
|
|
225
224
|
end
|
|
225
|
+
rescue TreasureData::TooManyRequestsError
|
|
226
|
+
raise
|
|
227
|
+
rescue TreasureData::ClientError => e
|
|
228
|
+
raise Fluent::UnrecoverableError.new(e.message)
|
|
226
229
|
rescue => e
|
|
227
230
|
elapsed = Time.now - start
|
|
228
231
|
ne = RuntimeError.new("Failed to upload to Treasure Data '#{database}.#{table}' table: #{e.inspect} (#{size} bytes; #{elapsed} seconds)")
|
|
@@ -269,6 +272,7 @@ module Fluent::Plugin
|
|
|
269
272
|
@api_client.create_database(database)
|
|
270
273
|
@api_client.create_log_table(database, table)
|
|
271
274
|
rescue TreasureData::AlreadyExistsError
|
|
275
|
+
# ignored
|
|
272
276
|
end
|
|
273
277
|
end
|
|
274
278
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require 'fluent/test'
|
|
2
2
|
require 'fluent/test/driver/output'
|
|
3
3
|
require 'fluent/plugin/out_tdlog'
|
|
4
|
-
require 'test_helper
|
|
4
|
+
require 'test_helper'
|
|
5
5
|
|
|
6
6
|
class TreasureDataLogOutputTest < Test::Unit::TestCase
|
|
7
7
|
TMP_DIR = File.dirname(__FILE__) + "/tmp"
|
|
@@ -144,7 +144,7 @@ class TreasureDataLogOutputTest < Test::Unit::TestCase
|
|
|
144
144
|
}
|
|
145
145
|
end
|
|
146
146
|
|
|
147
|
-
def
|
|
147
|
+
def test_emit_with_time_symbol
|
|
148
148
|
d = create_driver
|
|
149
149
|
time, records = stub_seed_values
|
|
150
150
|
database, table = d.instance.instance_variable_get(:@key).split(".", 2)
|
|
@@ -190,6 +190,38 @@ class TreasureDataLogOutputTest < Test::Unit::TestCase
|
|
|
190
190
|
assert_equal 1, d.error_events.size
|
|
191
191
|
end
|
|
192
192
|
|
|
193
|
+
def test_write_with_client_error
|
|
194
|
+
d = create_driver(DEFAULT_CONFIG)
|
|
195
|
+
time, records = stub_seed_values
|
|
196
|
+
database, table = d.instance.instance_variable_get(:@key).split(".", 2)
|
|
197
|
+
stub_td_table_create_request(database, table)
|
|
198
|
+
stub_td_import_request(stub_request_body(records, time), database, table, status: 400)
|
|
199
|
+
|
|
200
|
+
assert_nothing_raised(Fluent::UnrecoverableError) do
|
|
201
|
+
d.run(default_tag: 'test') {
|
|
202
|
+
records.each { |record|
|
|
203
|
+
d.feed(time, record)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def test_write_retry_if_too_many_requests
|
|
210
|
+
d = create_driver(DEFAULT_CONFIG)
|
|
211
|
+
time, records = stub_seed_values
|
|
212
|
+
database, table = d.instance.instance_variable_get(:@key).split(".", 2)
|
|
213
|
+
stub_td_table_create_request(database, table)
|
|
214
|
+
stub_td_import_request(stub_request_body(records, time), database, table, status: 429)
|
|
215
|
+
|
|
216
|
+
assert_raise(TreasureData::TooManyRequestsError) do
|
|
217
|
+
d.run(default_tag: 'test') {
|
|
218
|
+
records.each { |record|
|
|
219
|
+
d.feed(time, record)
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
193
225
|
sub_test_case 'tag splitting for database and table' do
|
|
194
226
|
def create_driver(conf = %[auto_create_table true])
|
|
195
227
|
config = BASE_CONFIG + conf
|
|
@@ -197,7 +229,7 @@ class TreasureDataLogOutputTest < Test::Unit::TestCase
|
|
|
197
229
|
Fluent::Test::Driver::Output.new(Fluent::Plugin::TreasureDataLogOutput).configure(config)
|
|
198
230
|
end
|
|
199
231
|
|
|
200
|
-
data('
|
|
232
|
+
data('event_time' => 'event_time', 'int_time' => 'int')
|
|
201
233
|
def test_tag_split(time_class)
|
|
202
234
|
d = create_driver
|
|
203
235
|
|
data/test/test_helper.rb
CHANGED
|
@@ -69,6 +69,7 @@ class Test::Unit::TestCase
|
|
|
69
69
|
opts[:use_ssl] = true unless opts.has_key?(:use_ssl)
|
|
70
70
|
format = opts[:format] || 'msgpack.gz'
|
|
71
71
|
schema = opts[:use_ssl] ? 'https' : 'http'
|
|
72
|
+
status = opts[:status] || 200
|
|
72
73
|
response = {"database" => db, "table" => table, "elapsed_time" => 0}.to_json
|
|
73
74
|
endpoint = opts[:endpoint] ? opts[:endpoint] : TreasureData::API::DEFAULT_IMPORT_ENDPOINT
|
|
74
75
|
|
|
@@ -80,6 +81,6 @@ class Test::Unit::TestCase
|
|
|
80
81
|
stub_request(:put, url_with_unique).with(:headers => {'Content-Type' => 'application/octet-stream'}) { |req|
|
|
81
82
|
@auth_header = req.headers["Authorization"]
|
|
82
83
|
stub_gzip_unwrap(req.body) == stub_gzip_unwrap(body)
|
|
83
|
-
}.to_return(:status =>
|
|
84
|
+
}.to_return(:status => status, :body => response)
|
|
84
85
|
end
|
|
85
86
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fluent-plugin-td
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Treasure Data, Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2022-05-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: fluentd
|
|
@@ -34,16 +34,16 @@ dependencies:
|
|
|
34
34
|
name: td-client
|
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
|
-
- - "
|
|
37
|
+
- - ">="
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version:
|
|
39
|
+
version: 1.0.8
|
|
40
40
|
type: :runtime
|
|
41
41
|
prerelease: false
|
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
|
43
43
|
requirements:
|
|
44
|
-
- - "
|
|
44
|
+
- - ">="
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
|
-
version:
|
|
46
|
+
version: 1.0.8
|
|
47
47
|
- !ruby/object:Gem::Dependency
|
|
48
48
|
name: rake
|
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -59,70 +59,98 @@ dependencies:
|
|
|
59
59
|
- !ruby/object:Gem::Version
|
|
60
60
|
version: 0.9.2
|
|
61
61
|
- !ruby/object:Gem::Dependency
|
|
62
|
-
name:
|
|
62
|
+
name: rubocop
|
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
|
64
64
|
requirements:
|
|
65
|
-
- - "
|
|
65
|
+
- - ">="
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
|
-
version: '
|
|
67
|
+
version: '0'
|
|
68
68
|
type: :development
|
|
69
69
|
prerelease: false
|
|
70
70
|
version_requirements: !ruby/object:Gem::Requirement
|
|
71
71
|
requirements:
|
|
72
|
-
- - "
|
|
72
|
+
- - ">="
|
|
73
73
|
- !ruby/object:Gem::Version
|
|
74
|
-
version: '
|
|
74
|
+
version: '0'
|
|
75
|
+
- !ruby/object:Gem::Dependency
|
|
76
|
+
name: rubocop-rake
|
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
82
|
+
type: :development
|
|
83
|
+
prerelease: false
|
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '0'
|
|
75
89
|
- !ruby/object:Gem::Dependency
|
|
76
90
|
name: test-unit
|
|
77
91
|
requirement: !ruby/object:Gem::Requirement
|
|
78
92
|
requirements:
|
|
79
93
|
- - "~>"
|
|
80
94
|
- !ruby/object:Gem::Version
|
|
81
|
-
version: 3.
|
|
95
|
+
version: 3.5.3
|
|
82
96
|
type: :development
|
|
83
97
|
prerelease: false
|
|
84
98
|
version_requirements: !ruby/object:Gem::Requirement
|
|
85
99
|
requirements:
|
|
86
100
|
- - "~>"
|
|
87
101
|
- !ruby/object:Gem::Version
|
|
88
|
-
version: 3.
|
|
102
|
+
version: 3.5.3
|
|
89
103
|
- !ruby/object:Gem::Dependency
|
|
90
104
|
name: test-unit-rr
|
|
91
105
|
requirement: !ruby/object:Gem::Requirement
|
|
92
106
|
requirements:
|
|
93
107
|
- - "~>"
|
|
94
108
|
- !ruby/object:Gem::Version
|
|
95
|
-
version: 1.0.
|
|
109
|
+
version: 1.0.5
|
|
96
110
|
type: :development
|
|
97
111
|
prerelease: false
|
|
98
112
|
version_requirements: !ruby/object:Gem::Requirement
|
|
99
113
|
requirements:
|
|
100
114
|
- - "~>"
|
|
101
115
|
- !ruby/object:Gem::Version
|
|
102
|
-
version: 1.0.
|
|
116
|
+
version: 1.0.5
|
|
117
|
+
- !ruby/object:Gem::Dependency
|
|
118
|
+
name: webmock
|
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - "~>"
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: 3.14.0
|
|
124
|
+
type: :development
|
|
125
|
+
prerelease: false
|
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
127
|
+
requirements:
|
|
128
|
+
- - "~>"
|
|
129
|
+
- !ruby/object:Gem::Version
|
|
130
|
+
version: 3.14.0
|
|
103
131
|
description: Treasure Data Cloud Data Service plugin for Fluentd
|
|
104
132
|
email: support@treasure-data.com
|
|
105
133
|
executables: []
|
|
106
134
|
extensions: []
|
|
107
135
|
extra_rdoc_files: []
|
|
108
136
|
files:
|
|
137
|
+
- ".circleci/config.yml"
|
|
138
|
+
- ".github/dependabot.yml"
|
|
139
|
+
- ".github/workflows/codeql-analysis.yml"
|
|
109
140
|
- ".gitignore"
|
|
110
|
-
- ".travis.yml"
|
|
111
141
|
- AUTHORS
|
|
112
142
|
- ChangeLog
|
|
113
143
|
- Gemfile
|
|
114
|
-
- Gemfile.
|
|
115
|
-
- Gemfile.v0.12
|
|
144
|
+
- Gemfile.lock
|
|
116
145
|
- README.rdoc
|
|
117
146
|
- Rakefile
|
|
118
147
|
- example.conf
|
|
119
148
|
- fluent-plugin-td.gemspec
|
|
120
149
|
- lib/fluent/plugin/out_tdlog.rb
|
|
121
|
-
- lib/fluent/plugin/td_plugin_util.rb
|
|
122
150
|
- lib/fluent/plugin/td_plugin_version.rb
|
|
123
151
|
- test/plugin/test_out_tdlog.rb
|
|
124
152
|
- test/test_helper.rb
|
|
125
|
-
homepage:
|
|
153
|
+
homepage: https://www.treasuredata.com/
|
|
126
154
|
licenses:
|
|
127
155
|
- Apache-2.0
|
|
128
156
|
metadata: {}
|
|
@@ -134,17 +162,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
134
162
|
requirements:
|
|
135
163
|
- - ">="
|
|
136
164
|
- !ruby/object:Gem::Version
|
|
137
|
-
version: '
|
|
165
|
+
version: '2.4'
|
|
138
166
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
139
167
|
requirements:
|
|
140
168
|
- - ">="
|
|
141
169
|
- !ruby/object:Gem::Version
|
|
142
170
|
version: '0'
|
|
143
171
|
requirements: []
|
|
144
|
-
rubygems_version: 3.
|
|
172
|
+
rubygems_version: 3.1.2
|
|
145
173
|
signing_key:
|
|
146
174
|
specification_version: 4
|
|
147
175
|
summary: Treasure Data Cloud Data Service plugin for Fluentd
|
|
148
|
-
test_files:
|
|
149
|
-
- test/plugin/test_out_tdlog.rb
|
|
150
|
-
- test/test_helper.rb
|
|
176
|
+
test_files: []
|
data/.travis.yml
DELETED
data/Gemfile.msgpack.0.4
DELETED
data/Gemfile.v0.12
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
module Fluent
|
|
2
|
-
module TDPluginUtil
|
|
3
|
-
require 'fileutils'
|
|
4
|
-
require 'stringio'
|
|
5
|
-
require 'tempfile'
|
|
6
|
-
require 'zlib'
|
|
7
|
-
require 'td-client'
|
|
8
|
-
|
|
9
|
-
def validate_database_and_table_name(database, table, conf)
|
|
10
|
-
begin
|
|
11
|
-
TreasureData::API.validate_database_name(database)
|
|
12
|
-
rescue => e
|
|
13
|
-
raise ConfigError, "Invalid database name #{database.inspect}: #{e}: #{conf}"
|
|
14
|
-
end
|
|
15
|
-
begin
|
|
16
|
-
TreasureData::API.validate_table_name(table)
|
|
17
|
-
rescue => e
|
|
18
|
-
raise ConfigError, "Invalid table name #{table.inspect}: #{e}: #{conf}"
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def parse_bool_parameter(param)
|
|
23
|
-
if param.empty?
|
|
24
|
-
true
|
|
25
|
-
else
|
|
26
|
-
param = Config.bool_value(param)
|
|
27
|
-
raise ConfigError, "'true' or 'false' is required for #{key} option on tdlog output" if param.nil?
|
|
28
|
-
param
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def summarize_record(record)
|
|
33
|
-
json = record.to_json
|
|
34
|
-
if json.size > 100
|
|
35
|
-
json[0..97] + "..."
|
|
36
|
-
else
|
|
37
|
-
json
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def check_table_existence(database, table)
|
|
42
|
-
@table_list ||= {}
|
|
43
|
-
key = "#{database}.#{table}"
|
|
44
|
-
unless @table_list.has_key?(key)
|
|
45
|
-
log.debug "checking whether table '#{key}' exists on Treasure Data"
|
|
46
|
-
io = StringIO.new(@empty_gz_data)
|
|
47
|
-
begin
|
|
48
|
-
# here doesn't check whether target table is item table or not because import-only user can't read the table status.
|
|
49
|
-
# So I use empty import request to check table existence.
|
|
50
|
-
@client.import(database, table, "msgpack.gz", io, io.size)
|
|
51
|
-
@table_list[key] = true
|
|
52
|
-
rescue TreasureData::NotFoundError
|
|
53
|
-
args = self.class == TreasureDataItemOutput ? ' -t item' : ''
|
|
54
|
-
raise "Table #{key.inspect} does not exist on Treasure Data. Use 'td table:create #{database} #{table}#{args}' to create it."
|
|
55
|
-
rescue => e
|
|
56
|
-
log.warn "failed to check table existence on Treasure Data", :error => e.inspect
|
|
57
|
-
log.debug_backtrace e
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def write(chunk)
|
|
63
|
-
unique_id = chunk.unique_id
|
|
64
|
-
database, table = chunk.key.split('.', 2)
|
|
65
|
-
|
|
66
|
-
FileUtils.mkdir_p(@tmpdir) unless @tmpdir.nil?
|
|
67
|
-
f = Tempfile.new(@tmpdir_prefix, @tmpdir)
|
|
68
|
-
w = Zlib::GzipWriter.new(f)
|
|
69
|
-
|
|
70
|
-
chunk.write_to(w)
|
|
71
|
-
w.finish
|
|
72
|
-
w = nil
|
|
73
|
-
|
|
74
|
-
size = f.pos
|
|
75
|
-
f.pos = 0
|
|
76
|
-
upload(database, table, f, size, unique_id)
|
|
77
|
-
ensure
|
|
78
|
-
w.close if w
|
|
79
|
-
f.close if f
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
# assume @client and @auto_create_table variable exist
|
|
83
|
-
def upload(database, table, io, size, unique_id)
|
|
84
|
-
unique_str = unique_id.unpack('C*').map {|x| "%02x" % x }.join
|
|
85
|
-
log.trace { "uploading logs to Treasure Data database=#{database} table=#{table} (#{size}bytes)" }
|
|
86
|
-
|
|
87
|
-
begin
|
|
88
|
-
begin
|
|
89
|
-
start = Time.now
|
|
90
|
-
@client.import(database, table, "msgpack.gz", io, size, unique_str)
|
|
91
|
-
rescue TreasureData::NotFoundError => e
|
|
92
|
-
unless @auto_create_table
|
|
93
|
-
raise e
|
|
94
|
-
end
|
|
95
|
-
ensure_database_and_table(database, table)
|
|
96
|
-
io.pos = 0
|
|
97
|
-
retry
|
|
98
|
-
end
|
|
99
|
-
rescue => e
|
|
100
|
-
elapsed = Time.now - start
|
|
101
|
-
ne = RuntimeError.new("Failed to upload to TreasureData: #{e} (#{size} bytes; #{elapsed} seconds)")
|
|
102
|
-
ne.set_backtrace(e.backtrace)
|
|
103
|
-
raise ne
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
end
|