logstash-integration-jdbc 5.2.2 → 5.2.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2f43be09f1996c0e4effd6914055fa643549925433ab4512f4e3a0ed1fa1933c
4
- data.tar.gz: 346cb42a27eaaa3f51e7cf1ba3d52fb332f278dfe8cecf7d1aa200af42ba4f5b
3
+ metadata.gz: b74796568bc1df12ae5015cfcf38aeb43971b3bd3eda2dcc668104decc69b6a2
4
+ data.tar.gz: ae3a1f82f7354798692933a2426977ea2e17f7335a74d02eb09a376e4421af6b
5
5
  SHA512:
6
- metadata.gz: 3a75a4a4165e04178384a66740de3bce2981c2d019a8bd2192519a725bfe88d5ddf7469cf2a2aebda12b1b48b2117817171da2f459d283c3e3e16d86422c4c06
7
- data.tar.gz: ae15ead4d5efd52cc67bf58ad1d994bde11443bbc0e083d56f695ddc7163be44454ee1db1a95b81ec884c51a790f2e7582733df4f5faf6b9d4715a0685a31c92
6
+ metadata.gz: d198c08e74dc4702dae5de1ca4661d68d10298ff497e44739e7cc775d575bfc9fe825154a9de6f2497e60fb3c694f06d36d8971ecf9935e13592c959d6c13c53
7
+ data.tar.gz: ccd725393201ec5282644f003880fa0449a027942442698fe6e1758f25335ff585efb73d0f52716c9698eb19990ef67a15b21fef90255473b39683339520796a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## 5.2.5
2
+ - Fix: do not execute more queries with debug logging [#109](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/109)
3
+
4
+ ## 5.2.4
5
+ - Fix: compatibility with all (>= 3.0) rufus-scheduler versions [#97](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/97)
6
+
7
+ ## 5.2.3
8
+ - Performance: avoid contention on scheduler execution [#103](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/103)
9
+
1
10
  ## 5.2.2
2
11
  - Feat: name scheduler threads + redirect error logging [#102](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/102)
3
12
 
data/Gemfile CHANGED
@@ -9,3 +9,5 @@ if Dir.exist?(logstash_path) && use_logstash_source
9
9
  gem 'logstash-core', :path => "#{logstash_path}/logstash-core"
10
10
  gem 'logstash-core-plugin-api', :path => "#{logstash_path}/logstash-core-plugin-api"
11
11
  end
12
+
13
+ gem 'rufus-scheduler', ENV['RUFUS_SCHEDULER_VERSION'] if ENV['RUFUS_SCHEDULER_VERSION']
@@ -4,60 +4,26 @@ require "rufus/scheduler"
4
4
 
5
5
  module LogStash module Filters module Jdbc
6
6
  class LoaderSchedule < Validatable
7
- attr_reader :schedule_frequency, :loader_schedule
8
-
9
- def to_log_string
10
- message = ""
11
- message.concat "these months in the year [#{@cronline.months.to_a.join(", ")}];" unless @cronline.months.nil?
12
- message.concat "these days in the month [#{@cronline.days.to_a.join(", ")}];" unless @cronline.days.nil?
13
- message.concat "these hours in the day [#{@cronline.hours.to_a.join(", ")}];" unless @cronline.hours.nil?
14
- message.concat "these minutes in the hour [#{@cronline.minutes.to_a.join(", ")}];" unless @cronline.minutes.nil?
15
- message.concat "these seconds in the minute [#{@cronline.seconds.to_a.join(", ")}]" unless @cronline.seconds.nil?
16
- if !message.empty?
17
- message.prepend "Scheduled for: "
18
- end
19
- message
20
- end
7
+ attr_reader :loader_schedule
21
8
 
22
9
  private
23
10
 
24
- def post_initialize
25
- if valid?
26
- # From the Rufus::Scheduler docs:
27
- # By default, rufus-scheduler sleeps 0.300 second between every step.
28
- # At each step it checks for jobs to trigger and so on.
29
- # set the frequency to 2.5 seconds if we are not reloading in the seconds timeframe
30
- # rufus scheduler thread should respond to stop quickly enough.
31
- if only_seconds_set?
32
- @schedule_frequency = 0.3
33
- else
34
- @schedule_frequency = 2.5
35
- end
36
- end
37
- end
38
-
39
-
40
- def only_seconds_set?
41
- @cronline.seconds &&
42
- @cronline.minutes.nil? &&
43
- @cronline.hours.nil? &&
44
- @cronline.days.nil? &&
45
- @cronline.months.nil?
46
- end
47
-
11
+ # @overload
48
12
  def parse_options
49
13
  @loader_schedule = @options
50
14
 
51
- unless @loader_schedule.is_a?(String)
15
+ if @loader_schedule.is_a?(String)
16
+ begin
17
+ # Rufus::Scheduler 3.0 - 3.6 methods signature: parse_cron(o, opts)
18
+ # since Rufus::Scheduler 3.7 methods signature: parse_cron(o, opts={})
19
+ @cronline = Rufus::Scheduler.parse_cron(@loader_schedule, {})
20
+ rescue => e
21
+ @option_errors << "The loader_schedule option is invalid: #{e.message}"
22
+ end
23
+ else
52
24
  @option_errors << "The loader_schedule option must be a string"
53
25
  end
54
26
 
55
- begin
56
- @cronline = Rufus::Scheduler::CronLine.new(@loader_schedule)
57
- rescue => e
58
- @option_errors << "The loader_schedule option is invalid: #{e.message}"
59
- end
60
-
61
27
  @valid = @option_errors.empty?
62
28
  end
63
29
  end
@@ -3,8 +3,6 @@ require_relative "single_load_runner"
3
3
 
4
4
  module LogStash module Filters module Jdbc
5
5
  class RepeatingLoadRunner < SingleLoadRunner
6
- # info - attr_reader :local, :loaders, :preloaders
7
-
8
6
  def repeated_load
9
7
  local.repopulate_all(loaders)
10
8
  @reload_counter.increment
@@ -26,10 +26,6 @@ module LogStash module Filters module Jdbc
26
26
  def repeated_load
27
27
  end
28
28
 
29
- def call
30
- repeated_load
31
- end
32
-
33
29
  def reload_count
34
30
  @reload_counter.value
35
31
  end
@@ -3,6 +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/jdbc/scheduler"
6
7
  require_relative "jdbc/loader"
7
8
  require_relative "jdbc/loader_schedule"
8
9
  require_relative "jdbc/repeating_load_runner"
@@ -191,17 +192,15 @@ module LogStash module Filters class JdbcStatic < LogStash::Filters::Base
191
192
  @processor = Jdbc::LookupProcessor.new(@local_lookups, global_lookup_options)
192
193
  runner_args.unshift(@processor.local)
193
194
  if @loader_schedule
194
- args = []
195
195
  @loader_runner = Jdbc::RepeatingLoadRunner.new(*runner_args)
196
196
  @loader_runner.initial_load
197
- cronline = Jdbc::LoaderSchedule.new(@loader_schedule)
198
- cronline.to_log_string.tap do |msg|
199
- logger.info("Scheduler operations: #{msg}") unless msg.empty?
197
+ @scheduler = LogStash::PluginMixins::Jdbc::Scheduler.
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)
200
203
  end
201
- logger.info("Scheduler scan for work frequency is: #{cronline.schedule_frequency}")
202
- rufus_args = {:max_work_threads => 1, :frequency => cronline.schedule_frequency}
203
- @scheduler = Rufus::Scheduler.new(rufus_args)
204
- @scheduler.cron(cronline.loader_schedule, @loader_runner)
205
204
  else
206
205
  @loader_runner = Jdbc::SingleLoadRunner.new(*runner_args)
207
206
  @loader_runner.initial_load
@@ -259,8 +259,8 @@ module LogStash module Inputs class Jdbc < LogStash::Inputs::Base
259
259
  end
260
260
  end
261
261
 
262
- set_value_tracker(LogStash::PluginMixins::Jdbc::ValueTracking.build_last_value_tracker(self))
263
- set_statement_logger(LogStash::PluginMixins::Jdbc::CheckedCountLogger.new(@logger))
262
+ set_value_tracker LogStash::PluginMixins::Jdbc::ValueTracking.build_last_value_tracker(self)
263
+ set_statement_handler LogStash::PluginMixins::Jdbc::StatementHandler.build_statement_handler(self)
264
264
 
265
265
  @enable_encoding = !@charset.nil? || !@columns_charset.empty?
266
266
 
@@ -283,8 +283,8 @@ module LogStash module Inputs class Jdbc < LogStash::Inputs::Base
283
283
  end # def register
284
284
 
285
285
  # test injection points
286
- def set_statement_logger(instance)
287
- @statement_handler = LogStash::PluginMixins::Jdbc::StatementHandler.build_statement_handler(self, instance)
286
+ def set_statement_handler(handler)
287
+ @statement_handler = handler
288
288
  end
289
289
 
290
290
  def set_value_tracker(instance)
@@ -295,13 +295,8 @@ module LogStash module Inputs class Jdbc < LogStash::Inputs::Base
295
295
  load_driver
296
296
  if @schedule
297
297
  # input thread (Java) name example "[my-oracle]<jdbc"
298
- @scheduler = LogStash::PluginMixins::Jdbc::Scheduler.new(
299
- :max_work_threads => 1, :thread_name => "[#{id}]<jdbc__scheduler"
300
- )
301
- @scheduler.schedule_cron @schedule do
302
- execute_query(queue)
303
- end
304
-
298
+ @scheduler = LogStash::PluginMixins::Jdbc::Scheduler.
299
+ start_cron_scheduler(@schedule, thread_name: "[#{id}]<jdbc__scheduler") { execute_query(queue) }
305
300
  @scheduler.join
306
301
  else
307
302
  execute_query(queue)
@@ -4,7 +4,6 @@ require "logstash/config/mixin"
4
4
  require "time"
5
5
  require "date"
6
6
  require_relative "value_tracking"
7
- require_relative "checked_count_logger"
8
7
  require_relative "statement_handler"
9
8
 
10
9
  java_import java.util.concurrent.locks.ReentrantLock
@@ -12,6 +12,70 @@ module LogStash module PluginMixins module Jdbc
12
12
  TimeImpl = defined?(Rufus::Scheduler::EoTime) ? Rufus::Scheduler::EoTime :
13
13
  (defined?(Rufus::Scheduler::ZoTime) ? Rufus::Scheduler::ZoTime : ::Time)
14
14
 
15
+ # @param cron [String] cron-line
16
+ # @param opts [Hash] scheduler options
17
+ # @return scheduler instance
18
+ def self.start_cron_scheduler(cron, opts = {}, &block)
19
+ unless block_given?
20
+ raise ArgumentError, 'missing (cron scheduler) block - worker task to execute'
21
+ end
22
+ scheduler = new_scheduler(opts)
23
+ scheduler.schedule_cron(cron, &block)
24
+ scheduler
25
+ end
26
+
27
+ # @param opts [Hash] scheduler options
28
+ # @return scheduler instance
29
+ def self.new_scheduler(opts)
30
+ unless opts.key?(:thread_name)
31
+ raise ArgumentError, 'thread_name: option is required to be able to distinguish multiple scheduler threads'
32
+ end
33
+ opts[:max_work_threads] ||= 1
34
+ # amount the scheduler thread sleeps between checking whether jobs
35
+ # should trigger, default is 0.3 which is a bit too often ...
36
+ # in theory the cron expression '* * * * * *' supports running jobs
37
+ # every second but this is very rare, we could potentially go higher
38
+ opts[:frequency] ||= 1.0
39
+
40
+ new(opts)
41
+ end
42
+
43
+ # @overload
44
+ def timeout_jobs
45
+ # Rufus relies on `Thread.list` which is a blocking operation and with many schedulers
46
+ # (and threads) within LS will have a negative impact on performance as scheduler
47
+ # threads will end up waiting to obtain the `Thread.list` lock.
48
+ #
49
+ # However, this isn't necessary we can easily detect whether there are any jobs
50
+ # that might need to timeout: only when `@opts[:timeout]` is set causes worker thread(s)
51
+ # to have a `Thread.current[:rufus_scheduler_timeout]` that is not nil
52
+ return unless @opts[:timeout]
53
+ super
54
+ end
55
+
56
+ # @overload
57
+ def work_threads(query = :all)
58
+ if query == :__all_no_cache__ # special case from JobDecorator#start_work_thread
59
+ @_work_threads = nil # when a new worker thread is being added reset
60
+ return super(:all)
61
+ end
62
+
63
+ # Gets executed every time a job is triggered, we're going to cache the
64
+ # worker threads for this scheduler (to avoid `Thread.list`) - they only
65
+ # change when a new thread is being started from #start_work_thread ...
66
+ work_threads = @_work_threads
67
+ if work_threads.nil?
68
+ work_threads = threads.select { |t| t[:rufus_scheduler_work_thread] }
69
+ @_work_threads = work_threads
70
+ end
71
+
72
+ case query
73
+ when :active then work_threads.select { |t| t[:rufus_scheduler_job] }
74
+ when :vacant then work_threads.reject { |t| t[:rufus_scheduler_job] }
75
+ else work_threads
76
+ end
77
+ end
78
+
15
79
  # @overload
16
80
  def on_error(job, err)
17
81
  details = { exception: err.class, message: err.message, backtrace: err.backtrace }
@@ -76,10 +140,10 @@ module LogStash module PluginMixins module Jdbc
76
140
 
77
141
  ret = super() # does not return Thread instance in 3.0
78
142
 
79
- work_threads = @scheduler.work_threads
143
+ work_threads = @scheduler.work_threads(:__all_no_cache__)
80
144
  while prev_thread_count == work_threads.size # very unlikely
81
145
  Thread.pass
82
- work_threads = @scheduler.work_threads
146
+ work_threads = @scheduler.work_threads(:__all_no_cache__)
83
147
  end
84
148
 
85
149
  work_thread_name_prefix = @scheduler.work_thread_name_prefix
@@ -2,7 +2,7 @@
2
2
 
3
3
  module LogStash module PluginMixins module Jdbc
4
4
  class StatementHandler
5
- def self.build_statement_handler(plugin, logger)
5
+ def self.build_statement_handler(plugin)
6
6
  if plugin.use_prepared_statements
7
7
  klass = PreparedStatementHandler
8
8
  else
@@ -16,27 +16,39 @@ module LogStash module PluginMixins module Jdbc
16
16
  klass = NormalStatementHandler
17
17
  end
18
18
  end
19
- klass.new(plugin, logger)
19
+ klass.new(plugin)
20
20
  end
21
21
 
22
- attr_reader :statement, :parameters, :statement_logger
22
+ attr_reader :statement, :parameters
23
23
 
24
- def initialize(plugin, statement_logger)
24
+ def initialize(plugin)
25
25
  @statement = plugin.statement
26
- @statement_logger = statement_logger
27
- post_init(plugin)
28
26
  end
29
27
 
30
28
  def build_query(db, sql_last_value)
31
- # override in subclass
29
+ fail NotImplementedError # override in subclass
32
30
  end
33
31
 
34
- def post_init(plugin)
35
- # override in subclass, if needed
36
- end
37
32
  end
38
33
 
39
34
  class NormalStatementHandler < StatementHandler
35
+
36
+ attr_reader :parameters
37
+
38
+ def initialize(plugin)
39
+ super(plugin)
40
+ @parameter_keys = ["sql_last_value"] + plugin.parameters.keys
41
+ @parameters = plugin.parameters.inject({}) do |hash,(k,v)|
42
+ case v
43
+ when LogStash::Timestamp
44
+ hash[k.to_sym] = v.time
45
+ else
46
+ hash[k.to_sym] = v
47
+ end
48
+ hash
49
+ end
50
+ end
51
+
40
52
  # Performs the query, yielding once per row of data
41
53
  # @param db [Sequel::Database]
42
54
  # @param sql_last_value [Integer|DateTime|Time]
@@ -52,27 +64,18 @@ module LogStash module PluginMixins module Jdbc
52
64
 
53
65
  def build_query(db, sql_last_value)
54
66
  parameters[:sql_last_value] = sql_last_value
55
- query = db[statement, parameters]
56
- statement_logger.log_statement_parameters(statement, parameters, query)
57
- query
67
+ db[statement, parameters]
58
68
  end
59
69
 
60
- def post_init(plugin)
61
- @parameter_keys = ["sql_last_value"] + plugin.parameters.keys
62
- @parameters = plugin.parameters.inject({}) do |hash,(k,v)|
63
- case v
64
- when LogStash::Timestamp
65
- hash[k.to_sym] = v.time
66
- else
67
- hash[k.to_sym] = v
68
- end
69
- hash
70
- end
71
- end
72
70
  end
73
71
 
74
72
  class PagedNormalStatementHandler < NormalStatementHandler
75
- attr_reader :jdbc_page_size
73
+
74
+ def initialize(plugin)
75
+ super(plugin)
76
+ @jdbc_page_size = plugin.jdbc_page_size
77
+ @logger = plugin.logger
78
+ end
76
79
 
77
80
  # Performs the query, respecting our pagination settings, yielding once per row of data
78
81
  # @param db [Sequel::Database]
@@ -81,16 +84,22 @@ module LogStash module PluginMixins module Jdbc
81
84
  def perform_query(db, sql_last_value)
82
85
  query = build_query(db, sql_last_value)
83
86
  query.each_page(@jdbc_page_size) do |paged_dataset|
87
+ log_dataset_page(paged_dataset) if @logger.debug?
84
88
  paged_dataset.each do |row|
85
89
  yield row
86
90
  end
87
91
  end
88
92
  end
89
93
 
90
- def post_init(plugin)
91
- super(plugin)
92
- @jdbc_page_size = plugin.jdbc_page_size
94
+ private
95
+
96
+ # @param paged_dataset [Sequel::Dataset::Pagination] like object
97
+ def log_dataset_page(paged_dataset)
98
+ @logger.debug "fetching paged dataset", current_page: paged_dataset.current_page,
99
+ record_count: paged_dataset.current_page_record_count,
100
+ total_record_count: paged_dataset.pagination_record_count
93
101
  end
102
+
94
103
  end
95
104
 
96
105
  class ExplicitPagingModeStatementHandler < PagedNormalStatementHandler
@@ -101,20 +110,29 @@ module LogStash module PluginMixins module Jdbc
101
110
  def perform_query(db, sql_last_value)
102
111
  query = build_query(db, sql_last_value)
103
112
  offset = 0
113
+ page_size = @jdbc_page_size
104
114
  loop do
105
115
  rows_in_page = 0
106
- query.with_sql(query.sql, offset: offset, size: jdbc_page_size).each do |row|
116
+ query.with_sql(query.sql, offset: offset, size: page_size).each do |row|
107
117
  yield row
108
118
  rows_in_page += 1
109
119
  end
110
- break unless rows_in_page == jdbc_page_size
111
- offset += jdbc_page_size
120
+ break unless rows_in_page == page_size
121
+ offset += page_size
112
122
  end
113
123
  end
114
124
  end
115
125
 
116
126
  class PreparedStatementHandler < StatementHandler
117
- attr_reader :name, :bind_values_array, :statement_prepared, :prepared
127
+ attr_reader :name, :bind_values_array, :statement_prepared, :prepared, :parameters
128
+
129
+ def initialize(plugin)
130
+ super(plugin)
131
+ @name = plugin.prepared_statement_name.to_sym
132
+ @bind_values_array = plugin.prepared_statement_bind_values
133
+ @parameters = plugin.parameters
134
+ @statement_prepared = Concurrent::AtomicBoolean.new(false)
135
+ end
118
136
 
119
137
  # Performs the query, ignoring our pagination settings, yielding once per row of data
120
138
  # @param db [Sequel::Database]
@@ -142,7 +160,6 @@ module LogStash module PluginMixins module Jdbc
142
160
  db.set_prepared_statement(name, prepared)
143
161
  end
144
162
  bind_value_sql_last_value(sql_last_value)
145
- statement_logger.log_statement_parameters(statement, parameters, nil)
146
163
  begin
147
164
  db.call(name, parameters)
148
165
  rescue => e
@@ -153,17 +170,6 @@ module LogStash module PluginMixins module Jdbc
153
170
  end
154
171
  end
155
172
 
156
- def post_init(plugin)
157
- # don't log statement count when using prepared statements for now...
158
- # needs enhancement to allow user to supply a bindable count prepared statement in settings.
159
- @statement_logger.disable_count
160
-
161
- @name = plugin.prepared_statement_name.to_sym
162
- @bind_values_array = plugin.prepared_statement_bind_values
163
- @parameters = plugin.parameters
164
- @statement_prepared = Concurrent::AtomicBoolean.new(false)
165
- end
166
-
167
173
  def create_bind_values_hash
168
174
  hash = {}
169
175
  bind_values_array.each_with_index {|v,i| hash[:"p#{i}"] = v}
@@ -6,9 +6,6 @@ module LogStash module PluginMixins module Jdbc
6
6
 
7
7
  def self.build_last_value_tracker(plugin)
8
8
  handler = plugin.record_last_run ? FileHandler.new(plugin.last_run_metadata_path) : NullFileHandler.new(plugin.last_run_metadata_path)
9
- if plugin.record_last_run
10
- handler = FileHandler.new(plugin.last_run_metadata_path)
11
- end
12
9
  if plugin.clean_run
13
10
  handler.clean
14
11
  end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-integration-jdbc'
3
- s.version = '5.2.2'
3
+ s.version = '5.2.5'
4
4
  s.licenses = ['Apache License (2.0)']
5
5
  s.summary = "Integration with JDBC - input and filter plugins"
6
6
  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"
@@ -34,7 +34,9 @@ Gem::Specification.new do |s|
34
34
 
35
35
  s.add_runtime_dependency 'tzinfo'
36
36
  s.add_runtime_dependency 'tzinfo-data'
37
- s.add_runtime_dependency 'rufus-scheduler', '~> 3.0.9'
37
+ # plugin maintains compatibility with < 3.5 (3.0.9)
38
+ # but works with newer rufus-scheduler >= 3.5 as well
39
+ s.add_runtime_dependency 'rufus-scheduler'
38
40
  s.add_runtime_dependency 'logstash-mixin-ecs_compatibility_support', '~>1.3'
39
41
  s.add_runtime_dependency "logstash-mixin-validator_support", '~> 1.0'
40
42
  s.add_runtime_dependency "logstash-mixin-event_support", '~> 1.0'
@@ -17,7 +17,7 @@ module LogStash module Filters module Jdbc
17
17
  expect(local_db).to receive(:populate_all).once.with(loaders)
18
18
  expect(local_db).to receive(:repopulate_all).once.with(loaders)
19
19
  runner.initial_load
20
- subject.call
20
+ subject.repeated_load
21
21
  end
22
22
  end
23
23
  end
@@ -41,6 +41,31 @@ describe LogStash::Inputs::Jdbc, :integration => true do
41
41
  expect(event.get('first_name')).to eq("Mark")
42
42
  expect(event.get('last_name')).to eq("Guckenheimer")
43
43
  end
44
+
45
+ context 'with paging' do
46
+ let(:settings) do
47
+ super().merge 'jdbc_paging_enabled' => true, 'jdbc_page_size' => 1,
48
+ "statement" => 'SELECT * FROM "employee" WHERE EMP_NO >= :p1 ORDER BY EMP_NO',
49
+ 'parameters' => { 'p1' => 0 }
50
+ end
51
+
52
+ before do # change plugin logger level to debug - to exercise logging
53
+ logger = plugin.class.name.gsub('::', '.').downcase
54
+ logger = org.apache.logging.log4j.LogManager.getLogger(logger)
55
+ @prev_logger_level = [ logger.getName, logger.getLevel ]
56
+ org.apache.logging.log4j.core.config.Configurator.setLevel logger.getName, org.apache.logging.log4j.Level::DEBUG
57
+ end
58
+
59
+ after do
60
+ org.apache.logging.log4j.core.config.Configurator.setLevel *@prev_logger_level
61
+ end
62
+
63
+ it "should populate the event with database entries" do
64
+ plugin.run(queue)
65
+ event = queue.pop
66
+ expect(event.get('first_name')).to eq('David')
67
+ end
68
+ end
44
69
  end
45
70
 
46
71
  context "when supplying a non-existent library" do
@@ -1432,54 +1432,6 @@ describe LogStash::Inputs::Jdbc do
1432
1432
  end
1433
1433
  end
1434
1434
 
1435
- context "when debug logging and a count query raises a count related error" do
1436
- let(:settings) do
1437
- { "statement" => "SELECT * from types_table" }
1438
- end
1439
- let(:logger) { double("logger", :debug? => true) }
1440
- let(:statement_logger) { LogStash::PluginMixins::Jdbc::CheckedCountLogger.new(logger) }
1441
- let(:value_tracker) { double("value tracker", :set_value => nil, :write => nil) }
1442
- let(:msg) { 'Java::JavaSql::SQLSyntaxErrorException: Dynamic SQL Error; SQL error code = -104; Token unknown - line 1, column 105; LIMIT [SQLState:42000, ISC error code:335544634]' }
1443
- let(:error_args) do
1444
- {"exception" => msg}
1445
- end
1446
-
1447
- before do
1448
- db << "INSERT INTO types_table (num, string, started_at, custom_time, ranking) VALUES (1, 'A test', '1999-12-31', '1999-12-31 23:59:59', 95.67)"
1449
- plugin.register
1450
- plugin.set_statement_logger(statement_logger)
1451
- plugin.set_value_tracker(value_tracker)
1452
- allow(value_tracker).to receive(:value).and_return("bar")
1453
- allow(statement_logger).to receive(:execute_count).once.and_raise(StandardError.new(msg))
1454
- end
1455
-
1456
- after do
1457
- plugin.stop
1458
- end
1459
-
1460
- context "if the count query raises an error" do
1461
- it "should log a debug line without a count key as its unknown whether a count works at this stage" do
1462
- expect(logger).to receive(:warn).once.with("Attempting a count query raised an error, the generated count statement is most likely incorrect but check networking, authentication or your statement syntax", error_args)
1463
- expect(logger).to receive(:warn).once.with("Ongoing count statement generation is being prevented")
1464
- expect(logger).to receive(:debug).once.with("Executing JDBC query", :statement => settings["statement"], :parameters => {:sql_last_value=>"bar"})
1465
- plugin.run(queue)
1466
- queue.pop
1467
- end
1468
-
1469
- it "should create an event normally" do
1470
- allow(logger).to receive(:warn)
1471
- allow(logger).to receive(:debug)
1472
- plugin.run(queue)
1473
- event = queue.pop
1474
- expect(event.get("num")).to eq(1)
1475
- expect(event.get("string")).to eq("A test")
1476
- expect(event.get("started_at")).to be_a_logstash_timestamp_equivalent_to("1999-12-31T00:00:00.000Z")
1477
- expect(event.get("custom_time")).to be_a_logstash_timestamp_equivalent_to("1999-12-31T23:59:59.000Z")
1478
- expect(event.get("ranking").to_f).to eq(95.67)
1479
- end
1480
- end
1481
- end
1482
-
1483
1435
  context "when an unreadable jdbc_driver_path entry is present" do
1484
1436
  let(:driver_jar_path) do
1485
1437
  jar_file = $CLASSPATH.find { |name| name.index(Jdbc::Derby.driver_jar) }
@@ -49,4 +49,30 @@ describe LogStash::PluginMixins::Jdbc::Scheduler do
49
49
 
50
50
  end
51
51
 
52
+ context 'work threads' do
53
+
54
+ let(:opts) { super().merge :max_work_threads => 3 }
55
+
56
+ let(:counter) { java.util.concurrent.atomic.AtomicLong.new(0) }
57
+
58
+ before do
59
+ scheduler.schedule_cron('* * * * * *') { counter.increment_and_get; sleep 3.25 } # every second
60
+ end
61
+
62
+ it "are working" do
63
+ sleep(0.05) while counter.get == 0
64
+ expect( scheduler.work_threads.size ).to eql 1
65
+ sleep(0.05) while counter.get == 1
66
+ expect( scheduler.work_threads.size ).to eql 2
67
+ sleep(0.05) while counter.get == 2
68
+ expect( scheduler.work_threads.size ).to eql 3
69
+
70
+ sleep 1.25
71
+ expect( scheduler.work_threads.size ).to eql 3
72
+ sleep 1.25
73
+ expect( scheduler.work_threads.size ).to eql 3
74
+ end
75
+
76
+ end
77
+
52
78
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-integration-jdbc
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.2
4
+ version: 5.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-19 00:00:00.000000000 Z
11
+ date: 2022-05-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -131,17 +131,17 @@ dependencies:
131
131
  - !ruby/object:Gem::Dependency
132
132
  requirement: !ruby/object:Gem::Requirement
133
133
  requirements:
134
- - - "~>"
134
+ - - ">="
135
135
  - !ruby/object:Gem::Version
136
- version: 3.0.9
136
+ version: '0'
137
137
  name: rufus-scheduler
138
138
  prerelease: false
139
139
  type: :runtime
140
140
  version_requirements: !ruby/object:Gem::Requirement
141
141
  requirements:
142
- - - "~>"
142
+ - - ">="
143
143
  - !ruby/object:Gem::Version
144
- version: 3.0.9
144
+ version: '0'
145
145
  - !ruby/object:Gem::Dependency
146
146
  requirement: !ruby/object:Gem::Requirement
147
147
  requirements:
@@ -275,7 +275,6 @@ files:
275
275
  - lib/logstash/filters/jdbc_streaming.rb
276
276
  - lib/logstash/inputs/jdbc.rb
277
277
  - lib/logstash/inputs/tzinfo_jruby_patch.rb
278
- - lib/logstash/plugin_mixins/jdbc/checked_count_logger.rb
279
278
  - lib/logstash/plugin_mixins/jdbc/common.rb
280
279
  - lib/logstash/plugin_mixins/jdbc/jdbc.rb
281
280
  - lib/logstash/plugin_mixins/jdbc/scheduler.rb
@@ -1,43 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module LogStash module PluginMixins module Jdbc
4
- class CheckedCountLogger
5
- def initialize(logger)
6
- @logger = logger
7
- @needs_check = true
8
- @count_is_supported = false
9
- @in_debug = @logger.debug?
10
- end
11
-
12
- def disable_count
13
- @needs_check = false
14
- @count_is_supported = false
15
- end
16
-
17
- def log_statement_parameters(statement, parameters, query)
18
- return unless @in_debug
19
- check_count_query(query) if @needs_check && query
20
- if @count_is_supported
21
- @logger.debug("Executing JDBC query", :statement => statement, :parameters => parameters, :count => execute_count(query))
22
- else
23
- @logger.debug("Executing JDBC query", :statement => statement, :parameters => parameters)
24
- end
25
- end
26
-
27
- def check_count_query(query)
28
- @needs_check = false
29
- begin
30
- execute_count(query)
31
- @count_is_supported = true
32
- rescue Exception => e
33
- @logger.warn("Attempting a count query raised an error, the generated count statement is most likely incorrect but check networking, authentication or your statement syntax", "exception" => e.message)
34
- @logger.warn("Ongoing count statement generation is being prevented")
35
- @count_is_supported = false
36
- end
37
- end
38
-
39
- def execute_count(query)
40
- query.count
41
- end
42
- end
43
- end end end