Skip to content

Commit 1ddcd42

Browse files
author
Guy Boertje
authored
Jdk11 class loading (#343)
* temp commit * Had to monkey patch tzinfo, jruby bug fix scheduled for 9.2.8.0 * update travis.yml * try a better matrix * maybe this matrix will do * try docker based travis * final adjustments, version bump and docs changes * review changes, add comments and jruby version guard * more review led changes
1 parent 78a9967 commit 1ddcd42

16 files changed

+343
-139
lines changed

.travis.yml

+12-17
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
---
2-
sudo: false
3-
language: ruby
4-
cache: bundler
2+
sudo: required
3+
services: docker
4+
addons:
5+
apt:
6+
packages:
7+
- docker-ce
58
matrix:
69
include:
7-
- rvm: jruby-9.1.13.0
8-
env: LOGSTASH_BRANCH=master
9-
- rvm: jruby-9.1.13.0
10-
env: LOGSTASH_BRANCH=7.0
11-
- rvm: jruby-9.1.13.0
12-
env: LOGSTASH_BRANCH=6.7
13-
- rvm: jruby-9.1.13.0
14-
env: LOGSTASH_BRANCH=6.6
15-
- rvm: jruby-1.7.27
16-
env: LOGSTASH_BRANCH=5.6
10+
- env: ELASTIC_STACK_VERSION=8.x SNAPSHOT=true
11+
- env: ELASTIC_STACK_VERSION=7.x SNAPSHOT=true
12+
- env: ELASTIC_STACK_VERSION=7.x
13+
- env: ELASTIC_STACK_VERSION=6.x
1714
fast_finish: true
18-
install: true
19-
script: ci/build.sh
20-
jdk: oraclejdk8
21-
before_install: gem install bundler -v '< 2'
15+
install: ci/unit/docker-setup.sh
16+
script: ci/unit/docker-run.sh

ci/build.sh

-21
This file was deleted.

ci/setup.sh

-26
This file was deleted.

ci/unit/Dockerfile

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
ARG ELASTIC_STACK_VERSION
2+
FROM docker.elastic.co/logstash/logstash:$ELASTIC_STACK_VERSION
3+
COPY --chown=logstash:logstash Gemfile /usr/share/plugins/plugin/Gemfile
4+
COPY --chown=logstash:logstash *.gemspec /usr/share/plugins/plugin/
5+
RUN cp /usr/share/logstash/logstash-core/versions-gem-copy.yml /usr/share/logstash/versions.yml
6+
ENV PATH="${PATH}:/usr/share/logstash/vendor/jruby/bin"
7+
ENV LOGSTASH_SOURCE="1"
8+
RUN gem install bundler -v '< 2'
9+
WORKDIR /usr/share/plugins/plugin
10+
RUN bundle install
11+
COPY --chown=logstash:logstash . /usr/share/plugins/plugin

ci/unit/docker-compose.yml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
version: '3'
2+
3+
# run tests: cd ci/unit; docker-compose up --build --force-recreate
4+
# manual: cd ci/unit; docker-compose run logstash bash
5+
services:
6+
7+
logstash:
8+
build:
9+
context: ../../
10+
dockerfile: ci/unit/Dockerfile
11+
args:
12+
- ELASTIC_STACK_VERSION=$ELASTIC_STACK_VERSION
13+
command: /usr/share/plugins/plugin/ci/unit/run.sh
14+
environment:
15+
LS_JAVA_OPTS: "-Xmx256m -Xms256m"
16+
LOGSTASH_SOURCE: 1
17+
tty: true

ci/unit/docker-run.sh

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env bash
2+
3+
# This is intended to be run inside the docker container as the command of the docker-compose.
4+
set -ex
5+
docker-compose -f ci/unit/docker-compose.yml up --exit-code-from logstash

ci/unit/docker-setup.sh

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/env bash
2+
3+
# This is intended to be run the plugin's root directory. `ci/unit/docker-test.sh`
4+
# Ensure you have Docker installed locally and set the ELASTIC_STACK_VERSION environment variable.
5+
set -e
6+
7+
VERSION_URL="https://raw.githubusercontent.com/elastic/logstash/master/ci/logstash_releases.json"
8+
9+
if [ -z "${ELASTIC_STACK_VERSION}" ]; then
10+
echo "Please set the ELASTIC_STACK_VERSION environment variable"
11+
echo "For example: export ELASTIC_STACK_VERSION=6.2.4"
12+
exit 1
13+
fi
14+
15+
echo "Fetching versions from $VERSION_URL"
16+
VERSIONS=$(curl $VERSION_URL)
17+
18+
if [[ "$SNAPSHOT" = "true" ]]; then
19+
ELASTIC_STACK_RETRIEVED_VERSION=$(echo $VERSIONS | jq '.snapshots."'"$ELASTIC_STACK_VERSION"'"')
20+
echo $ELASTIC_STACK_RETRIEVED_VERSION
21+
else
22+
ELASTIC_STACK_RETRIEVED_VERSION=$(echo $VERSIONS | jq '.releases."'"$ELASTIC_STACK_VERSION"'"')
23+
fi
24+
25+
if [[ "$ELASTIC_STACK_RETRIEVED_VERSION" != "null" ]]; then
26+
# remove starting and trailing double quotes
27+
ELASTIC_STACK_RETRIEVED_VERSION="${ELASTIC_STACK_RETRIEVED_VERSION%\"}"
28+
ELASTIC_STACK_RETRIEVED_VERSION="${ELASTIC_STACK_RETRIEVED_VERSION#\"}"
29+
echo "Translated $ELASTIC_STACK_VERSION to ${ELASTIC_STACK_RETRIEVED_VERSION}"
30+
export ELASTIC_STACK_VERSION=$ELASTIC_STACK_RETRIEVED_VERSION
31+
fi
32+
33+
echo "Testing against version: $ELASTIC_STACK_VERSION"
34+
35+
if [[ "$ELASTIC_STACK_VERSION" = *"-SNAPSHOT" ]]; then
36+
cd /tmp
37+
38+
jq=".build.projects.logstash.packages.\"logstash-$ELASTIC_STACK_VERSION-docker-image.tar.gz\".url"
39+
result=$(curl --silent https://artifacts-api.elastic.co/v1/versions/$ELASTIC_STACK_VERSION/builds/latest | jq -r $jq)
40+
echo $result
41+
curl $result > logstash-docker-image.tar.gz
42+
tar xfvz logstash-docker-image.tar.gz repositories
43+
echo "Loading docker image: "
44+
cat repositories
45+
docker load < logstash-docker-image.tar.gz
46+
rm logstash-docker-image.tar.gz
47+
cd -
48+
fi
49+
50+
if [ -f Gemfile.lock ]; then
51+
rm Gemfile.lock
52+
fi
53+
54+
docker-compose -f ci/unit/docker-compose.yml down
55+
docker-compose -f ci/unit/docker-compose.yml build

ci/unit/run.sh

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env bash
2+
3+
# This is intended to be run inside the docker container as the command of the docker-compose.
4+
set -ex
5+
6+
export USER='logstash'
7+
8+
bundle exec rspec -fd 2>/dev/null

docs/index.asciidoc

+25-2
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ This plugin supports the following configuration options plus the <<plugins-{typ
149149
[cols="<,<,<",options="header",]
150150
|=======================================================================
151151
|Setting |Input type|Required
152+
| <<plugins-{type}s-{plugin}-plugin_timezone>> |<<string,string>>, one of `["local", "utc"]`|No
152153
| <<plugins-{type}s-{plugin}-clean_run>> |<<boolean,boolean>>|No
153154
| <<plugins-{type}s-{plugin}-columns_charset>> |<<hash,hash>>|No
154155
| <<plugins-{type}s-{plugin}-connection_retry_attempts>> |<<number,number>>|No
@@ -247,13 +248,35 @@ JDBC connection string
247248
* There is no default value for this setting.
248249

249250
Timezone conversion.
250-
SQL does not allow for timezone data in timestamp fields. This plugin will automatically
251-
convert your SQL timestamp fields to Logstash timestamps, in relative UTC time in ISO8601 format.
251+
Logstash (and Elasticsearch) expects that timestamps are expressed in UTC terms.
252+
If your database has recorded timestamps that are relative to another timezone,
253+
the database timezone if you will, then set this setting to be the timezone that
254+
the database is using. However, as SQL does not allow for timezone data in
255+
timestamp fields we can't figure this out on a record by record basis. This plugin
256+
will automatically convert your SQL timestamp fields to Logstash timestamps,
257+
in relative UTC time in ISO8601 format.
252258

253259
Using this setting will manually assign a specified timezone offset, instead
254260
of using the timezone setting of the local machine. You must use a canonical
255261
timezone, *America/Denver*, for example.
256262

263+
[id="plugins-{type}s-{plugin}-plugin_timezone"]
264+
===== `plugin_timezone`
265+
266+
* Value can be any of: `utc`, `local`
267+
* Default value is `"utc"`
268+
269+
If you want this plugin to offset timestamps to a timezone other than UTC, you
270+
can set this setting to `local` and the plugin will use the OS timezone for offset
271+
adjustments.
272+
273+
Note: when specifying `plugin_timezone` and/or `jdbc_default_timezone`, offset
274+
adjustments are made in two places, if `sql_last_value` is a timestamp and it
275+
is used as a parameter in the statement then offset adjustment is done from the
276+
plugin timezone into the data timezone and while records are processed, timestamps
277+
are offset adjusted from the database timezone to the plugin timezone. If your
278+
database timezone is UTC then you do not need to set either of these settings.
279+
257280
[id="plugins-{type}s-{plugin}-jdbc_driver_class"]
258281
===== `jdbc_driver_class`
259282

lib/logstash/inputs/jdbc.rb

+16-12
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
require "logstash/namespace"
44
require "logstash/plugin_mixins/jdbc/jdbc"
55

6+
# this require_relative returns early unless the JRuby version is between 9.2.0.0 and 9.2.8.0
7+
require_relative "tzinfo_jruby_patch"
68

79
# This plugin was created as a way to ingest data from any database
810
# with a JDBC interface into Logstash. You can periodically schedule ingestion
@@ -84,19 +86,19 @@
8486
# The file option only supports one SQL statement. The plugin will only accept one of the options.
8587
# It cannot read a statement from a file as well as from the `statement` configuration parameter.
8688
#
87-
# ==== Configuring multiple SQL statements
89+
# ==== Configuring multiple SQL statements
8890
#
89-
# Configuring multiple SQL statements is useful when there is a need to query and ingest data
90-
# from different database tables or views. It is possible to define separate Logstash
91-
# configuration files for each statement or to define multiple statements in a single configuration
92-
# file. When using multiple statements in a single Logstash configuration file, each statement
93-
# has to be defined as a separate jdbc input (including jdbc driver, connection string and other
94-
# required parameters).
91+
# Configuring multiple SQL statements is useful when there is a need to query and ingest data
92+
# from different database tables or views. It is possible to define separate Logstash
93+
# configuration files for each statement or to define multiple statements in a single configuration
94+
# file. When using multiple statements in a single Logstash configuration file, each statement
95+
# has to be defined as a separate jdbc input (including jdbc driver, connection string and other
96+
# required parameters).
9597
#
96-
# Please note that if any of the statements use the `sql_last_value` parameter (e.g. for
97-
# ingesting only data changed since last run), each input should define its own
98+
# Please note that if any of the statements use the `sql_last_value` parameter (e.g. for
99+
# ingesting only data changed since last run), each input should define its own
98100
# `last_run_metadata_path` parameter. Failure to do so will result in undesired behaviour, as
99-
# all inputs will store their state to the same (default) metadata file, effectively
101+
# all inputs will store their state to the same (default) metadata file, effectively
100102
# overwriting each other's `sql_last_value`.
101103
#
102104
# ==== Predefined Parameters
@@ -178,11 +180,11 @@ module LogStash module Inputs class Jdbc < LogStash::Inputs::Base
178180
# Whether to force the lowercasing of identifier fields
179181
config :lowercase_column_names, :validate => :boolean, :default => true
180182

181-
# The character encoding of all columns, leave empty if the columns are already properly UTF-8
183+
# The character encoding of all columns, leave empty if the columns are already properly UTF-8
182184
# encoded. Specific columns charsets using :columns_charset can override this setting.
183185
config :charset, :validate => :string
184186

185-
# The character encoding for specific columns. This option will override the `:charset` option
187+
# The character encoding for specific columns. This option will override the `:charset` option
186188
# for the specified columns.
187189
#
188190
# Example:
@@ -199,6 +201,8 @@ module LogStash module Inputs class Jdbc < LogStash::Inputs::Base
199201
# this will only convert column0 that has ISO-8859-1 as an original encoding.
200202
config :columns_charset, :validate => :hash, :default => {}
201203

204+
attr_reader :database # for test mocking/stubbing
205+
202206
public
203207

204208
def register
+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# encoding: UTF-8
2+
# frozen_string_literal: true
3+
4+
# There is a bug in JRuby versions between 9.2.0.0 and 9.2.8.0
5+
# the TZinfo::Timestamp `new_datetime` can build Rational numbers having
6+
# numerators and denominators that are too large for Java longs.
7+
#
8+
# This patch reopens the TZinfo::Timestamp class and redefines
9+
# the `new_datetime method.
10+
# It scales down the numerator and denominator if they are larger than
11+
# Java Long. There is no appreciable precision loss at the microsecond level
12+
13+
tzinfo_jruby_bugfixed_version = "9.2.8.0"
14+
tzinfo_jruby_bugadded_version = "9.2.0.0"
15+
16+
current_jruby_version = Gem::Version.new(JRUBY_VERSION)
17+
broken_jruby_version = Gem::Version.new(tzinfo_jruby_bugadded_version)
18+
patched_jruby_version = Gem::Version.new(tzinfo_jruby_bugfixed_version)
19+
20+
return unless current_jruby_version >= broken_jruby_version && current_jruby_version < patched_jruby_version
21+
22+
require 'tzinfo'
23+
24+
if defined?(TZInfo::VERSION) && TZInfo::VERSION > '2'
25+
module TZInfo
26+
# A time represented as an `Integer` number of seconds since 1970-01-01
27+
# 00:00:00 UTC (ignoring leap seconds), the fraction through the second
28+
# (sub_second as a `Rational`) and an optional UTC offset. Like Ruby's `Time`
29+
# class, {Timestamp} can distinguish between a local time with a zero offset
30+
# and a time specified explicitly as UTC.
31+
class Timestamp
32+
33+
protected
34+
35+
def new_datetime(klass = DateTime)
36+
val = JD_EPOCH + ((@value.to_r + @sub_second) / 86400)
37+
datetime = klass.jd(jruby_scale_down_rational(val))
38+
@utc_offset && @utc_offset != 0 ? datetime.new_offset(Rational(@utc_offset, 86400)) : datetime
39+
end
40+
41+
private
42+
43+
# while this JRuby bug exists in 9.2.X.X https://github.com/jruby/jruby/issues/5791
44+
# we must scale down the numerator and denominator to fit Java Long values.
45+
46+
def jruby_scale_down_rational(rat)
47+
return rat if rat.numerator <= java.lang.Long::MAX_VALUE
48+
[10, 100, 1000].each do |scale_by|
49+
new_numerator = rat.numerator / scale_by
50+
if new_numerator <= java.lang.Long::MAX_VALUE
51+
return Rational(new_numerator, rat.denominator / scale_by)
52+
end
53+
end
54+
end
55+
end
56+
end
57+
end

0 commit comments

Comments
 (0)