fluent-plugin-sql 0.6.1 → 1.0.0.rc1
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/.travis.yml +0 -1
- data/README.md +9 -0
- data/VERSION +1 -1
- data/lib/fluent/plugin/in_sql.rb +27 -39
- data/lib/fluent/plugin/out_sql.rb +41 -41
- data/test/plugin/test_in_sql.rb +12 -8
- data/test/plugin/test_out_sql.rb +12 -11
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e683b76d37276e4bbe276dc6148216c113e5267
|
4
|
+
data.tar.gz: 374e957bfaf1f9eea818a6d3bc9c9b370c58604f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a71af14e2817621d22c85ac31a49d54d6b7f224b605ce2febaf09fbe369b435b33df779b23196e37ac6fb5d3c5a26d2039cb5aadf24dc90ec5d105ba4b283c6
|
7
|
+
data.tar.gz: 593be077cfbc429c9502ad7b56c404cac24afbae65268d095c723339bb77a4645a5c4297d03a6cbf73dd269cdda69824d3e2e5d4d4b498406e8871c5e0fb775e
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -7,6 +7,15 @@ This SQL plugin has two parts:
|
|
7
7
|
1. SQL **input** plugin reads records from RDBMSes periodically. An example use case would be getting "diffs" of a table (based on the "updated_at" field).
|
8
8
|
2. SQL **output** plugin that writes records into RDBMes. An example use case would be aggregating server/app/sensor logs into RDBMS systems.
|
9
9
|
|
10
|
+
## Requirements
|
11
|
+
|
12
|
+
| fluent-plugin-sql | fluentd | ruby |
|
13
|
+
|-------------------|------------|--------|
|
14
|
+
| >= 1.0.0 | >= v0.14.4 | >= 2.1 |
|
15
|
+
| < 1.0.0 | < v0.14.0 | >= 1.9 |
|
16
|
+
|
17
|
+
NOTE: fluent-plugin-sql v1.0.0 is now RC. We will release stable v1.0.0 soon.
|
18
|
+
|
10
19
|
## Installation
|
11
20
|
|
12
21
|
$ fluent-gem install fluent-plugin-sql --no-document
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.0.rc1
|
data/lib/fluent/plugin/in_sql.rb
CHANGED
@@ -16,59 +16,47 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
|
19
|
-
require "fluent/input"
|
19
|
+
require "fluent/plugin/input"
|
20
20
|
|
21
|
-
module Fluent
|
21
|
+
module Fluent::Plugin
|
22
22
|
|
23
23
|
require 'active_record'
|
24
24
|
|
25
25
|
class SQLInput < Input
|
26
|
-
Plugin.register_input('sql', self)
|
27
|
-
|
28
|
-
# For fluentd v0.12.16 or earlier
|
29
|
-
class << self
|
30
|
-
unless method_defined?(:desc)
|
31
|
-
def desc(description)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
26
|
+
Fluent::Plugin.register_input('sql', self)
|
35
27
|
|
36
28
|
desc 'RDBMS host'
|
37
29
|
config_param :host, :string
|
38
30
|
desc 'RDBMS port'
|
39
|
-
config_param :port, :integer, :
|
31
|
+
config_param :port, :integer, default: nil
|
40
32
|
desc 'RDBMS driver name.'
|
41
33
|
config_param :adapter, :string
|
42
34
|
desc 'RDBMS database name'
|
43
35
|
config_param :database, :string
|
44
36
|
desc 'RDBMS login user name'
|
45
|
-
config_param :username, :string, :
|
37
|
+
config_param :username, :string, default: nil
|
46
38
|
desc 'RDBMS login password'
|
47
|
-
config_param :password, :string, :
|
39
|
+
config_param :password, :string, default: nil, secret: true
|
48
40
|
desc 'RDBMS socket path'
|
49
|
-
config_param :socket, :string, :
|
41
|
+
config_param :socket, :string, default: nil
|
50
42
|
|
51
43
|
desc 'path to a file to store last rows'
|
52
|
-
config_param :state_file, :string, :
|
44
|
+
config_param :state_file, :string, default: nil
|
53
45
|
desc 'prefix of tags of events. actual tag will be this_tag_prefix.tables_tag (optional)'
|
54
|
-
config_param :tag_prefix, :string, :
|
46
|
+
config_param :tag_prefix, :string, default: nil
|
55
47
|
desc 'interval to run SQLs (optional)'
|
56
|
-
config_param :select_interval, :time, :
|
48
|
+
config_param :select_interval, :time, default: 60
|
57
49
|
desc 'limit of number of rows for each SQL(optional)'
|
58
|
-
config_param :select_limit, :time, :
|
59
|
-
|
60
|
-
unless method_defined?(:log)
|
61
|
-
define_method(:log) { $log }
|
62
|
-
end
|
50
|
+
config_param :select_limit, :time, default: 500
|
63
51
|
|
64
52
|
class TableElement
|
65
|
-
include Configurable
|
53
|
+
include Fluent::Configurable
|
66
54
|
|
67
55
|
config_param :table, :string
|
68
|
-
config_param :tag, :string, :
|
69
|
-
config_param :update_column, :string, :
|
70
|
-
config_param :time_column, :string, :
|
71
|
-
config_param :primary_key, :string, :
|
56
|
+
config_param :tag, :string, default: nil
|
57
|
+
config_param :update_column, :string, default: nil
|
58
|
+
config_param :time_column, :string, default: nil
|
59
|
+
config_param :primary_key, :string, default: nil
|
72
60
|
|
73
61
|
def configure(conf)
|
74
62
|
super
|
@@ -127,9 +115,9 @@ module Fluent
|
|
127
115
|
relation = relation.order("#{@update_column} ASC")
|
128
116
|
relation = relation.limit(limit) if limit > 0
|
129
117
|
|
130
|
-
now = Engine.now
|
118
|
+
now = Fluent::Engine.now
|
131
119
|
|
132
|
-
me = MultiEventStream.new
|
120
|
+
me = Fluent::MultiEventStream.new
|
133
121
|
relation.each do |obj|
|
134
122
|
record = obj.serializable_hash rescue nil
|
135
123
|
if record
|
@@ -181,13 +169,13 @@ module Fluent
|
|
181
169
|
@state_store = @state_file.nil? ? MemoryStateStore.new : StateStore.new(@state_file)
|
182
170
|
|
183
171
|
config = {
|
184
|
-
:
|
185
|
-
:
|
186
|
-
:
|
187
|
-
:
|
188
|
-
:
|
189
|
-
:
|
190
|
-
:
|
172
|
+
adapter: @adapter,
|
173
|
+
host: @host,
|
174
|
+
port: @port,
|
175
|
+
database: @database,
|
176
|
+
username: @username,
|
177
|
+
password: @password,
|
178
|
+
socket: @socket,
|
191
179
|
}
|
192
180
|
|
193
181
|
# creates subclass of ActiveRecord::Base so that it can have different
|
@@ -230,7 +218,7 @@ module Fluent
|
|
230
218
|
log.info "Selecting '#{te.table}' table"
|
231
219
|
false
|
232
220
|
rescue => e
|
233
|
-
log.warn "Can't handle '#{te.table}' table. Ignoring.",
|
221
|
+
log.warn "Can't handle '#{te.table}' table. Ignoring.", error: e
|
234
222
|
log.warn_backtrace e.backtrace
|
235
223
|
true
|
236
224
|
end
|
@@ -264,7 +252,7 @@ module Fluent
|
|
264
252
|
@state_store.last_records[t.table] = t.emit_next_records(last_record, @select_limit)
|
265
253
|
@state_store.update!
|
266
254
|
rescue => e
|
267
|
-
log.error "unexpected error",
|
255
|
+
log.error "unexpected error", error: e
|
268
256
|
log.error_backtrace e.backtrace
|
269
257
|
end
|
270
258
|
end
|
@@ -1,59 +1,52 @@
|
|
1
|
-
require "fluent/output"
|
1
|
+
require "fluent/plugin/output"
|
2
2
|
|
3
|
-
module Fluent
|
4
|
-
class SQLOutput <
|
5
|
-
Plugin.register_output('sql', self)
|
3
|
+
module Fluent::Plugin
|
4
|
+
class SQLOutput < Output
|
5
|
+
Fluent::Plugin.register_output('sql', self)
|
6
6
|
|
7
|
-
|
8
|
-
include SetTagKeyMixin
|
7
|
+
DEFAULT_BUFFER_TYPE = "memory"
|
9
8
|
|
10
|
-
|
11
|
-
class << self
|
12
|
-
unless method_defined?(:desc)
|
13
|
-
def desc(description)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
9
|
+
helpers :inject, :compat_parameters, :event_emitter
|
17
10
|
|
18
11
|
desc 'RDBMS host'
|
19
12
|
config_param :host, :string
|
20
13
|
desc 'RDBMS port'
|
21
|
-
config_param :port, :integer, :
|
14
|
+
config_param :port, :integer, default: nil
|
22
15
|
desc 'RDBMS driver name.'
|
23
16
|
config_param :adapter, :string
|
24
17
|
desc 'RDBMS login user name'
|
25
|
-
config_param :username, :string, :
|
18
|
+
config_param :username, :string, default: nil
|
26
19
|
desc 'RDBMS login password'
|
27
|
-
config_param :password, :string, :
|
20
|
+
config_param :password, :string, default: nil, secret: true
|
28
21
|
desc 'RDBMS database name'
|
29
22
|
config_param :database, :string
|
30
23
|
desc 'RDBMS socket path'
|
31
|
-
config_param :socket, :string, :
|
24
|
+
config_param :socket, :string, default: nil
|
32
25
|
desc 'remove the given prefix from the events'
|
33
|
-
config_param :remove_tag_prefix, :string, :
|
26
|
+
config_param :remove_tag_prefix, :string, default: nil
|
34
27
|
desc 'enable fallback'
|
35
|
-
config_param :enable_fallback, :bool, :
|
36
|
-
|
37
|
-
attr_accessor :tables
|
28
|
+
config_param :enable_fallback, :bool, default: true
|
38
29
|
|
39
|
-
|
40
|
-
|
30
|
+
config_section :buffer do
|
31
|
+
config_set_default :@type, DEFAULT_BUFFER_TYPE
|
41
32
|
end
|
42
33
|
|
34
|
+
attr_accessor :tables
|
35
|
+
|
43
36
|
# TODO: Merge SQLInput's TableElement
|
44
37
|
class TableElement
|
45
|
-
include Configurable
|
38
|
+
include Fluent::Configurable
|
46
39
|
|
47
40
|
config_param :table, :string
|
48
41
|
config_param :column_mapping, :string
|
49
|
-
config_param :num_retries, :integer, :
|
42
|
+
config_param :num_retries, :integer, default: 5
|
50
43
|
|
51
44
|
attr_reader :model
|
52
45
|
attr_reader :pattern
|
53
46
|
|
54
47
|
def initialize(pattern, log, enable_fallback)
|
55
48
|
super()
|
56
|
-
@pattern = MatchPattern.create(pattern)
|
49
|
+
@pattern = Fluent::MatchPattern.create(pattern)
|
57
50
|
@log = log
|
58
51
|
@enable_fallback = enable_fallback
|
59
52
|
end
|
@@ -95,7 +88,7 @@ module Fluent
|
|
95
88
|
# format process should be moved to emit / format after supports error stream.
|
96
89
|
records << @model.new(@format_proc.call(data))
|
97
90
|
rescue => e
|
98
|
-
args = {
|
91
|
+
args = {error: e, table: @table, record: Yajl.dump(data)}
|
99
92
|
@log.warn "Failed to create the model. Ignore a record:", args
|
100
93
|
end
|
101
94
|
}
|
@@ -104,10 +97,10 @@ module Fluent
|
|
104
97
|
rescue ActiveRecord::StatementInvalid, ActiveRecord::Import::MissingColumnError => e
|
105
98
|
if @enable_fallback
|
106
99
|
# ignore other exceptions to use Fluentd retry mechanizm
|
107
|
-
@log.warn "Got deterministic error. Fallback to one-by-one import",
|
100
|
+
@log.warn "Got deterministic error. Fallback to one-by-one import", error: e
|
108
101
|
one_by_one_import(records)
|
109
102
|
else
|
110
|
-
$log.warn "Got deterministic error. Fallback is disabled",
|
103
|
+
$log.warn "Got deterministic error. Fallback is disabled", error: e
|
111
104
|
raise e
|
112
105
|
end
|
113
106
|
end
|
@@ -119,15 +112,15 @@ module Fluent
|
|
119
112
|
begin
|
120
113
|
@model.import([record])
|
121
114
|
rescue ActiveRecord::StatementInvalid, ActiveRecord::Import::MissingColumnError => e
|
122
|
-
@log.error "Got deterministic error again. Dump a record",
|
115
|
+
@log.error "Got deterministic error again. Dump a record", error: e, record: record
|
123
116
|
rescue => e
|
124
117
|
retries += 1
|
125
118
|
if retries > @num_retries
|
126
|
-
@log.error "Can't recover undeterministic error. Dump a record",
|
119
|
+
@log.error "Can't recover undeterministic error. Dump a record", error: e, record: record
|
127
120
|
next
|
128
121
|
end
|
129
122
|
|
130
|
-
@log.warn "Failed to import a record: retry number = #{retries}",
|
123
|
+
@log.warn "Failed to import a record: retry number = #{retries}", error: e
|
131
124
|
sleep 0.5
|
132
125
|
retry
|
133
126
|
end
|
@@ -154,6 +147,8 @@ module Fluent
|
|
154
147
|
end
|
155
148
|
|
156
149
|
def configure(conf)
|
150
|
+
compat_parameters_convert(conf, :inject, :buffer)
|
151
|
+
|
157
152
|
super
|
158
153
|
|
159
154
|
if remove_tag_prefix = conf['remove_tag_prefix']
|
@@ -177,7 +172,7 @@ module Fluent
|
|
177
172
|
@only_default = @tables.empty?
|
178
173
|
|
179
174
|
if @default_table.nil?
|
180
|
-
raise ConfigError, "There is no default table. <table> is required in sql output"
|
175
|
+
raise Fluent::ConfigError, "There is no default table. <table> is required in sql output"
|
181
176
|
end
|
182
177
|
end
|
183
178
|
|
@@ -185,13 +180,13 @@ module Fluent
|
|
185
180
|
super
|
186
181
|
|
187
182
|
config = {
|
188
|
-
:
|
189
|
-
:
|
190
|
-
:
|
191
|
-
:
|
192
|
-
:
|
193
|
-
:
|
194
|
-
:
|
183
|
+
adapter: @adapter,
|
184
|
+
host: @host,
|
185
|
+
port: @port,
|
186
|
+
database: @database,
|
187
|
+
username: @username,
|
188
|
+
password: @password,
|
189
|
+
socket: @socket,
|
195
190
|
}
|
196
191
|
|
197
192
|
@base_model = Class.new(ActiveRecord::Base) do
|
@@ -221,9 +216,14 @@ module Fluent
|
|
221
216
|
end
|
222
217
|
|
223
218
|
def format(tag, time, record)
|
219
|
+
record = inject_values_to_record(tag, time, record)
|
224
220
|
[tag, time, record].to_msgpack
|
225
221
|
end
|
226
222
|
|
223
|
+
def formatted_to_msgpack_binary
|
224
|
+
true
|
225
|
+
end
|
226
|
+
|
227
227
|
def write(chunk)
|
228
228
|
ActiveRecord::Base.connection_pool.with_connection do
|
229
229
|
|
@@ -244,7 +244,7 @@ module Fluent
|
|
244
244
|
log.info "Selecting '#{te.table}' table"
|
245
245
|
false
|
246
246
|
rescue => e
|
247
|
-
log.warn "Can't handle '#{te.table}' table. Ignoring.",
|
247
|
+
log.warn "Can't handle '#{te.table}' table. Ignoring.", error: e
|
248
248
|
log.warn_backtrace e.backtrace
|
249
249
|
true
|
250
250
|
end
|
data/test/plugin/test_in_sql.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "helper"
|
2
|
+
require "fluent/test/driver/input"
|
2
3
|
|
3
4
|
class SqlInputTest < Test::Unit::TestCase
|
4
5
|
def setup
|
@@ -28,7 +29,7 @@ class SqlInputTest < Test::Unit::TestCase
|
|
28
29
|
]
|
29
30
|
|
30
31
|
def create_driver(conf = CONFIG)
|
31
|
-
Fluent::Test::
|
32
|
+
Fluent::Test::Driver::Input.new(Fluent::Plugin::SQLInput).configure(conf)
|
32
33
|
end
|
33
34
|
|
34
35
|
def test_configure
|
@@ -65,18 +66,21 @@ class SqlInputTest < Test::Unit::TestCase
|
|
65
66
|
Message.create!(message: "message 2")
|
66
67
|
Message.create!(message: "message 3")
|
67
68
|
|
69
|
+
d.end_if do
|
70
|
+
d.record_count >= 3
|
71
|
+
end
|
68
72
|
d.run
|
69
73
|
|
70
|
-
assert_equal("db.logs", d.
|
74
|
+
assert_equal("db.logs", d.events[0][0])
|
71
75
|
expected = [
|
72
|
-
[d.
|
73
|
-
[d.
|
74
|
-
[d.
|
76
|
+
[d.events[0][1], "message 1"],
|
77
|
+
[d.events[1][1], "message 2"],
|
78
|
+
[d.events[2][1], "message 3"],
|
75
79
|
]
|
76
80
|
actual = [
|
77
|
-
[Time.parse(d.
|
78
|
-
[Time.parse(d.
|
79
|
-
[Time.parse(d.
|
81
|
+
[Time.parse(d.events[0][2]["updated_at"]).to_i, d.events[0][2]["message"]],
|
82
|
+
[Time.parse(d.events[1][2]["updated_at"]).to_i, d.events[1][2]["message"]],
|
83
|
+
[Time.parse(d.events[2][2]["updated_at"]).to_i, d.events[2][2]["message"]],
|
80
84
|
]
|
81
85
|
assert_equal(expected, actual)
|
82
86
|
end
|
data/test/plugin/test_out_sql.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "helper"
|
2
|
+
require "fluent/test/driver/output"
|
2
3
|
|
3
4
|
class SqlOutputTest < Test::Unit::TestCase
|
4
5
|
def setup
|
@@ -26,7 +27,7 @@ class SqlOutputTest < Test::Unit::TestCase
|
|
26
27
|
]
|
27
28
|
|
28
29
|
def create_driver(conf = CONFIG)
|
29
|
-
Fluent::Test::
|
30
|
+
Fluent::Test::Driver::Output.new(Fluent::Plugin::SQLOutput).configure(conf)
|
30
31
|
end
|
31
32
|
|
32
33
|
def test_configure
|
@@ -61,10 +62,10 @@ class SqlOutputTest < Test::Unit::TestCase
|
|
61
62
|
d = create_driver
|
62
63
|
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
63
64
|
|
64
|
-
d.
|
65
|
-
|
66
|
-
|
67
|
-
|
65
|
+
d.run(default_tag: 'test') do
|
66
|
+
d.feed(time, {"message" => "message1"})
|
67
|
+
d.feed(time, {"message" => "message2"})
|
68
|
+
end
|
68
69
|
|
69
70
|
default_table = d.instance.instance_variable_get(:@default_table)
|
70
71
|
model = default_table.instance_variable_get(:@model)
|
@@ -78,10 +79,10 @@ class SqlOutputTest < Test::Unit::TestCase
|
|
78
79
|
d = create_driver
|
79
80
|
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
80
81
|
|
81
|
-
d.
|
82
|
-
|
82
|
+
d.run(default_tag: 'test') do
|
83
|
+
d.feed(time, {"message" => "message1"})
|
84
|
+
d.feed(time, {"message" => "message2"})
|
83
85
|
|
84
|
-
d.run do
|
85
86
|
default_table = d.instance.instance_variable_get(:@default_table)
|
86
87
|
model = default_table.instance_variable_get(:@model)
|
87
88
|
mock(model).import(anything).at_least(1) do
|
@@ -95,10 +96,10 @@ class SqlOutputTest < Test::Unit::TestCase
|
|
95
96
|
d = create_driver
|
96
97
|
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
97
98
|
|
98
|
-
d.
|
99
|
-
|
99
|
+
d.run(default_tag: 'test') do
|
100
|
+
d.feed(time, {"message" => "message1"})
|
101
|
+
d.feed(time, {"message" => "message2"})
|
100
102
|
|
101
|
-
d.run do
|
102
103
|
default_table = d.instance.instance_variable_get(:@default_table)
|
103
104
|
model = default_table.instance_variable_get(:@model)
|
104
105
|
mock(model).import([anything, anything]).once do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-sql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sadayuki Furuhashi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fluentd
|
@@ -162,12 +162,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
162
162
|
version: '0'
|
163
163
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
164
164
|
requirements:
|
165
|
-
- - "
|
165
|
+
- - ">"
|
166
166
|
- !ruby/object:Gem::Version
|
167
|
-
version:
|
167
|
+
version: 1.3.1
|
168
168
|
requirements: []
|
169
169
|
rubyforge_project:
|
170
|
-
rubygems_version: 2.6.
|
170
|
+
rubygems_version: 2.6.13
|
171
171
|
signing_key:
|
172
172
|
specification_version: 4
|
173
173
|
summary: SQL input/output plugin for Fluentd event collector
|