logstash-output-jdbc 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 033e6d7684e87ec8494733ad218b09ad81145442
4
+ data.tar.gz: 4b2502b6210e89621a9416a32666d5e511082fe1
5
+ SHA512:
6
+ metadata.gz: 4584a4a7129bf1dcbcb30a2d7bb3b628aef7bacd7a9d8607768ffcb2f77f63ee3ee915ed72b80f378fd55efaa6d7dd48a7722003816790f64b85f61ac18985dc
7
+ data.tar.gz: a75c975b799472844afd9448e2f054ac8ce6d1b618ba77daae8a4ceb3acce7919c3ae912a6044594f4d608528e5a08255e163926ffa8a6f9b0f6fe3c88d389ed
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ Gemfile.lock
3
+ Gemfile.bak
4
+ .bundle
5
+ vendor
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,97 @@
1
+ # logstash-jdbc
2
+ JDBC output plugin for Logstash.
3
+ This plugin is provided as an external plugin and is not part of the Logstash project.
4
+
5
+ ## Warning
6
+ The master branch is for 1.5, is currently incomplete and should NOT be used (yet).
7
+
8
+ Please see the v1.4 branch for v1.4 of Logstash.
9
+
10
+ This has not yet been extensively tested with all JDBC drivers and may not yet work for you.
11
+
12
+ ## Installation
13
+ - Copy lib directory contents into your logstash installation.
14
+ - Create the directory vendor/jar/jdbc in your logstash installation (`mkdir -p vendor/jar/jdbc/`)
15
+ - Add JDBC jar files to vendor/jar/jdbc in your logstash installation
16
+ - Configure
17
+
18
+ ## Configuration options
19
+ * driver_class, string, JDBC driver class to load
20
+ * connection_string, string, JDBC connection string
21
+ * statement, array, an array of strings representing the SQL statement to run. Index 0 is the SQL statement that is prepared, all other array entries are passed in as parameters (in order). A parameter may either be a property of the event (i.e. "@timestamp", or "host") or a formatted string (i.e. "%{host} - %{message}" or "%{message}"). If a key is passed then it will be automatically converted as required for insertion into SQL. If it's a formatted string then it will be passed in verbatim.
22
+ * flush_size, number, default = 1000, number of entries to buffer before sending to SQL
23
+ * idle_flush_time, number, default = 1, number of idle seconds before sending data to SQL, even if the flush_size has not been reached. If you modify this value you should also consider altering max_repeat_exceptions_time
24
+ * max_repeat_exceptions, number, default = 5, number of times the same exception can repeat before we stop logstash. Set to a value less than 1 if you never want it to stop
25
+ * max_repeat_exceptions_time, number, default = 30, maxium number of seconds between exceptions before they're considered "different" exceptions. If you modify idle_flush_time you should consider this value
26
+
27
+ ## Example configurations
28
+ ### SQLite3
29
+ * Tested using https://bitbucket.org/xerial/sqlite-jdbc
30
+ * SQLite setup - `echo "CREATE table log (host text, timestamp datetime, message text);" | sqlite3 test.db`
31
+ ```
32
+ input
33
+ {
34
+ stdin { }
35
+ }
36
+ output {
37
+ stdout { }
38
+
39
+ jdbc {
40
+ driver_class => 'org.sqlite.JDBC'
41
+ connection_string => 'jdbc:sqlite:test.db'
42
+ statement => [ "INSERT INTO log (host, timestamp, message) VALUES(?, ?, ?)", "host", "@timestamp", "message" ]
43
+ }
44
+ }
45
+ ```
46
+
47
+ ### SQL Server
48
+ * Tested using http://msdn.microsoft.com/en-gb/sqlserver/aa937724.aspx
49
+ ```
50
+ input
51
+ {
52
+ stdin { }
53
+ }
54
+ output {
55
+ jdbc {
56
+ driver_class => 'com.microsoft.sqlserver.jdbc.SQLServerDriver'
57
+ connection_string => "jdbc:sqlserver://server:1433;databaseName=databasename;user=username;password=password;autoReconnect=true;"
58
+ statement => [ "INSERT INTO log (host, timestamp, message) VALUES(?, ?, ?)", "host", "@timestamp", "message" ]
59
+ }
60
+ }
61
+ ```
62
+
63
+ ### Postgres
64
+ With thanks to [@roflmao](https://github.com/roflmao)
65
+ ```
66
+ input
67
+ {
68
+ stdin { }
69
+ }
70
+ output {
71
+ jdbc {
72
+ driver_class => 'org.postgresql.Driver'
73
+ connection_string => 'jdbc:postgresql://hostname:5432/database?user=username&password=password'
74
+ statement => [ "INSERT INTO log (host, timestamp, message) VALUES(?, CAST (? AS timestamp), ?)", "host", "@timestamp", "message" ]
75
+ }
76
+ }
77
+ ```
78
+
79
+ ### Oracle
80
+ With thanks to [@josemazo](https://github.com/josemazo)
81
+ * Tested with Express Edition 11g Release 2
82
+ * Tested using http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-112010-090769.html (ojdbc6.jar)
83
+ ```
84
+ input
85
+ {
86
+ stdin { }
87
+ }
88
+ output {
89
+ jdbc {
90
+ driver_class => "oracle.jdbc.driver.OracleDriver"
91
+ connection_string => "jdbc:oracle:thin:USER/PASS@HOST:PORT:SID"
92
+ statement => [ "INSERT INTO log (host, timestamp, message) VALUES(?, CAST (? AS timestamp), ?)", "host", "@timestamp", "message" ]
93
+ }
94
+ }
95
+ ```
96
+
97
+ /* vim: set ts=4 sw=4 tw=0 :*/
@@ -0,0 +1 @@
1
+ require "logstash/devutils/rake"
@@ -0,0 +1,165 @@
1
+ # encoding: utf-8
2
+ require "logstash/outputs/base"
3
+ require "logstash/namespace"
4
+ require "stud/buffer"
5
+ require "java"
6
+
7
+ class LogStash::Outputs::Jdbc < LogStash::Outputs::Base
8
+ # Adds buffer support
9
+ include Stud::Buffer
10
+
11
+ config_name "jdbc"
12
+
13
+ # Driver class
14
+ config :driver_class, :validate => :string
15
+
16
+ # connection string
17
+ config :connection_string, :validate => :string, :required => true
18
+
19
+ # [ "insert into table (message) values(?)", "%{message}" ]
20
+ config :statement, :validate => :array, :required => true
21
+
22
+ # We buffer a certain number of events before flushing that out to SQL.
23
+ # This setting controls how many events will be buffered before sending a
24
+ # batch of events.
25
+ config :flush_size, :validate => :number, :default => 1000
26
+
27
+ # The amount of time since last flush before a flush is forced.
28
+ #
29
+ # This setting helps ensure slow event rates don't get stuck in Logstash.
30
+ # For example, if your `flush_size` is 100, and you have received 10 events,
31
+ # and it has been more than `idle_flush_time` seconds since the last flush,
32
+ # Logstash will flush those 10 events automatically.
33
+ #
34
+ # This helps keep both fast and slow log streams moving along in
35
+ # a timely manner.
36
+ #
37
+ # If you change this value please ensure that you change
38
+ # max_repeat_exceptions_time accordingly.
39
+ config :idle_flush_time, :validate => :number, :default => 1
40
+
41
+ # Maximum number of repeating (sequential) exceptions, before we stop retrying
42
+ # If set to < 1, then it will infinitely retry.
43
+ config :max_repeat_exceptions, :validate => :number, :default => 5
44
+
45
+ # The max number of seconds since the last exception, before we consider it
46
+ # a different cause.
47
+ # This value should be carefully considered in respect to idle_flush_time.
48
+ config :max_repeat_exceptions_time, :validate => :number, :default => 30
49
+
50
+ public
51
+ def register
52
+
53
+ @logger.info("JDBC - Starting up")
54
+
55
+ if ENV['LOGSTASH_HOME']
56
+ jarpath = File.join(ENV['LOGSTASH_HOME'], "/vendor/jar/jdbc/*.jar")
57
+ else
58
+ jarpath = File.join(File.dirname(__FILE__), "../../../vendor/jar/jdbc/*.jar")
59
+ end
60
+
61
+ @logger.debug("JDBC - jarpath", path: jarpath)
62
+
63
+ jars = Dir[jarpath]
64
+ raise Exception.new("JDBC - No jars found in jarpath. Have you read the README?") if jars.empty?
65
+
66
+ jars.each do |jar|
67
+ @logger.debug("JDBC - Loaded jar", :jar => jar)
68
+ require jar
69
+ end
70
+
71
+ import @driver_class
72
+
73
+ driver = Object.const_get(@driver_class[@driver_class.rindex('.') + 1, @driver_class.length]).new
74
+ @connection = driver.connect(@connection_string, java.util.Properties.new)
75
+
76
+ @logger.debug("JDBC - Created connection", :driver => driver, :connection => @connection)
77
+
78
+ if (@flush_size > 1000)
79
+ @logger.warn("JDBC - Flush size is set to > 1000. May have performance penalties, depending on your SQL engine.")
80
+ end
81
+
82
+ @repeat_exception_count = 0
83
+ @last_exception_time = Time.now
84
+
85
+ if (@max_repeat_exceptions > 0) and ((@idle_flush_time * @max_repeat_exceptions) > @max_repeat_exceptions_time)
86
+ @logger.warn("JDBC - max_repeat_exceptions_time is set such that it may still permit a looping exception. You probably changed idle_flush_time. Considering increasing max_repeat_exceptions_time.")
87
+ end
88
+
89
+ buffer_initialize(
90
+ :max_items => @flush_size,
91
+ :max_interval => @idle_flush_time,
92
+ :logger => @logger
93
+ )
94
+ end
95
+
96
+ def receive(event)
97
+ return unless output?(event)
98
+ return unless @statement.length > 0
99
+
100
+ buffer_receive(event)
101
+ end
102
+
103
+ def flush(events, teardown=false)
104
+ statement = @connection.prepareStatement(@statement[0])
105
+
106
+ events.each do |event|
107
+ next if @statement.length < 2
108
+
109
+ @statement[1..-1].each_with_index do |i, idx|
110
+ case event[i]
111
+ when Time, LogStash::Timestamp
112
+ # Most reliable solution, cross JDBC driver
113
+ statement.setString(idx + 1, event[i].iso8601())
114
+ when Fixnum, Integer
115
+ statement.setInt(idx + 1, event[i])
116
+ when Float
117
+ statement.setFloat(idx + 1, event[i])
118
+ when String
119
+ statement.setString(idx + 1, event[i])
120
+ else
121
+ statement.setString(idx + 1, event.sprintf(i))
122
+ end
123
+ end
124
+
125
+ statement.addBatch()
126
+ end
127
+
128
+ begin
129
+ @logger.debug("JDBC - Sending SQL", :sql => statement.toString())
130
+ statement.executeBatch()
131
+ rescue => e
132
+ # Raising an exception will incur a retry from Stud::Buffer.
133
+ # Since the exceutebatch failed this should mean any events failed to be
134
+ # inserted will be re-run. We're going to log it for the lols anyway.
135
+ @logger.warn("JDBC - Exception. Will automatically retry", :exception => e)
136
+ end
137
+
138
+ statement.close()
139
+ end
140
+
141
+ def on_flush_error(e)
142
+ return if @max_repeat_exceptions < 1
143
+
144
+ if @last_exception == e.to_s
145
+ @repeat_exception_count += 1
146
+ else
147
+ @repeat_exception_count = 0
148
+ end
149
+
150
+ if (@repeat_exception_count >= @max_repeat_exceptions) and (Time.now - @last_exception_time) < @max_repeat_exceptions_time
151
+ @logger.error("JDBC - Exception repeated more than the maximum configured", :exception => e, :max_repeat_exceptions => @max_repeat_exceptions, :max_repeat_exceptions_time => @max_repeat_exceptions_time)
152
+ raise e
153
+ end
154
+
155
+ @last_exception_time = Time.now
156
+ @last_exception = e.to_s
157
+ end
158
+
159
+ def teardown
160
+ buffer_flush(:final => true)
161
+ @connection.close()
162
+ super
163
+ end
164
+
165
+ end # class LogStash::Outputs::jdbc
@@ -0,0 +1,24 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'logstash-output-jdbc'
3
+ s.version = "0.1.0"
4
+ s.licenses = [ "Apache License (2.0)" ]
5
+ s.summary = "This plugin allows you to output to SQL, via JDBC"
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 = ["the_angry_angel"]
8
+ s.email = "karl+github@theangryangel.co.uk"
9
+ s.homepage = "https://github.com/theangryangel/logstash-output-jdbc"
10
+ s.require_paths = [ "lib" ]
11
+
12
+ # Files
13
+ s.files = `git ls-files`.split($\)
14
+ # Tests
15
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
16
+
17
+ # Special flag to let us know this is actually a logstash plugin
18
+ s.metadata = { "logstash_plugin" => "true", "logstash_group" => "output" }
19
+
20
+ # Gem dependencies
21
+ s.add_runtime_dependency "logstash-core", ">= 1.4.0", "< 2.0.0"
22
+ s.add_runtime_dependency "logstash-codec-plain"
23
+ s.add_development_dependency "logstash-devutils"
24
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: logstash-output-jdbc
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - the_angry_angel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-06-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: logstash-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.4.0
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: 2.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 1.4.0
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: 2.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: logstash-codec-plain
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: logstash-devutils
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ description: This gem is a logstash plugin required to be installed on top of the
62
+ Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not
63
+ a stand-alone program
64
+ email: karl+github@theangryangel.co.uk
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - ".gitignore"
70
+ - Gemfile
71
+ - LICENSE.txt
72
+ - README.md
73
+ - Rakefile
74
+ - lib/logstash/outputs/jdbc.rb
75
+ - logstash-output-jdbc.gemspec
76
+ homepage: https://github.com/theangryangel/logstash-output-jdbc
77
+ licenses:
78
+ - Apache License (2.0)
79
+ metadata:
80
+ logstash_plugin: 'true'
81
+ logstash_group: output
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.4.5
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: This plugin allows you to output to SQL, via JDBC
102
+ test_files: []