logstash-filter-jdbc 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cbd156b8cd6dbdd977575f47331cddd69a8c85e5
4
+ data.tar.gz: 1bc4f90f12e3c4cb2a0f3bd40ece7abad49fbf1c
5
+ SHA512:
6
+ metadata.gz: 61554b48417126c424bff92340575f16f67fd06b3284fd4b434e8694d577ac5050d43bc626c303d6c2ba5513f8949c5367de21a2ea269f0ab40c5248ab7b9ac1
7
+ data.tar.gz: d7d314c6012188fe20f386164781e32ac977826c09f903c62f1b7e74cb771479bb9ea9ff9e9d5b8b428bb9487e3b5cc949bbda6fcd11239c235cab714c0bf90b
@@ -0,0 +1,14 @@
1
+ # About mixin definition
2
+
3
+ Whether it is for input/filter/output, communicating with a database through JDBC should be very similar as it would require common capabilities:
4
+
5
+ * connection pool
6
+ * transaction
7
+ * ...
8
+
9
+ but it can be implemented with different libraries:
10
+
11
+ * Ruby: Sequel, Activerecords,...
12
+ * Java: Plain JDBC, Apache commons- DBCP, c3p0 ...
13
+
14
+ This filter contains a mixin proposal based on Sequel
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2012-2015 Elasticsearch <http://www.elasticsearch.org>
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,100 @@
1
+ # Work in progress
2
+
3
+ This plugin is a work in progress.
4
+ Please see DEVELOPMENT.md for more information.
5
+
6
+ # Logstash Plugin
7
+
8
+ This is a plugin for [Logstash](https://github.com/elasticsearch/logstash).
9
+
10
+ It is fully free and fully open source. The license is Apache 2.0, meaning you are pretty much free to use it however you want in whatever way.
11
+
12
+ ## Documentation
13
+
14
+ Logstash provides infrastructure to automatically generate documentation for this plugin. We use the asciidoc format to write documentation so any comments in the source code will be first converted into asciidoc and then into html. All plugin documentation are placed under one [central location](http://www.elasticsearch.org/guide/en/logstash/current/).
15
+
16
+ - For formatting code or config example, you can use the asciidoc `[source,ruby]` directive
17
+ - For more asciidoc formatting tips, see the excellent reference here https://github.com/elasticsearch/docs#asciidoc-guide
18
+
19
+ ## Need Help?
20
+
21
+ Need help? Try #logstash on freenode IRC or the logstash-users@googlegroups.com mailing list.
22
+
23
+ ## Developing
24
+
25
+ ### 1. Plugin Developement and Testing
26
+
27
+ #### Code
28
+ - To get started, you'll need JRuby with the Bundler gem installed.
29
+
30
+ - Create a new plugin or clone and existing from the GitHub [logstash-plugins](https://github.com/logstash-plugins) organization.
31
+
32
+ - Install dependencies
33
+ ```sh
34
+ bundle install
35
+ ```
36
+
37
+ #### Test
38
+
39
+ ```sh
40
+ bundle exec rspec
41
+ ```
42
+
43
+ The Logstash code required to run the tests/specs is specified in the `Gemfile` by the line similar to:
44
+ ```ruby
45
+ gem "logstash", :github => "elasticsearch/logstash", :branch => "1.5"
46
+ ```
47
+ To test against another version or a local Logstash, edit the `Gemfile` to specify an alternative location, for example:
48
+ ```ruby
49
+ gem "logstash", :github => "elasticsearch/logstash", :ref => "master"
50
+ ```
51
+ ```ruby
52
+ gem "logstash", :path => "/your/local/logstash"
53
+ ```
54
+
55
+ Then update your dependencies and run your tests:
56
+
57
+ ```sh
58
+ bundle install
59
+ bundle exec rspec
60
+ ```
61
+
62
+ ### 2. Running your unpublished Plugin in Logstash
63
+
64
+ #### 2.1 Run in a local Logstash clone
65
+
66
+ - Edit Logstash `tools/Gemfile` and add the local plugin path, for example:
67
+ ```ruby
68
+ gem "logstash-filter-awesome", :path => "/your/local/logstash-filter-awesome"
69
+ ```
70
+ - Update Logstash dependencies
71
+ ```sh
72
+ rake vendor:gems
73
+ ```
74
+ - Run Logstash with your plugin
75
+ ```sh
76
+ bin/logstash -e 'filter {awesome {}}'
77
+ ```
78
+ At this point any modifications to the plugin code will be applied to this local Logstash setup. After modifying the plugin, simply rerun Logstash.
79
+
80
+ #### 2.2 Run in an installed Logstash
81
+
82
+ - Build your plugin gem
83
+ ```sh
84
+ gem build logstash-filter-awesome.gemspec
85
+ ```
86
+ - Install the plugin from the Logstash home
87
+ ```sh
88
+ bin/plugin install /your/local/plugin/logstash-filter-awesome.gem
89
+ ```
90
+ - Start Logstash and proceed to test the plugin
91
+
92
+ ## Contributing
93
+
94
+ All contributions are welcome: ideas, patches, documentation, bug reports, complaints, and even something you drew up on a napkin.
95
+
96
+ Programming is not a required skill. Whatever you've seen about open source and maintainers or community members saying "send patches or die" - you will not see that here.
97
+
98
+ It is more important to me that you are able to contribute.
99
+
100
+ For more information about contributing, see the [CONTRIBUTING](https://github.com/elasticsearch/logstash/blob/master/CONTRIBUTING.md) file.
@@ -0,0 +1,68 @@
1
+ # encoding: utf-8
2
+ require "logstash/filters/base"
3
+ require "logstash/namespace"
4
+ require "logstash/plugin_mixins/jdbc"
5
+
6
+ # This filter executes a SQL query and store the result set in the field
7
+ # specified as `target`.
8
+ #
9
+ # For example you can load a row based on an id from in the event
10
+ #
11
+ # [source,ruby]
12
+ # filter {
13
+ # jdbc {
14
+ # jdbc_driver_library => "/path/to/mysql-connector-java-5.1.34-bin.jar"
15
+ # jdbc_driver_class => "com.mysql.jdbc.Driver"
16
+ # jdbc_connection_string => ""jdbc:mysql://localhost:3306/mydatabase"
17
+ # jdbc_user => "me"
18
+ # jdbc_password => "secret"
19
+ # statement => "select * from WORLD.COUNTRY WHERE Code = :code"
20
+ # parameters => { "code" => "country_code"}
21
+ # target => "country_details"
22
+ # }
23
+ # }
24
+ #
25
+ class LogStash::Filters::Jdbc < LogStash::Filters::Base
26
+ include LogStash::PluginMixins::Jdbc
27
+ config_name "jdbc"
28
+
29
+ # Statement to execute.
30
+ # To use parameters, use named parameter syntax, for example "SELECT * FROM MYTABLE WHERE ID = :id"
31
+ config :statement, :validate => :string, :required => true
32
+
33
+ # Hash of query parameter, for example `{ "id" => "id_field" }`
34
+ config :parameters, :validate => :hash, :default => {}
35
+
36
+ # Target field to store the result set.
37
+ # Field is overwritten if exists.
38
+ config :target, :validate => :string, :required => true
39
+
40
+ # Append values to the `tags` field if sql error occured
41
+ config :tag_on_failure, :validate => :array, :default => ["_jdbcfailure"]
42
+
43
+
44
+ public
45
+ def register
46
+ prepare_jdbc_connection()
47
+ end # def register
48
+
49
+ public
50
+ def filter(event)
51
+ result = []
52
+ #Prepare parameters from event values
53
+ params = @parameters.inject({}) {|hash,(k,v)| hash[k] = event[event.sprintf(v)] ; hash }
54
+ #Execute statement and collect results
55
+ success = execute_statement(@statement,params) do |row|
56
+ result << row
57
+ end
58
+ if success
59
+ event[@target] = result
60
+ filter_matched(event)
61
+ else
62
+ @tag_on_failure.each do |tag|
63
+ event["tags"] ||= []
64
+ event["tags"] << tag unless event["tags"].include?(tag)
65
+ end
66
+ end
67
+ end # def filter
68
+ end # class LogStash::Filters::Jdbc
@@ -0,0 +1,90 @@
1
+ # encoding: utf-8
2
+ require "logstash/config/mixin"
3
+
4
+ # Tentative of abstracting JDBC logic to a mixin
5
+ # for potential reuse in other plugins (input/output)
6
+ module LogStash::PluginMixins::Jdbc
7
+
8
+ @logger = Cabin::Channel.get(LogStash)
9
+
10
+ # This method is called when someone includes this module
11
+ def self.included(base)
12
+ # Add these methods to the 'base' given.
13
+ base.extend(self)
14
+ base.setup_jdbc_config
15
+ end
16
+
17
+
18
+ public
19
+ def setup_jdbc_config
20
+ # JDBC driver library path to third party driver library.
21
+ config :jdbc_driver_library, :validate => :path
22
+
23
+ # JDBC driver class to load, for example "oracle.jdbc.OracleDriver" or "org.apache.derby.jdbc.ClientDriver"
24
+ config :jdbc_driver_class, :validate => :string, :required => true
25
+
26
+ # JDBC connection string
27
+ config :jdbc_connection_string, :validate => :string, :required => true
28
+
29
+ # JDBC user
30
+ config :jdbc_user, :validate => :string
31
+
32
+ # JDBC password
33
+ config :jdbc_password, :validate => :password
34
+
35
+ # Connection pool configuration.
36
+ # Validate connection before use.
37
+ config :jdbc_validate_connection, :validate => :boolean, :default => false
38
+
39
+ # Connection pool configuration.
40
+ # How often to validate a connection (in seconds)
41
+ config :jdcb_validation_timeout, :validate => :number, :default => 3600
42
+ end
43
+
44
+ public
45
+ def prepare_jdbc_connection
46
+ require "sequel"
47
+ require "sequel/adapters/jdbc"
48
+ require "java"
49
+ require @jdbc_driver_library if @jdbc_driver_library
50
+ Sequel::JDBC.load_driver(@jdbc_driver_class)
51
+ @database = Sequel.connect(@jdbc_connection_string, :user=> @jdbc_user, :password=> @jdbc_password.nil? ? nil : @jdbc_password.value)
52
+ if @jdbc_validate_connection
53
+ @database.extension(:connection_validator)
54
+ @database.pool.connection_validation_timeout = @jdcb_validation_timeout
55
+ end
56
+ begin
57
+ @database.test_connection
58
+ rescue Sequel::DatabaseConnectionError => e
59
+ #TODO return false and let the plugin raise a LogStash::ConfigurationError
60
+ raise e
61
+ end
62
+ end # def prepare_jdbc_connection
63
+
64
+ public
65
+ def execute_statement(statement, parameters)
66
+ success = false
67
+ begin
68
+ #Symbolize parameters keys to use with Sequel
69
+ parameters = parameters.inject({}) do |hash,(k,v)|
70
+ case v
71
+ when LogStash::Timestamp
72
+ hash[k.to_sym] = v.time
73
+ else
74
+ hash[k.to_sym] = v
75
+ end
76
+ hash
77
+ end
78
+ query = @database[statement,parameters]
79
+ @logger.debug? and @logger.debug("Executing JDBC query", :statement => statement, :parameters => parameters)
80
+ query.all do |row|
81
+ #Stringify row keys
82
+ yield row.inject({}){|hash,(k,v)| hash[k.to_s] = v; hash}
83
+ end
84
+ success = true
85
+ rescue Sequel::DatabaseConnectionError, Sequel::DatabaseError => e
86
+ @logger.warn("Exception when executing JDBC query", :exception => e)
87
+ end
88
+ return success
89
+ end
90
+ end
@@ -0,0 +1,27 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'logstash-filter-jdbc'
3
+ s.version = '0.1.2'
4
+ s.licenses = ['Apache License (2.0)']
5
+ s.summary = "This filter executes a SQL query and store the result set in the event."
6
+ s.description = "This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program"
7
+ s.authors = ["Elastic"]
8
+ s.email = 'info@elastic.co'
9
+ s.homepage = "http://www.elastic.co/guide/en/logstash/current/index.html"
10
+ s.require_paths = ["lib"]
11
+
12
+ # Files
13
+ s.files = Dir['lib/**/*','spec/**/*','vendor/**/*','*.gemspec','*.md','CONTRIBUTORS','Gemfile','LICENSE','NOTICE.TXT']
14
+
15
+ # Tests
16
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
17
+
18
+ # Special flag to let us know this is actually a logstash plugin
19
+ s.metadata = { "logstash_plugin" => "true", "logstash_group" => "filter" }
20
+
21
+ # Gem dependencies
22
+ s.add_runtime_dependency "logstash-core", '>= 2.0.0.beta2', '< 5.0.0'
23
+ s.add_runtime_dependency 'sequel'
24
+
25
+ s.add_development_dependency 'logstash-devutils'
26
+ s.add_development_dependency 'jdbc-derby'
27
+ end
@@ -0,0 +1,109 @@
1
+ require 'spec_helper'
2
+ require "logstash/filters/jdbc"
3
+ require 'jdbc/derby'
4
+ describe LogStash::Filters::Jdbc do
5
+ #Use embedded Derby for tests
6
+ Jdbc::Derby.load_driver
7
+
8
+ describe "All default - Retrieve a value from database" do
9
+ let(:config) do <<-CONFIG
10
+ filter {
11
+ jdbc {
12
+ jdbc_driver_class => "org.apache.derby.jdbc.EmbeddedDriver"
13
+ jdbc_connection_string => "jdbc:derby:memory:testdb;create=true"
14
+ statement => "SELECT 'from_database' FROM SYSIBM.SYSDUMMY1"
15
+ target => "new_field"
16
+ }
17
+ }
18
+ CONFIG
19
+ end
20
+
21
+ sample("message" => "some text") do
22
+ expect(subject['new_field']).to eq([{"1" => 'from_database'}])
23
+ end
24
+ end
25
+
26
+ describe "Named column - Retrieve a value from database" do
27
+ let(:config) do <<-CONFIG
28
+ filter {
29
+ jdbc {
30
+ jdbc_driver_class => "org.apache.derby.jdbc.EmbeddedDriver"
31
+ jdbc_connection_string => "jdbc:derby:memory:testdb;create=true"
32
+ statement => "SELECT 'from_database' as col_1 FROM SYSIBM.SYSDUMMY1"
33
+ target => "new_field"
34
+ }
35
+ }
36
+ CONFIG
37
+ end
38
+
39
+ sample("message" => "some text") do
40
+ expect(subject['new_field']).to eq([{"col_1" => 'from_database'}])
41
+ end
42
+ end
43
+
44
+ describe "Using string parameters - Retrieve a value from database" do
45
+ let(:config) do <<-CONFIG
46
+ filter {
47
+ jdbc {
48
+ jdbc_driver_class => "org.apache.derby.jdbc.EmbeddedDriver"
49
+ jdbc_connection_string => "jdbc:derby:memory:testdb;create=true"
50
+ statement => "SELECT 'from_database' FROM SYSIBM.SYSDUMMY1 WHERE '1' = :param"
51
+ parameters => { "param" => "param_field"}
52
+ target => "new_field"
53
+ }
54
+ }
55
+ CONFIG
56
+ end
57
+
58
+ sample("message" => "some text", "param_field" => "1") do
59
+ expect(subject['new_field']).to eq([{"1" => 'from_database'}])
60
+ end
61
+
62
+ sample("message" => "some text", "param_field" => "2") do
63
+ expect(subject['new_field'].nil?)
64
+ end
65
+ end
66
+
67
+ describe "Using integer parameters" do
68
+ let(:config) do <<-CONFIG
69
+ filter {
70
+ jdbc {
71
+ jdbc_driver_class => "org.apache.derby.jdbc.EmbeddedDriver"
72
+ jdbc_connection_string => "jdbc:derby:memory:testdb;create=true"
73
+ statement => "SELECT 'from_database' FROM SYSIBM.SYSDUMMY1 WHERE 1 = :param"
74
+ parameters => { "param" => "param_field"}
75
+ target => "new_field"
76
+ }
77
+ }
78
+ CONFIG
79
+ end
80
+
81
+ sample("message" => "some text", "param_field" => 1) do
82
+ expect(subject['new_field']).to eq([{"1" => 'from_database'}])
83
+ end
84
+
85
+ sample("message" => "some text", "param_field" => "1") do
86
+ expect(subject['new_field'].nil?)
87
+ end
88
+ end
89
+
90
+ describe "Using timestamp parameter" do
91
+ let(:config) do <<-CONFIG
92
+ filter {
93
+ jdbc {
94
+ jdbc_driver_class => "org.apache.derby.jdbc.EmbeddedDriver"
95
+ jdbc_connection_string => "jdbc:derby:memory:testdb;create=true"
96
+ statement => "SELECT 'from_database' FROM SYSIBM.SYSDUMMY1 WHERE {fn TIMESTAMPDIFF( SQL_TSI_DAY, {t :param}, current_timestamp)} = 0"
97
+ parameters => { "param" => "@timestamp"}
98
+ target => "new_field"
99
+ }
100
+ }
101
+ CONFIG
102
+ end
103
+
104
+ sample("message" => "some text") do
105
+ expect(subject['new_field']).to eq([{"1" => 'from_database'}])
106
+ end
107
+ end
108
+ end
109
+
@@ -0,0 +1 @@
1
+ require "logstash/devutils/rspec/spec_helper"
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: logstash-filter-jdbc
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Elastic
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-12-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - '>='
17
+ - !ruby/object:Gem::Version
18
+ version: 2.0.0.beta2
19
+ - - <
20
+ - !ruby/object:Gem::Version
21
+ version: 5.0.0
22
+ name: logstash-core
23
+ prerelease: false
24
+ type: :runtime
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 2.0.0.beta2
30
+ - - <
31
+ - !ruby/object:Gem::Version
32
+ version: 5.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ name: sequel
40
+ prerelease: false
41
+ type: :runtime
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ requirement: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ name: logstash-devutils
54
+ prerelease: false
55
+ type: :development
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ name: jdbc-derby
68
+ prerelease: false
69
+ type: :development
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ description: This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program
76
+ email: info@elastic.co
77
+ executables: []
78
+ extensions: []
79
+ extra_rdoc_files: []
80
+ files:
81
+ - DEVELOPMENT.md
82
+ - Gemfile
83
+ - LICENSE
84
+ - README.md
85
+ - lib/logstash/filters/jdbc.rb
86
+ - lib/logstash/plugin_mixins/jdbc.rb
87
+ - logstash-filter-jdbc.gemspec
88
+ - spec/filters/jdbc_spec.rb
89
+ - spec/spec_helper.rb
90
+ homepage: http://www.elastic.co/guide/en/logstash/current/index.html
91
+ licenses:
92
+ - Apache License (2.0)
93
+ metadata:
94
+ logstash_plugin: 'true'
95
+ logstash_group: filter
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubyforge_project:
112
+ rubygems_version: 2.4.8
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: This filter executes a SQL query and store the result set in the event.
116
+ test_files:
117
+ - spec/filters/jdbc_spec.rb
118
+ - spec/spec_helper.rb