logstash-integration-jdbc 5.2.4 → 5.4.11
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/CHANGELOG.md +50 -0
- data/docs/filter-jdbc_static.asciidoc +14 -2
- data/docs/filter-jdbc_streaming.asciidoc +1 -1
- data/docs/input-jdbc.asciidoc +41 -4
- data/lib/logstash/filters/jdbc/basic_database.rb +1 -1
- data/lib/logstash/filters/jdbc/read_only_database.rb +2 -2
- data/lib/logstash/filters/jdbc_static.rb +19 -10
- data/lib/logstash/inputs/jdbc.rb +69 -20
- data/lib/logstash/plugin_mixins/jdbc/common.rb +2 -1
- data/lib/logstash/plugin_mixins/jdbc/jdbc.rb +22 -17
- data/lib/logstash/plugin_mixins/jdbc/sequel_bootstrap.rb +21 -0
- data/lib/logstash/plugin_mixins/jdbc/statement_handler.rb +51 -45
- data/lib/logstash/plugin_mixins/jdbc/timezone_proxy.rb +61 -0
- data/lib/logstash/plugin_mixins/jdbc/value_tracking.rb +16 -3
- data/lib/logstash-integration-jdbc_jars.rb +4 -2
- data/logstash-integration-jdbc.gemspec +6 -6
- data/spec/filters/jdbc_static_spec.rb +10 -0
- data/spec/filters/jdbc_streaming_spec.rb +7 -10
- data/spec/inputs/integration/integ_spec.rb +28 -9
- data/spec/inputs/jdbc_spec.rb +202 -59
- data/spec/plugin_mixins/jdbc/timezone_proxy_spec.rb +68 -0
- data/spec/plugin_mixins/jdbc/value_tracking_spec.rb +113 -0
- data/vendor/jar-dependencies/org/apache/derby/derby/10.15.2.1/derby-10.15.2.1.jar +0 -0
- data/vendor/jar-dependencies/org/apache/derby/derbyclient/10.15.2.1/derbyclient-10.15.2.1.jar +0 -0
- data/vendor/jar-dependencies/org/apache/derby/derbyshared/10.15.2.1/derbyshared-10.15.2.1.jar +0 -0
- data/vendor/jar-dependencies/org/apache/derby/derbytools/10.15.2.1/derbytools-10.15.2.1.jar +0 -0
- metadata +39 -49
- data/lib/logstash/plugin_mixins/jdbc/checked_count_logger.rb +0 -43
- data/lib/logstash/plugin_mixins/jdbc/scheduler.rb +0 -175
- data/spec/plugin_mixins/jdbc/scheduler_spec.rb +0 -78
- data/vendor/jar-dependencies/org/apache/derby/derby/10.14.1.0/derby-10.14.1.0.jar +0 -0
- data/vendor/jar-dependencies/org/apache/derby/derbyclient/10.14.1.0/derbyclient-10.14.1.0.jar +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7604bb8967c9d63f585d14622ab18b70bc0d9e9b34e43bca6b6c59c9d05a6b76
|
4
|
+
data.tar.gz: 2e9d142376d12bbd1313142e79174d540d53e098e481330262e784c8177e4898
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 165749e33fed7d98b9635f6a1d74cdb05623563a3942d34c093ef761cd8e4f4784e6eb467a699909e5420ceef8fb4779c00e1b154845838052aa278a592ddc2a
|
7
|
+
data.tar.gz: b9a4e7822ea60c3dde25edd6a1a6e72837069a993046a050a05aa32e92172d4689624df12e85c31b79f62c40fd0f45f98700e07a678a7ea2656d9730f2f14a8e
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,53 @@
|
|
1
|
+
## 5.4.11
|
2
|
+
- Fixes an issue in which any one instance of a JDBC input plugin using `jdbc_default_timezone` changes the behaviour of plugin instances that do _not_ use `jdbc_default_timezone`, ensuring that timezone offsets remain consistent for each instance of the plugin _as configured_ [#151](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/151)
|
3
|
+
- Fixes an exception that could occur while reloading `jdbc_static` databases when the underlying connection to the remote has been broken [#165](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/165)
|
4
|
+
|
5
|
+
## 5.4.10
|
6
|
+
- Adds retry mechanism when checkout Derby from SVN repository [#158](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/158)
|
7
|
+
- [DOC] add known limitations and settings for connection issue [#167](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/167)
|
8
|
+
|
9
|
+
## 5.4.9
|
10
|
+
- Fix Derby missed driver classes when built locally for version 10.15 [#160](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/160)
|
11
|
+
|
12
|
+
## 5.4.8
|
13
|
+
- Update Derby with locally built 10.15.2.1 version [#155](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/155)
|
14
|
+
|
15
|
+
## 5.4.7
|
16
|
+
- Update sequel version to >= 5.74.0. It fixes the generic jdbc adapter to properly handle disconnect errors [#153](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/153)
|
17
|
+
|
18
|
+
## 5.4.6
|
19
|
+
- Update sequel version to >= 5.73.0. The ibmdb and jdbc/db2 adapters were fixed to properly handle disconnect errors, removing the related connection from the pool [#144](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/144)
|
20
|
+
|
21
|
+
## 5.4.5
|
22
|
+
- Pin sequel to < 5.72.0 due to ruby/bigdecimal#169 [#141](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/141)
|
23
|
+
|
24
|
+
## 5.4.4
|
25
|
+
- Fix: adaptations for JRuby 9.4 [#125](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/125)
|
26
|
+
|
27
|
+
## 5.4.3
|
28
|
+
- Fix crash when metadata file can't be deleted after moving under path.data [#136](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/136)
|
29
|
+
|
30
|
+
## 5.4.2
|
31
|
+
- Doc: described default_hash and tag_on_default_use interaction filter plugin [#122](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/122)
|
32
|
+
- Added new settings `statement_retry_attempts` and `statement_retry_attempts_wait_time` for retry of failed sql statement execution [#123](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/123)
|
33
|
+
|
34
|
+
## 5.4.1
|
35
|
+
- Bugfix leak which happened in creating a new Database pool for every query. The pool is now crated on registration and closed on plugin's `stop` [#119](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/119)
|
36
|
+
|
37
|
+
## 5.4.0
|
38
|
+
- Ambiguous Timestamp Support [#92](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/92)
|
39
|
+
- FIX: when encountering an ambiguous timestamp, the JDBC Input no longer crashes
|
40
|
+
- Added support for disambiguating timestamps in daylight saving time (DST) overlap periods
|
41
|
+
|
42
|
+
## 5.3.0
|
43
|
+
- Refactor: start using scheduler mixin [#110](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/110)
|
44
|
+
|
45
|
+
## 5.2.6
|
46
|
+
- Fix: change default path of 'last_run_metadata_path' to be rooted in the LS data.path folder and not in $HOME [#106](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/106)
|
47
|
+
|
48
|
+
## 5.2.5
|
49
|
+
- Fix: do not execute more queries with debug logging [#109](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/109)
|
50
|
+
|
1
51
|
## 5.2.4
|
2
52
|
- Fix: compatibility with all (>= 3.0) rufus-scheduler versions [#97](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/97)
|
3
53
|
|
@@ -111,10 +111,14 @@ filter {
|
|
111
111
|
query => "SELECT firstname, lastname FROM users WHERE userid = ? AND country = ?"
|
112
112
|
prepared_parameters => ["[loggedin_userid]", "[user_nation]"] <4>
|
113
113
|
target => "user" <5>
|
114
|
+
default_hash => { <6>
|
115
|
+
firstname => nil
|
116
|
+
lastname => nil
|
117
|
+
}
|
114
118
|
}
|
115
119
|
]
|
116
120
|
# using add_field here to add & rename values to the event root
|
117
|
-
add_field => { server_name => "%{[server][0][description]}" } <
|
121
|
+
add_field => { server_name => "%{[server][0][description]}" } <7>
|
118
122
|
add_field => { user_firstname => "%{[user][0][firstname]}" }
|
119
123
|
add_field => { user_lastname => "%{[user][0][lastname]}" }
|
120
124
|
remove_field => ["server", "user"]
|
@@ -127,6 +131,13 @@ filter {
|
|
127
131
|
jdbc_connection_string => "jdbc:postgresql://remotedb:5432/ls_test_2"
|
128
132
|
}
|
129
133
|
}
|
134
|
+
|
135
|
+
output {
|
136
|
+
if "_jdbcstaticdefaultsused" in [tags] {
|
137
|
+
# Print all the not found users
|
138
|
+
stdout { }
|
139
|
+
}
|
140
|
+
}
|
130
141
|
-----
|
131
142
|
<1> Queries an external database to fetch the dataset that will be cached
|
132
143
|
locally.
|
@@ -139,7 +150,8 @@ See <<plugins-{type}s-{plugin}-object_order>>.
|
|
139
150
|
follow the positional ordering.
|
140
151
|
<5> Specifies the event field that will store the looked-up data. If the lookup
|
141
152
|
returns multiple columns, the data is stored as a JSON object within the field.
|
142
|
-
<6>
|
153
|
+
<6> When the user is not found in the database, an event is created using data from the <<plugins-{type}s-{plugin}-local_lookups>> `default hash` setting, and the event is tagged with the list set in <<plugins-{type}s-{plugin}-tag_on_default_use>>.
|
154
|
+
<7> Takes data from the JSON object and stores it in top-level event fields for
|
143
155
|
easier analysis in Kibana.
|
144
156
|
|
145
157
|
Here's a full example:
|
@@ -21,7 +21,7 @@ include::{include_path}/plugin_header-integration.asciidoc[]
|
|
21
21
|
|
22
22
|
==== Description
|
23
23
|
|
24
|
-
This filter executes a SQL query and
|
24
|
+
This filter executes a SQL query and stores the result set in the field
|
25
25
|
specified as `target`.
|
26
26
|
It will cache the results locally in an LRU cache with expiry.
|
27
27
|
|
data/docs/input-jdbc.asciidoc
CHANGED
@@ -176,6 +176,29 @@ input {
|
|
176
176
|
}
|
177
177
|
---------------------------------------------------------------------------------------------------
|
178
178
|
|
179
|
+
==== Database-specific considerations
|
180
|
+
|
181
|
+
The JDBC input plugin leverages the https://github.com/jeremyevans/sequel[sequel] library to query databases through their JDBC drivers.
|
182
|
+
The implementation of drivers will vary, however, potentially leading to unexpected behavior.
|
183
|
+
|
184
|
+
===== Unable to reuse connections
|
185
|
+
|
186
|
+
Some databases - such as Sybase or SQL Anywhere - may have issues with stale connections, timing out between scheduled runs and never reconnecting.
|
187
|
+
|
188
|
+
To ensure connections are valid before queries are executed, enable <<plugins-{type}s-{plugin}-jdbc_validate_connection>> and set <<plugins-{type}s-{plugin}-jdbc_validation_timeout>> to a shorter interval than the <<plugins-{type}s-{plugin}-schedule>>.
|
189
|
+
|
190
|
+
[source,ruby]
|
191
|
+
---------------------------------------------------------------------------------------------------
|
192
|
+
input {
|
193
|
+
jdbc {
|
194
|
+
schedule => "* * * * *" # run every minute
|
195
|
+
jdbc_validate_connection => true
|
196
|
+
jdbc_validation_timeout => 50 # 50 seconds
|
197
|
+
}
|
198
|
+
}
|
199
|
+
---------------------------------------------------------------------------------------------------
|
200
|
+
|
201
|
+
|
179
202
|
|
180
203
|
[id="plugins-{type}s-{plugin}-options"]
|
181
204
|
==== Jdbc Input Configuration Options
|
@@ -286,10 +309,14 @@ JDBC connection string
|
|
286
309
|
===== `jdbc_default_timezone`
|
287
310
|
|
288
311
|
* Value type is <<string,string>>
|
312
|
+
** Value should be a canonical timezone or offset, such as `Europe/Paris` or `Etc/GMT+3`
|
313
|
+
** Value _may_ include square-bracketed extensions, such as `America/Denver[dst_enabled_on_overlap:true]`
|
289
314
|
* There is no default value for this setting.
|
290
315
|
|
291
|
-
|
292
|
-
|
316
|
+
[id="plugins-{type}s-{plugin}-jdbc_timezone_conv"]
|
317
|
+
====== Timezone conversion
|
318
|
+
|
319
|
+
Logstash and Elasticsearch expect timestamps to be expressed in UTC terms.
|
293
320
|
If your database has recorded timestamps that are relative to another timezone,
|
294
321
|
the database timezone if you will, then set this setting to be the timezone that
|
295
322
|
the database is using. However, as SQL does not allow for timezone data in
|
@@ -299,7 +326,15 @@ in relative UTC time in ISO8601 format.
|
|
299
326
|
|
300
327
|
Using this setting will manually assign a specified timezone offset, instead
|
301
328
|
of using the timezone setting of the local machine. You must use a canonical
|
302
|
-
timezone,
|
329
|
+
timezone, `America/Denver`, for example.
|
330
|
+
|
331
|
+
[id="plugins-{type}s-{plugin}-jdbc_ambiguous_timestamps"]
|
332
|
+
===== Ambiguous timestamps
|
333
|
+
|
334
|
+
While it is common to store local times in SQL's timestamp column type, many timezones change their offset during the course of a calendar year and therefore cannot be used with SQL's timestamp type to represent an ordered, continuous timeline.
|
335
|
+
For example in the `America/Chicago` zone when daylight saving time (DST) ends in the autumn, the clock rolls from `01:59:59` back to `01:00:00`, making any timestamp in the 2-hour period between `01:00:00CDT` and `02:00:00CST` on that day ambiguous.
|
336
|
+
|
337
|
+
When encountering an ambiguous timestamp caused by a DST transition, the query will fail unless the timezone specified here includes a square-bracketed instruction for how to handle overlapping periods (such as: `America/Chicago[dst_enabled_on_overlap:true]` or `Australia/Melbourne[dst_enabled_on_overlap:false]`).
|
303
338
|
|
304
339
|
[id="plugins-{type}s-{plugin}-plugin_timezone"]
|
305
340
|
===== `plugin_timezone`
|
@@ -479,10 +514,12 @@ How often to validate a connection (in seconds)
|
|
479
514
|
===== `last_run_metadata_path`
|
480
515
|
|
481
516
|
* Value type is <<string,string>>
|
482
|
-
* Default value is `"
|
517
|
+
* Default value is `"<path.data>/plugins/inputs/jdbc/logstash_jdbc_last_run"`
|
483
518
|
|
484
519
|
Path to file with last run time
|
485
520
|
|
521
|
+
In versions prior to 5.2.6 the metadata file was written to `$HOME/.logstash_jdbc_last_run`. If during a Logstash upgrade the file is found in "$HOME" it will be moved to the default location under "path.data". If the path is defined by the user then no automatic move is performed.
|
522
|
+
|
486
523
|
[id="plugins-{type}s-{plugin}-lowercase_column_names"]
|
487
524
|
===== `lowercase_column_names`
|
488
525
|
|
@@ -12,7 +12,7 @@ module LogStash module Filters module Jdbc
|
|
12
12
|
if connected?
|
13
13
|
result = @db[statement].count
|
14
14
|
else
|
15
|
-
debug_log_messages
|
15
|
+
debug_log_messages << "and there is no connection to the remote db at this time"
|
16
16
|
end
|
17
17
|
rescue ::Sequel::Error => err
|
18
18
|
# a fatal issue
|
@@ -32,7 +32,7 @@ module LogStash module Filters module Jdbc
|
|
32
32
|
if connected?
|
33
33
|
result = @db[statement].all
|
34
34
|
else
|
35
|
-
debug_log_messages
|
35
|
+
debug_log_messages << "and there is no connection to the remote db at this time"
|
36
36
|
end
|
37
37
|
rescue ::Sequel::Error => err
|
38
38
|
# a fatal issue
|
@@ -3,7 +3,7 @@ require "logstash-integration-jdbc_jars"
|
|
3
3
|
require "logstash/filters/base"
|
4
4
|
require "logstash/namespace"
|
5
5
|
require "logstash/plugin_mixins/ecs_compatibility_support"
|
6
|
-
require "logstash/plugin_mixins/
|
6
|
+
require "logstash/plugin_mixins/scheduler"
|
7
7
|
require_relative "jdbc/loader"
|
8
8
|
require_relative "jdbc/loader_schedule"
|
9
9
|
require_relative "jdbc/repeating_load_runner"
|
@@ -19,6 +19,8 @@ module LogStash module Filters class JdbcStatic < LogStash::Filters::Base
|
|
19
19
|
# adds ecs_compatibility config which could be :disabled or :v1
|
20
20
|
include LogStash::PluginMixins::ECSCompatibilitySupport(:disabled, :v1, :v8 => :v1)
|
21
21
|
|
22
|
+
include LogStash::PluginMixins::Scheduler
|
23
|
+
|
22
24
|
config_name "jdbc_static"
|
23
25
|
|
24
26
|
# Define the loaders, an Array of Hashes, to fetch remote data and create local tables.
|
@@ -162,7 +164,6 @@ module LogStash module Filters class JdbcStatic < LogStash::Filters::Base
|
|
162
164
|
end
|
163
165
|
|
164
166
|
def close
|
165
|
-
@scheduler.stop if @scheduler
|
166
167
|
@parsed_loaders.each(&:close)
|
167
168
|
@processor.close
|
168
169
|
end
|
@@ -175,9 +176,23 @@ module LogStash module Filters class JdbcStatic < LogStash::Filters::Base
|
|
175
176
|
private
|
176
177
|
|
177
178
|
def prepare_data_dir
|
179
|
+
# cleanup existing Derby file left behind in $HOME
|
180
|
+
derby_log = "#{ENV['HOME']}/derby.log"
|
181
|
+
if ::File.exist?(derby_log)
|
182
|
+
begin
|
183
|
+
::File.delete(derby_log)
|
184
|
+
rescue Errno::EPERM => e
|
185
|
+
@logger.warn("Can't delete temporary file #{derby_log} due to access permissions")
|
186
|
+
rescue e
|
187
|
+
@logger.warn("Can't delete temporary file #{derby_log}", {message => e.message})
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
178
191
|
# later, when local persistent databases are allowed set this property to LS_HOME/data/jdbc-static/
|
179
192
|
# must take multi-pipelines into account and more than one config using the same jdbc-static settings
|
180
|
-
|
193
|
+
path_data = Pathname.new(LogStash::SETTINGS.get_value("path.data")).join("plugins", "shared", "derby_home")
|
194
|
+
path_data.mkpath
|
195
|
+
java.lang.System.setProperty("derby.system.home", path_data.to_path)
|
181
196
|
logger.info("derby.system.home is: #{java.lang.System.getProperty("derby.system.home")}")
|
182
197
|
end
|
183
198
|
|
@@ -194,13 +209,7 @@ module LogStash module Filters class JdbcStatic < LogStash::Filters::Base
|
|
194
209
|
if @loader_schedule
|
195
210
|
@loader_runner = Jdbc::RepeatingLoadRunner.new(*runner_args)
|
196
211
|
@loader_runner.initial_load
|
197
|
-
@
|
198
|
-
start_cron_scheduler(@loader_schedule, thread_name: "[#{id}]-jdbc_static__scheduler") { @loader_runner.repeated_load }
|
199
|
-
cron_job = @scheduler.cron_jobs.first
|
200
|
-
if cron_job
|
201
|
-
frequency = cron_job.respond_to?(:rough_frequency) ? cron_job.rough_frequency : cron_job.frequency
|
202
|
-
logger.info("Loaders will execute every #{frequency} seconds", loader_schedule: @loader_schedule)
|
203
|
-
end
|
212
|
+
scheduler.cron(@loader_schedule) { @loader_runner.repeated_load }
|
204
213
|
else
|
205
214
|
@loader_runner = Jdbc::SingleLoadRunner.new(*runner_args)
|
206
215
|
@loader_runner.initial_load
|
data/lib/logstash/inputs/jdbc.rb
CHANGED
@@ -3,12 +3,12 @@ require "logstash/inputs/base"
|
|
3
3
|
require "logstash/namespace"
|
4
4
|
require "logstash/plugin_mixins/jdbc/common"
|
5
5
|
require "logstash/plugin_mixins/jdbc/jdbc"
|
6
|
-
require "logstash/plugin_mixins/jdbc/scheduler"
|
7
6
|
require "logstash/plugin_mixins/ecs_compatibility_support"
|
8
7
|
require "logstash/plugin_mixins/ecs_compatibility_support/target_check"
|
9
8
|
require "logstash/plugin_mixins/validator_support/field_reference_validation_adapter"
|
10
|
-
|
11
9
|
require "logstash/plugin_mixins/event_support/event_factory_adapter"
|
10
|
+
require "logstash/plugin_mixins/scheduler"
|
11
|
+
require "fileutils"
|
12
12
|
|
13
13
|
# this require_relative returns early unless the JRuby version is between 9.2.0.0 and 9.2.8.0
|
14
14
|
require_relative "tzinfo_jruby_patch"
|
@@ -146,6 +146,8 @@ module LogStash module Inputs class Jdbc < LogStash::Inputs::Base
|
|
146
146
|
# adds :field_reference validator adapter
|
147
147
|
extend LogStash::PluginMixins::ValidatorSupport::FieldReferenceValidationAdapter
|
148
148
|
|
149
|
+
include LogStash::PluginMixins::Scheduler
|
150
|
+
|
149
151
|
config_name "jdbc"
|
150
152
|
|
151
153
|
# If undefined, Logstash will complain, even if codec is unused.
|
@@ -178,8 +180,10 @@ module LogStash module Inputs class Jdbc < LogStash::Inputs::Base
|
|
178
180
|
# exactly once.
|
179
181
|
config :schedule, :validate => :string
|
180
182
|
|
181
|
-
# Path to file with last run time
|
182
|
-
|
183
|
+
# Path to file with last run time.
|
184
|
+
# The default will write file to `<path.data>/plugins/inputs/jdbc/logstash_jdbc_last_run`
|
185
|
+
# NOTE: it must be a file path and not a directory path
|
186
|
+
config :last_run_metadata_path, :validate => :string
|
183
187
|
|
184
188
|
# Use an incremental column value rather than a timestamp
|
185
189
|
config :use_column_value, :validate => :boolean, :default => false
|
@@ -230,13 +234,32 @@ module LogStash module Inputs class Jdbc < LogStash::Inputs::Base
|
|
230
234
|
config :target, :validate => :field_reference, :required => false
|
231
235
|
|
232
236
|
attr_reader :database # for test mocking/stubbing
|
237
|
+
attr_reader :last_run_metadata_file_path # path to the file used as last run storage
|
233
238
|
|
234
239
|
public
|
235
240
|
|
236
241
|
def register
|
237
242
|
@logger = self.logger
|
238
|
-
|
239
|
-
|
243
|
+
|
244
|
+
if @record_last_run
|
245
|
+
if @last_run_metadata_path.nil?
|
246
|
+
logstash_data_path = LogStash::SETTINGS.get_value("path.data")
|
247
|
+
logstash_data_path = Pathname.new(logstash_data_path).join("plugins", "inputs", "jdbc")
|
248
|
+
# Ensure that the filepath exists before writing, since it's deeply nested.
|
249
|
+
logstash_data_path.mkpath
|
250
|
+
logstash_data_file_path = logstash_data_path.join("logstash_jdbc_last_run")
|
251
|
+
|
252
|
+
ensure_default_metadatafile_location(logstash_data_file_path)
|
253
|
+
|
254
|
+
@last_run_metadata_file_path = logstash_data_file_path.to_path
|
255
|
+
else
|
256
|
+
# validate the path is a file and not a directory
|
257
|
+
if Pathname.new(@last_run_metadata_path).directory?
|
258
|
+
raise LogStash::ConfigurationError.new("The \"last_run_metadata_path\" argument must point to a file, received a directory: \"#{last_run_metadata_path}\"")
|
259
|
+
end
|
260
|
+
@last_run_metadata_file_path = @last_run_metadata_path
|
261
|
+
end
|
262
|
+
end
|
240
263
|
|
241
264
|
if @use_column_value
|
242
265
|
# Raise an error if @use_column_value is true, but no @tracking_column is set
|
@@ -259,8 +282,8 @@ module LogStash module Inputs class Jdbc < LogStash::Inputs::Base
|
|
259
282
|
end
|
260
283
|
end
|
261
284
|
|
262
|
-
set_value_tracker
|
263
|
-
|
285
|
+
set_value_tracker LogStash::PluginMixins::Jdbc::ValueTracking.build_last_value_tracker(self)
|
286
|
+
set_statement_handler LogStash::PluginMixins::Jdbc::StatementHandler.build_statement_handler(self)
|
264
287
|
|
265
288
|
@enable_encoding = !@charset.nil? || !@columns_charset.empty?
|
266
289
|
|
@@ -280,11 +303,25 @@ module LogStash module Inputs class Jdbc < LogStash::Inputs::Base
|
|
280
303
|
converters[encoding] = converter
|
281
304
|
end
|
282
305
|
end
|
306
|
+
|
307
|
+
load_driver
|
308
|
+
begin
|
309
|
+
open_jdbc_connection
|
310
|
+
rescue Sequel::DatabaseConnectionError,
|
311
|
+
Sequel::DatabaseError,
|
312
|
+
Sequel::InvalidValue,
|
313
|
+
Java::JavaSql::SQLException => e
|
314
|
+
details = { exception: e.class, message: e.message }
|
315
|
+
details[:cause] = e.cause.inspect if e.cause
|
316
|
+
details[:backtrace] = e.backtrace if @logger.debug?
|
317
|
+
@logger.warn("Exception when executing JDBC query", details)
|
318
|
+
raise(LogStash::ConfigurationError, "Can't create a connection pool to the database")
|
319
|
+
end
|
283
320
|
end # def register
|
284
321
|
|
285
322
|
# test injection points
|
286
|
-
def
|
287
|
-
@statement_handler =
|
323
|
+
def set_statement_handler(handler)
|
324
|
+
@statement_handler = handler
|
288
325
|
end
|
289
326
|
|
290
327
|
def set_value_tracker(instance)
|
@@ -292,24 +329,17 @@ module LogStash module Inputs class Jdbc < LogStash::Inputs::Base
|
|
292
329
|
end
|
293
330
|
|
294
331
|
def run(queue)
|
295
|
-
load_driver
|
296
332
|
if @schedule
|
297
|
-
# input thread
|
298
|
-
@
|
299
|
-
|
300
|
-
@scheduler.join
|
333
|
+
# scheduler input thread name example: "[my-oracle]|input|jdbc|scheduler"
|
334
|
+
scheduler.cron(@schedule) { execute_query(queue) }
|
335
|
+
scheduler.join
|
301
336
|
else
|
302
337
|
execute_query(queue)
|
303
338
|
end
|
304
339
|
end # def run
|
305
340
|
|
306
|
-
def close
|
307
|
-
@scheduler.shutdown if @scheduler
|
308
|
-
end
|
309
|
-
|
310
341
|
def stop
|
311
342
|
close_jdbc_connection
|
312
|
-
@scheduler.shutdown(:wait) if @scheduler
|
313
343
|
end
|
314
344
|
|
315
345
|
private
|
@@ -363,4 +393,23 @@ module LogStash module Inputs class Jdbc < LogStash::Inputs::Base
|
|
363
393
|
value
|
364
394
|
end
|
365
395
|
end
|
396
|
+
|
397
|
+
def ensure_default_metadatafile_location(metadata_new_path)
|
398
|
+
old_default_path = Pathname.new("#{ENV['HOME']}/.logstash_jdbc_last_run")
|
399
|
+
|
400
|
+
if old_default_path.exist? && !metadata_new_path.exist?
|
401
|
+
# Previous versions of the plugin hosted the state file into $HOME/.logstash_jdbc_last_run.
|
402
|
+
# Copy in the new location
|
403
|
+
FileUtils.cp(old_default_path.to_path, metadata_new_path.to_path)
|
404
|
+
begin
|
405
|
+
# If there is a permission error in the delete of the old file inform the user to give
|
406
|
+
# the correct access rights
|
407
|
+
::File.delete(old_default_path.to_path)
|
408
|
+
@logger.info("Successfully moved the #{old_default_path.to_path} into #{metadata_new_path.to_path}")
|
409
|
+
rescue => e
|
410
|
+
@logger.warn("Using new metadata file at #{metadata_new_path.to_path} but #{old_default_path} can't be removed.")
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
366
415
|
end end end # class LogStash::Inputs::Jdbc
|
@@ -24,7 +24,8 @@ module LogStash module PluginMixins module Jdbc
|
|
24
24
|
return @driver_impl if @driver_impl ||= nil
|
25
25
|
|
26
26
|
require "java"
|
27
|
-
|
27
|
+
|
28
|
+
require_relative "sequel_bootstrap"
|
28
29
|
require "sequel/adapters/jdbc"
|
29
30
|
|
30
31
|
# execute all the driver loading related duties in a serial fashion to avoid
|
@@ -4,7 +4,7 @@ require "logstash/config/mixin"
|
|
4
4
|
require "time"
|
5
5
|
require "date"
|
6
6
|
require_relative "value_tracking"
|
7
|
-
require_relative "
|
7
|
+
require_relative "timezone_proxy"
|
8
8
|
require_relative "statement_handler"
|
9
9
|
|
10
10
|
java_import java.util.concurrent.locks.ReentrantLock
|
@@ -83,7 +83,8 @@ module LogStash module PluginMixins module Jdbc
|
|
83
83
|
# Using this setting will manually assign a specified timezone offset, instead
|
84
84
|
# of using the timezone setting of the local machine. You must use a canonical
|
85
85
|
# timezone, *America/Denver*, for example.
|
86
|
-
config :jdbc_default_timezone, :validate => :
|
86
|
+
config :jdbc_default_timezone, :validate => :jdbc_timezone_spec
|
87
|
+
extend TimezoneProxy::JDBCTimezoneSpecValidator
|
87
88
|
|
88
89
|
# General/Vendor-specific Sequel configuration options.
|
89
90
|
#
|
@@ -103,6 +104,11 @@ module LogStash module PluginMixins module Jdbc
|
|
103
104
|
# Number of seconds to sleep between connection attempts
|
104
105
|
config :connection_retry_attempts_wait_time, :validate => :number, :default => 0.5
|
105
106
|
|
107
|
+
# Maximum number of times to try running statement
|
108
|
+
config :statement_retry_attempts, :validate => :number, :default => 1
|
109
|
+
# Number of seconds to sleep between statement execution
|
110
|
+
config :statement_retry_attempts_wait_time, :validate => :number, :default => 0.5
|
111
|
+
|
106
112
|
# give users the ability to force Sequel application side into using local timezone
|
107
113
|
config :plugin_timezone, :validate => ["local", "utc"], :default => "utc"
|
108
114
|
end
|
@@ -158,7 +164,7 @@ module LogStash module PluginMixins module Jdbc
|
|
158
164
|
@database.extension(:pagination)
|
159
165
|
if @jdbc_default_timezone
|
160
166
|
@database.extension(:named_timezones)
|
161
|
-
@database.timezone = @jdbc_default_timezone
|
167
|
+
@database.timezone = TimezoneProxy.load(@jdbc_default_timezone)
|
162
168
|
end
|
163
169
|
if @jdbc_validate_connection
|
164
170
|
@database.extension(:connection_validator)
|
@@ -187,31 +193,24 @@ module LogStash module PluginMixins module Jdbc
|
|
187
193
|
end
|
188
194
|
end
|
189
195
|
|
190
|
-
public
|
191
|
-
def prepare_jdbc_connection
|
192
|
-
@connection_lock = ReentrantLock.new
|
193
|
-
end
|
194
|
-
|
195
196
|
public
|
196
197
|
def close_jdbc_connection
|
197
198
|
begin
|
198
199
|
# pipeline restarts can also close the jdbc connection, block until the current executing statement is finished to avoid leaking connections
|
199
200
|
# connections in use won't really get closed
|
200
|
-
@connection_lock.lock
|
201
201
|
@database.disconnect if @database
|
202
202
|
rescue => e
|
203
203
|
@logger.warn("Failed to close connection", :exception => e)
|
204
|
-
ensure
|
205
|
-
@connection_lock.unlock
|
206
204
|
end
|
207
205
|
end
|
208
206
|
|
209
207
|
public
|
210
208
|
def execute_statement
|
211
209
|
success = false
|
210
|
+
retry_attempts = @statement_retry_attempts
|
211
|
+
|
212
212
|
begin
|
213
|
-
|
214
|
-
open_jdbc_connection
|
213
|
+
retry_attempts -= 1
|
215
214
|
sql_last_value = @use_column_value ? @value_tracker.value : Time.now.utc
|
216
215
|
@tracking_column_warning_sent = false
|
217
216
|
@statement_handler.perform_query(@database, @value_tracker.value) do |row|
|
@@ -219,17 +218,23 @@ module LogStash module PluginMixins module Jdbc
|
|
219
218
|
yield extract_values_from(row)
|
220
219
|
end
|
221
220
|
success = true
|
222
|
-
rescue Sequel::
|
221
|
+
rescue Sequel::Error, Java::JavaSql::SQLException => e
|
223
222
|
details = { exception: e.class, message: e.message }
|
224
223
|
details[:cause] = e.cause.inspect if e.cause
|
225
224
|
details[:backtrace] = e.backtrace if @logger.debug?
|
226
225
|
@logger.warn("Exception when executing JDBC query", details)
|
226
|
+
|
227
|
+
if retry_attempts == 0
|
228
|
+
@logger.error("Unable to execute statement. Tried #{@statement_retry_attempts} times.")
|
229
|
+
else
|
230
|
+
@logger.error("Unable to execute statement. Trying again.")
|
231
|
+
sleep(@statement_retry_attempts_wait_time)
|
232
|
+
retry
|
233
|
+
end
|
227
234
|
else
|
228
235
|
@value_tracker.set_value(sql_last_value)
|
229
|
-
ensure
|
230
|
-
close_jdbc_connection
|
231
|
-
@connection_lock.unlock
|
232
236
|
end
|
237
|
+
|
233
238
|
return success
|
234
239
|
end
|
235
240
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "sequel"
|
4
|
+
|
5
|
+
# prevent Sequel's datetime_class from being modified,
|
6
|
+
# and ensure behaviour is restored to the library's default
|
7
|
+
# if something else in the Ruby VM has already changed it.
|
8
|
+
Sequel.synchronize do
|
9
|
+
def Sequel.datetime_class=(klass)
|
10
|
+
# noop
|
11
|
+
end
|
12
|
+
def Sequel.datetime_class
|
13
|
+
::Time
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# load the named_timezones extension, which will attempt to
|
18
|
+
# override the global Sequel::datetime_class; for safety,
|
19
|
+
# we reset it once more.
|
20
|
+
Sequel.extension(:named_timezones)
|
21
|
+
Sequel.datetime_class = ::Time
|