Skip to content

Commit c0583ce

Browse files
authored
Sequel datetime class consistency (#151)
* timezones: absent instruction otherwise, interpret times as local these tests SUCCEED when run on their own, but FAIL when run after any instance of a plugin has been initialized with `jdbc_default_timezone`, since doing so globally configures Sequel to use DateTime instead of Time: To validate, modify the `.ci/run.sh` execution line to be: > ~~~ > bundle exec rspec spec --format documentation --example "without jdbc_default_timezone" > ~~~ * timezones: consistently pre-load Sequel, force datetime_class=Time By default, when a plugin is configured _without_ `jdbc_default_timezone` timestamps are assumed to be in the same timezone as the Logstash host machine, because they are parsed with Ruby's `Time#parse` which uses local context. However, when any one plugin declares `jdbc_default_timezone`, we load Sequel's `named_timezones` extension, which has a side-effect of globally changing `Sequel.datetime_class` to ruby's `DateTime`. The plugins that are configured with `jdbc_default_timezone` have enough information to apply the separately-provided offset, but the plugins that do _not_ have a `jdbc_default_timezone` directive become broken and effectively fail to parse the timestamps as they did when run on their own. Sequel's `named_timezones` extension supports being used with `Time` objects, and is noted to override `Sequel#datetime_class` on load only for historic reasons. We force Sequel to use ruby's `Time` class globally (enforcing its default and preventing it from being changed). This is done inside of a separately-required bootstrap, which allows us to ensure it is loaded exacltly once. * bump version & add changelog entry
1 parent 48f8053 commit c0583ce

File tree

5 files changed

+52
-2
lines changed

5 files changed

+52
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
## 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)
23
- 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)
34

45
## 5.4.10

lib/logstash/filters/jdbc/basic_database.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# encoding: utf-8
22
require "fileutils"
3-
require "sequel"
3+
require "logstash/plugin_mixins/jdbc/sequel_bootstrap"
44
require "sequel/adapters/jdbc"
55
require "java"
66
require "logstash/util/loggable"

lib/logstash/plugin_mixins/jdbc/common.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ def load_driver
2424
return @driver_impl if @driver_impl ||= nil
2525

2626
require "java"
27-
require "sequel"
27+
28+
require_relative "sequel_bootstrap"
2829
require "sequel/adapters/jdbc"
2930

3031
# execute all the driver loading related duties in a serial fashion to avoid
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

spec/inputs/jdbc_spec.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,33 @@
601601
# With no timezone set, no change should occur
602602
expect(event.get("custom_time").time).to eq(Time.iso8601("2015-01-01T12:00:00Z"))
603603
end
604+
605+
%w(
606+
Etc/UTC
607+
America/Los_Angeles
608+
Europe/Berlin
609+
Asia/Tokyo
610+
).each do |local_timezone|
611+
context "when host machine has timezone `#{local_timezone}`" do
612+
around(:each) do |example|
613+
begin
614+
previous_tz = ENV['TZ']
615+
ENV['TZ'] = local_timezone
616+
example.call
617+
ensure
618+
ENV['TZ'] = previous_tz
619+
end
620+
end
621+
622+
let(:tz) { TZInfo::Timezone.get(local_timezone) }
623+
624+
it "converts the time using the machine's local timezone" do
625+
plugin.run(queue)
626+
event = queue.pop
627+
expect(event.get("custom_time").time).to eq(Time.new(2015,1,1,12,0,0,tz))
628+
end
629+
end
630+
end
604631
end
605632

606633
context "when iteratively running plugin#run" do

0 commit comments

Comments
 (0)