More v5 adjustments
This commit is contained in:
parent
85b3f31051
commit
fe2e23ac27
|
@ -50,8 +50,8 @@ For development:
|
||||||
| max_pool_size | Number | Maximum number of connections to open to the SQL server at any 1 time | No | 5 |
|
| max_pool_size | Number | Maximum number of connections to open to the SQL server at any 1 time | No | 5 |
|
||||||
| connection_timeout | Number | Number of seconds before a SQL connection is closed | No | 2800 |
|
| connection_timeout | Number | Number of seconds before a SQL connection is closed | No | 2800 |
|
||||||
| flush_size | Number | Maximum number of entries to buffer before sending to SQL - if this is reached before idle_flush_time | No | 1000 |
|
| flush_size | Number | Maximum number of entries to buffer before sending to SQL - if this is reached before idle_flush_time | No | 1000 |
|
||||||
| max_flush_exceptions | Number | Number of sequential flushes which cause an exception, before the set of events are discarded. Set to a value less than 1 if you never want it to stop. This should be carefully configured with respect to retry_initial_interval and retry_max_interval, if your SQL server is not highly available | No | 0 |
|
| max_flush_exceptions | Number | Number of sequential flushes which cause an exception, before the set of events are discarded. Set to a value less than 1 if you never want it to stop. This should be carefully configured with respect to retry_initial_interval and retry_max_interval, if your SQL server is not highly available | No | 10 |
|
||||||
| retry_initial_interval | Number | Number of seconds before the initial retry in the event of a failure | No | 2 |
|
| retry_initial_interval | Number | Number of seconds before the initial retry in the event of a failure. On each failure it will be doubled until it reaches retry_max_interval | No | 2 |
|
||||||
| retry_max_interval | Number | Maximum number of seconds between each retry | No | 128 |
|
| retry_max_interval | Number | Maximum number of seconds between each retry | No | 128 |
|
||||||
|
|
||||||
## Example configurations
|
## Example configurations
|
||||||
|
|
|
@ -9,6 +9,40 @@ require "logstash-output-jdbc_jars"
|
||||||
class LogStash::Outputs::Jdbc < LogStash::Outputs::Base
|
class LogStash::Outputs::Jdbc < LogStash::Outputs::Base
|
||||||
STRFTIME_FMT = "%Y-%m-%d %T.%L".freeze
|
STRFTIME_FMT = "%Y-%m-%d %T.%L".freeze
|
||||||
|
|
||||||
|
# Will never work, but only because it duplicates data (i.e. duplicate keys)
|
||||||
|
# Will throw a warning.
|
||||||
|
SQL_STATES_IGNORE = [
|
||||||
|
### Constraint Violation
|
||||||
|
# Integrity constraint violation.
|
||||||
|
23000,
|
||||||
|
# A violation of the constraint imposed by a unique index or a unique constraint occurred.
|
||||||
|
23505
|
||||||
|
]
|
||||||
|
|
||||||
|
# Will never work because of SQL statement errors.
|
||||||
|
# Will throw an error.
|
||||||
|
SQL_STATES_FATAL = [
|
||||||
|
### Data Exception
|
||||||
|
# Character data, right truncation occurred. Field too small.
|
||||||
|
22001,
|
||||||
|
# Numeric value out of range.
|
||||||
|
22003,
|
||||||
|
# A null value is not allowed.
|
||||||
|
22004,
|
||||||
|
# Invalid datetime format.
|
||||||
|
22007,
|
||||||
|
# A parameter or host variable value is invalid.
|
||||||
|
22023,
|
||||||
|
# Character conversion resulted in truncation.
|
||||||
|
22524,
|
||||||
|
|
||||||
|
### Constraint Violation
|
||||||
|
# The insert or update value of a foreign key is invalid.
|
||||||
|
23503,
|
||||||
|
# The range of values for the identity column or sequence is exhausted.
|
||||||
|
23522
|
||||||
|
]
|
||||||
|
|
||||||
config_name "jdbc"
|
config_name "jdbc"
|
||||||
|
|
||||||
# Driver class - Reintroduced for https://github.com/theangryangel/logstash-output-jdbc/issues/26
|
# Driver class - Reintroduced for https://github.com/theangryangel/logstash-output-jdbc/issues/26
|
||||||
|
@ -58,7 +92,8 @@ class LogStash::Outputs::Jdbc < LogStash::Outputs::Base
|
||||||
|
|
||||||
# Maximum number of sequential failed attempts, before we stop retrying.
|
# Maximum number of sequential failed attempts, before we stop retrying.
|
||||||
# If set to < 1, then it will infinitely retry.
|
# If set to < 1, then it will infinitely retry.
|
||||||
config :max_flush_exceptions, :validate => :number, :default => 0
|
# At the default values this is a little over 10 minutes
|
||||||
|
config :max_flush_exceptions, :validate => :number, :default => 10
|
||||||
|
|
||||||
config :max_repeat_exceptions, :obsolete => "This has been replaced by max_flush_exceptions - which behaves slightly differently. Please check the documentation."
|
config :max_repeat_exceptions, :obsolete => "This has been replaced by max_flush_exceptions - which behaves slightly differently. Please check the documentation."
|
||||||
config :max_repeat_exceptions_time, :obsolete => "This is no longer required"
|
config :max_repeat_exceptions_time, :obsolete => "This is no longer required"
|
||||||
|
@ -157,52 +192,7 @@ class LogStash::Outputs::Jdbc < LogStash::Outputs::Base
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def submit_safe(events)
|
def submit(events)
|
||||||
connection = nil
|
|
||||||
statement = nil
|
|
||||||
events_to_retry = []
|
|
||||||
begin
|
|
||||||
connection = @pool.getConnection()
|
|
||||||
rescue => e
|
|
||||||
log_jdbc_exception(e)
|
|
||||||
return events
|
|
||||||
end
|
|
||||||
|
|
||||||
begin
|
|
||||||
statement = connection.prepareStatement(@statement[0])
|
|
||||||
events.each do |event|
|
|
||||||
next if event.cancelled?
|
|
||||||
next if @statement.length < 2
|
|
||||||
statement = add_statement_event_params(statement, event)
|
|
||||||
|
|
||||||
statement.addBatch()
|
|
||||||
end
|
|
||||||
statement.executeBatch()
|
|
||||||
rescue java.sql.BatchUpdateException => e
|
|
||||||
# Only retry the failed items from the batch
|
|
||||||
updates = e.getUpdateCounts()
|
|
||||||
events_to_retry = events
|
|
||||||
updates.each_with_index{ |update, idx|
|
|
||||||
if (update != java.sql.Statement.EXECUTE_FAILED)
|
|
||||||
# Remove any successful events
|
|
||||||
events_to_retry[idx] = nil
|
|
||||||
end
|
|
||||||
}
|
|
||||||
# Remove the nil entries
|
|
||||||
events_to_retry = events_to_retry.compact
|
|
||||||
log_jdbc_exception(e)
|
|
||||||
rescue => e
|
|
||||||
events_to_retry = events
|
|
||||||
log_jdbc_exception(e)
|
|
||||||
ensure
|
|
||||||
statement.close() unless statement.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
connection.close() unless connection.nil?
|
|
||||||
return events_to_retry
|
|
||||||
end
|
|
||||||
|
|
||||||
def submit_unsafe(events)
|
|
||||||
connection = nil
|
connection = nil
|
||||||
statement = nil
|
statement = nil
|
||||||
events_to_retry = []
|
events_to_retry = []
|
||||||
|
@ -216,16 +206,30 @@ class LogStash::Outputs::Jdbc < LogStash::Outputs::Base
|
||||||
|
|
||||||
events.each do |event|
|
events.each do |event|
|
||||||
begin
|
begin
|
||||||
statement = connection.prepareStatement(event.sprintf(@statement[0]))
|
if @unsafe_statement == true
|
||||||
|
statement = connection.prepareStatement(event.sprintf(@statement[0]))
|
||||||
|
else
|
||||||
|
statement = connection.prepareStatement(@statement[0])
|
||||||
|
end
|
||||||
|
|
||||||
statement = add_statement_event_params(statement, event) if @statement.length > 1
|
statement = add_statement_event_params(statement, event) if @statement.length > 1
|
||||||
|
|
||||||
statement.execute()
|
statement.execute()
|
||||||
|
rescue java.sql.SQLException => e
|
||||||
|
if SQL_STATES_IGNORE.include? e.getSQLState()
|
||||||
|
@logger.warn('JDBC - Dropping event. Ignore-able exception (duplicate key most likely)', exception: e, event: event)
|
||||||
|
elsif SQL_STATES_FATAL.include? e.getSQLState()
|
||||||
|
@logger.error('JDBC - Fatal SQL exception. Can never succeed. Dropping event.', exception: e, event: event)
|
||||||
|
else
|
||||||
|
log_jdbc_exception(e)
|
||||||
|
events_to_retry.push(event)
|
||||||
|
end
|
||||||
rescue => e
|
rescue => e
|
||||||
|
# Something else happened.
|
||||||
log_jdbc_exception(e)
|
log_jdbc_exception(e)
|
||||||
events_to_retry.push(event)
|
events_to_retry.push(event)
|
||||||
ensure
|
ensure
|
||||||
statement.close() unless statement.nil?
|
statement.close() unless statement.nil?
|
||||||
statement = nil
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -243,29 +247,21 @@ class LogStash::Outputs::Jdbc < LogStash::Outputs::Base
|
||||||
sleep_interval = @retry_initial_interval
|
sleep_interval = @retry_initial_interval
|
||||||
while submit_actions && submit_actions.length > 0
|
while submit_actions && submit_actions.length > 0
|
||||||
return if !submit_actions || submit_actions.empty? # If everything's a success we move along
|
return if !submit_actions || submit_actions.empty? # If everything's a success we move along
|
||||||
# We retry with whatever is didn't succeed
|
# We retry whatever didn't succeed
|
||||||
begin
|
submit_actions = submit(submit_actions)
|
||||||
if @unsafe_statement == true
|
|
||||||
submit_actions = submit_unsafe(submit_actions)
|
# Everything was a success!
|
||||||
else
|
break if !submit_actions || submit_actions.empty?
|
||||||
submit_actions = submit_safe(submit_actions)
|
|
||||||
end
|
|
||||||
rescue => e
|
|
||||||
log_jdbc_exception(e)
|
|
||||||
end
|
|
||||||
|
|
||||||
if @max_flush_exceptions > 0
|
if @max_flush_exceptions > 0
|
||||||
attempts += 1
|
attempts += 1
|
||||||
|
|
||||||
if attempts > @max_flush_exceptions
|
if attempts > @max_flush_exceptions
|
||||||
@logger.error("JDBC - max_flush_exceptions has been reached")
|
@logger.error("JDBC - max_flush_exceptions has been reached. #{submit_actions.length} events have been unable to be sent to SQL and are being dropped. See previously logged exceptions for details.")
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Everything was a success!
|
|
||||||
break if !submit_actions || submit_actions.empty?
|
|
||||||
|
|
||||||
# If we're retrying the action sleep for the recommended interval
|
# If we're retrying the action sleep for the recommended interval
|
||||||
# Double the interval for the next time through to achieve exponential backoff
|
# Double the interval for the next time through to achieve exponential backoff
|
||||||
Stud.stoppable_sleep(sleep_interval) { @stopping.true? }
|
Stud.stoppable_sleep(sleep_interval) { @stopping.true? }
|
||||||
|
@ -313,7 +309,7 @@ class LogStash::Outputs::Jdbc < LogStash::Outputs::Base
|
||||||
def log_jdbc_exception(exception)
|
def log_jdbc_exception(exception)
|
||||||
current_exception = exception
|
current_exception = exception
|
||||||
loop do
|
loop do
|
||||||
@logger.error("JDBC Exception encountered: Will automatically retry.", :exception => current_exception)
|
@logger.warn("JDBC Exception encountered: Will automatically retry.", :exception => current_exception)
|
||||||
current_exception = current_exception.getNextException()
|
current_exception = current_exception.getNextException()
|
||||||
break if current_exception == nil
|
break if current_exception == nil
|
||||||
end
|
end
|
||||||
|
|
20
scripts/minutes_to_retries.rb
Executable file
20
scripts/minutes_to_retries.rb
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
#!/usr/bin/env ruby -w
|
||||||
|
|
||||||
|
seconds_to_reach = 10 * 60
|
||||||
|
default_interval = 2
|
||||||
|
retry_max_interval = 128
|
||||||
|
|
||||||
|
current_interval = 2
|
||||||
|
total_interval = 0
|
||||||
|
exceptions_count = 1
|
||||||
|
|
||||||
|
loop do
|
||||||
|
break if total_interval > seconds_to_reach
|
||||||
|
exceptions_count += 1
|
||||||
|
|
||||||
|
current_interval = current_interval*2 > retry_max_interval ? retry_max_interval : current_interval*2
|
||||||
|
|
||||||
|
total_interval += current_interval
|
||||||
|
end
|
||||||
|
|
||||||
|
puts exceptions_count
|
Loading…
Reference in New Issue
Block a user