Skip to content

Commit 8d813e2

Browse files
authored
Add extra safety to local data retrieval (#78)
* Add extra safety to local data retrieval Under certain circumstances, retrieving local data from the embedded derby database can result in an exception being thrown from the Sequel library that is not wrapped in a `SequelError`. Prior to this commit, that would result in the exception "escaping" the plugin, causing the plugin (and the pipeline) to crash. This commit broadens the scope of the rescue to catch any errors that might result from that call, enabling the appropriate logging and tagging to take place without crashing the plugin. Fixes #77
1 parent f1bf6ae commit 8d813e2

File tree

6 files changed

+51
-7
lines changed

6 files changed

+51
-7
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 5.1.3
2+
- Improve robustness when handling errors from `sequel` library in jdbc static and streaming
3+
filters[#78](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/78)
4+
15
## 5.1.2
26
- Fix `prepared_statement_bind_values` in streaming filter to resolve nested event's fields[#76](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/76)
37

lib/logstash/filters/jdbc/lookup.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,11 @@ def retrieve_local_data(local, event, &proc)
162162
begin
163163
logger.debug? && logger.debug("Executing Jdbc query", :lookup_id => @id, :statement => query, :parameters => params)
164164
proc.call(local, query, params, result)
165-
rescue ::Sequel::Error => e
166-
# all sequel errors are a subclass of this, let all other standard or runtime errors bubble up
165+
rescue => e
166+
# In theory all exceptions in Sequel should be wrapped in Sequel::Error
167+
# However, there are cases where other errors can occur - a `SQLTransactionRollbackException`
168+
# may be thrown during `prepareStatement`. Let's handle these cases here, where we can tag and warn
169+
# appropriately rather than bubble up and potentially crash the plugin.
167170
result.failed!
168171
logger.warn? && logger.warn("Exception when executing Jdbc query", :lookup_id => @id, :exception => e.message, :backtrace => e.backtrace.take(8))
169172
end

lib/logstash/plugin_mixins/jdbc/jdbc.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,7 @@ def jdbc_connect
119119
else
120120
@logger.error("Failed to connect to database. #{@jdbc_pool_timeout} second timeout exceeded. Trying again.")
121121
end
122-
# rescue Java::JavaSql::SQLException, ::Sequel::Error => e
123-
rescue ::Sequel::Error => e
122+
rescue Java::JavaSql::SQLException, ::Sequel::Error => e
124123
if retry_attempts <= 0
125124
log_java_exception(e.cause)
126125
@logger.error("Unable to connect to database. Tried #{@connection_retry_attempts} times", error_details(e, trace: true))

lib/logstash/plugin_mixins/jdbc_streaming/statement_handler.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,11 @@ def common_cache_lookup(db, event)
3838
begin
3939
logger.debug? && logger.debug("Executing JDBC query", :statement => statement, :parameters => params)
4040
execute_extract_records(db, params, result)
41-
rescue ::Sequel::Error => e
42-
# all sequel errors are a subclass of this, let all other standard or runtime errors bubble up
41+
rescue => e
42+
# In theory all exceptions in Sequel should be wrapped in Sequel::Error
43+
# However, there are cases where other errors can occur - a `SQLException`may be thrown
44+
# during `prepareStatement`. Let's handle these cases here, where we can tag and warn
45+
# appropriately rather than bubble up and potentially crash the plugin.
4346
result.failed!
4447
logger.warn? && logger.warn("Exception when executing JDBC query", :statement => statement, :parameters => params, :exception => e)
4548
end

logstash-integration-jdbc.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Gem::Specification.new do |s|
22
s.name = 'logstash-integration-jdbc'
3-
s.version = '5.1.2'
3+
s.version = '5.1.3'
44
s.licenses = ['Apache License (2.0)']
55
s.summary = "Integration with JDBC - input and filter plugins"
66
s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"

spec/filters/jdbc/lookup_spec.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,41 @@ module LogStash module Filters module Jdbc
249249
end
250250
end
251251

252+
describe "lookup operations when prepareStatement throws" do
253+
let(:local_db) { double("local_db") }
254+
let(:lookup_hash) do
255+
{
256+
"query" => "select * from servers WHERE ip LIKE ? AND os LIKE ?",
257+
"prepared_parameters" => ["%%{[ip]}"],
258+
"target" => "server",
259+
"tag_on_failure" => ["_jdbcstaticfailure_server"]
260+
}
261+
end
262+
let(:event) { LogStash::Event.new()}
263+
let(:records) { [{"name" => "ldn-1-23", "rack" => "2:1:6"}] }
264+
let(:prepared_statement) { double("prepared_statement")}
265+
266+
subject(:lookup) { described_class.new(lookup_hash, {}, "lookup-1") }
267+
268+
before(:each) do
269+
allow(local_db).to receive(:prepare).once.and_return(prepared_statement)
270+
allow(prepared_statement).to receive(:call).once.and_raise(Java::JavaSql::SQLTransactionRollbackException.new)
271+
end
272+
273+
it "must not be valid" do
274+
expect(subject.valid?).to be_falsey
275+
end
276+
277+
it "should tag event as failed" do
278+
event.set("ip", "20.20")
279+
event.set("os", "MacOS")
280+
subject.prepare(local_db)
281+
subject.enhance(local_db, event)
282+
expect(event.get("tags")).to eq(["_jdbcstaticfailure_server"])
283+
expect(event.get("server")).to be_nil
284+
end
285+
end
286+
252287
describe "validation of target option" do
253288
let(:lookup_hash) do
254289
{

0 commit comments

Comments
 (0)