logstash-input-drupal_dblog 0.1.1-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ab1d14e9119a017b64d778d9b8f84b76898556ad
4
+ data.tar.gz: 74b57346691258168e9832c9ae3d8731986d0569
5
+ SHA512:
6
+ metadata.gz: d823b5c58ef1f8c6574d6c0fdf7ce9fef18e3d0ce533c5ee523161b0942a86c87ed9a2dfb984ec4a3d5d993fa30c03d00bfe864b84bc0999701a67b3536d97ff
7
+ data.tar.gz: c576c6d730e8f697091edbb9d9a6529cdbfb652f959f09ecd94b202534be3d55e603db8ee09ff60d8e6387dbd5d73fab129b9dccb040670f2eb8ddef73015cfe
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ Gemfile.lock
3
+ .bundle
4
+ vendor
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+ gem "logstash", :github => "elasticsearch/logstash", :branch => "1.5"
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2012-2014 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.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ @files=[]
2
+
3
+ task :default do
4
+ system("rake -T")
5
+ end
6
+
7
+ require "logstash/devutils/rake"
@@ -0,0 +1,324 @@
1
+ # encoding: utf-8
2
+ require "date"
3
+ require "logstash/inputs/base"
4
+ require "logstash/namespace"
5
+
6
+
7
+ # Retrieve watchdog log events from a Drupal installation with DBLog enabled.
8
+ # The events are pulled out directly from the database.
9
+ # The original events are not deleted, and on every consecutive run only new
10
+ # events are pulled.
11
+ #
12
+ # The last watchdog event id that was processed is stored in the Drupal
13
+ # variable table with the name "logstash_last_wid". Delete this variable or
14
+ # set it to 0 if you want to re-import all events.
15
+ #
16
+ # More info on DBLog: http://drupal.org/documentation/modules/dblog
17
+ #
18
+ class LogStash::Inputs::DrupalDblog < LogStash::Inputs::Base
19
+ config_name "drupal_dblog"
20
+ milestone 1
21
+
22
+ default :codec, "plain"
23
+
24
+ # Specify all drupal databases that you whish to import from.
25
+ # This can be as many as you whish.
26
+ # The format is a hash, with a unique site name as the key, and a databse
27
+ # url as the value.
28
+ #
29
+ # Example:
30
+ # [
31
+ # "site1", "mysql://user1:password@host1.com/databasename",
32
+ # "other_site", "mysql://user2:password@otherhost.com/databasename",
33
+ # ...
34
+ # ]
35
+ config :databases, :validate => :hash
36
+
37
+ # By default, the event only contains the current user id as a field.
38
+ # If you whish to add the username as an additional field, set this to true.
39
+ config :add_usernames, :validate => :boolean, :default => false
40
+
41
+ # Time between checks in minutes.
42
+ config :interval, :validate => :number, :default => 10
43
+
44
+ # The amount of log messages that should be fetched with each query.
45
+ # Bulk fetching is done to prevent querying huge data sets when lots of
46
+ # messages are in the database.
47
+ config :bulksize, :validate => :number, :default => 5000
48
+
49
+ # Label this input with a type.
50
+ # Types are used mainly for filter activation.
51
+ #
52
+ #
53
+ # If you create an input with type "foobar", then only filters
54
+ # which also have type "foobar" will act on them.
55
+ #
56
+ # The type is also stored as part of the event itself, so you
57
+ # can also use the type to search for in the web interface.
58
+ config :type, :validate => :string, :default => 'watchdog'
59
+
60
+ public
61
+ def register
62
+ require "php_serialize"
63
+
64
+ if RUBY_PLATFORM == 'java'
65
+ require "logstash/inputs/drupal_dblog/jdbcconnection"
66
+ else
67
+ require "mysql2"
68
+ end
69
+ end # def register
70
+
71
+ public
72
+ def config_init(params)
73
+ super
74
+
75
+ dbs = {}
76
+ valid = true
77
+
78
+ @databases.each do |name, rawUri|
79
+ uri = URI(rawUri)
80
+
81
+ dbs[name] = {
82
+ "site" => name,
83
+ "scheme" => uri.scheme,
84
+ "host" => uri.host,
85
+ "user" => uri.user,
86
+ "password" => uri.password,
87
+ "database" => uri.path.sub('/', ''),
88
+ "port" => uri.port.to_i
89
+ }
90
+
91
+ if not (
92
+ uri.scheme and not uri.scheme.empty?\
93
+ and uri.host and not uri.host.empty?\
94
+ and uri.user and not uri.user.empty?\
95
+ and uri.password\
96
+ and uri.path and not uri.path.sub('/', '').empty?
97
+ )
98
+ @logger.error("Drupal DBLog: Invalid database URI for #{name} : #{rawUri}")
99
+ valid = false
100
+ end
101
+ if not uri.scheme == 'mysql'
102
+ @logger.error("Drupal DBLog: Only mysql databases are supported.")
103
+ valid = false
104
+ end
105
+ end
106
+
107
+ if not valid
108
+ @logger.error("Config validation failed.")
109
+ exit 1
110
+ end
111
+
112
+ @databases = dbs
113
+ end #def config_init
114
+
115
+ public
116
+ def run(output_queue)
117
+ @logger.info("Initializing drupal_dblog")
118
+
119
+ loop do
120
+ @logger.debug("Drupal DBLog: Starting to fetch new watchdog entries")
121
+ start = Time.now.to_i
122
+
123
+ @databases.each do |name, db|
124
+ @logger.debug("Drupal DBLog: Checking database #{name}")
125
+ check_database(output_queue, db)
126
+ @logger.info("Drupal DBLog: Retrieved all new watchdog messages from #{name}")
127
+ end
128
+
129
+ timeTaken = Time.now.to_i - start
130
+ @logger.info("Drupal DBLog: Fetched all new watchdog entries in #{timeTaken} seconds")
131
+
132
+ # If fetching of all databases took less time than the interval,
133
+ # sleep a bit.
134
+ sleepTime = @interval * 60 - timeTaken
135
+ if sleepTime > 0
136
+ @logger.debug("Drupal DBLog: Sleeping for #{sleepTime} seconds")
137
+ sleep(sleepTime)
138
+ end
139
+ end # loop
140
+ end # def run
141
+
142
+ private
143
+ def initialize_client(db)
144
+ if db["scheme"] == 'mysql'
145
+
146
+ if not db["port"] > 0
147
+ db["port"] = 3306
148
+ end
149
+
150
+ if RUBY_PLATFORM == 'java'
151
+ @client = LogStash::DrupalDblogJavaMysqlConnection.new(
152
+ db["host"],
153
+ db["user"],
154
+ db["password"],
155
+ db["database"],
156
+ db["port"]
157
+ )
158
+ else
159
+ @client = Mysql2::Client.new(
160
+ :host => db["host"],
161
+ :port => db["port"],
162
+ :username => db["user"],
163
+ :password => db["password"],
164
+ :database => db["database"]
165
+ )
166
+ end
167
+ end
168
+ end #def get_client
169
+
170
+ private
171
+ def check_database(output_queue, db)
172
+
173
+ begin
174
+ # connect to the MySQL server
175
+ initialize_client(db)
176
+ rescue Exception => e
177
+ @logger.error("Could not connect to database: " + e.message)
178
+ return
179
+ end #begin
180
+
181
+ begin
182
+ @sitename = db["site"]
183
+
184
+ @usermap = @add_usernames ? get_usermap : nil
185
+
186
+ # Retrieve last pulled watchdog entry id
187
+ initialLastWid = get_last_wid
188
+ lastWid = nil
189
+
190
+
191
+ if initialLastWid == false
192
+ lastWid = 0
193
+ set_last_wid(0, true)
194
+ else
195
+ lastWid = initialLastWid
196
+ end
197
+
198
+ # Fetch new entries, and create the event
199
+ while true
200
+ results = get_db_rows(lastWid)
201
+ if results.length() < 1
202
+ break
203
+ end
204
+
205
+ @logger.debug("Fetched " + results.length().to_s + " database rows")
206
+
207
+ results.each do |row|
208
+ event = build_event(row)
209
+ if event
210
+ decorate(event)
211
+ output_queue << event
212
+ lastWid = row['wid'].to_s
213
+ end
214
+ end
215
+
216
+ set_last_wid(lastWid, false)
217
+ end
218
+ rescue Exception => e
219
+ @logger.error("Error while fetching messages: ", :error => e.message)
220
+ end # begin
221
+
222
+ # Close connection
223
+ @client.close
224
+ end # def check_database
225
+
226
+ def get_db_rows(lastWid)
227
+ query = 'SELECT * from watchdog WHERE wid > ' + lastWid.to_s + " ORDER BY wid asc LIMIT " + @bulksize.to_s
228
+ return @client.query(query)
229
+ end # def get_db_rows
230
+
231
+ private
232
+ def update_sitename
233
+ if @sitename == ""
234
+ result = @client.query('SELECT value FROM variable WHERE name="site_name"')
235
+ if result.first()
236
+ @sitename = PHP.unserialize(result.first()['value'])
237
+ end
238
+ end
239
+ end # def update_sitename
240
+
241
+ private
242
+ def get_last_wid
243
+ result = @client.query('SELECT value FROM variable WHERE name="logstash_last_wid"')
244
+ lastWid = false
245
+
246
+ if result.count() > 0
247
+ tmp = result.first()["value"].gsub("i:", "").gsub(";", "")
248
+ lastWid = tmp.to_i.to_s == tmp ? tmp : "0"
249
+ end
250
+
251
+ return lastWid
252
+ end # def get_last_wid
253
+
254
+ private
255
+ def set_last_wid(wid, insert)
256
+ wid = PHP.serialize(wid.to_i)
257
+
258
+ # Update last import wid variable
259
+ if insert
260
+ # Does not exist yet, so insert
261
+ @client.query('INSERT INTO variable (name, value) VALUES("logstash_last_wid", "' + wid + '")')
262
+ else
263
+ @client.query('UPDATE variable SET value="' + wid + '" WHERE name="logstash_last_wid"')
264
+ end
265
+ end # def set_last_wid
266
+
267
+ private
268
+ def get_usermap
269
+ map = {}
270
+
271
+ @client.query("SELECT uid, name FROM users").each do |row|
272
+ map[row["uid"]] = row["name"]
273
+ end
274
+
275
+ map[0] = "guest"
276
+ return map
277
+ end # def get_usermap
278
+
279
+ private
280
+ def build_event(row)
281
+ # Convert unix timestamp
282
+ timestamp = Time.at(row["timestamp"])
283
+
284
+ msg = row["message"]
285
+ vars = {}
286
+
287
+ # Unserialize the variables, and construct the message
288
+ if row['variables'] != 'N;'
289
+ vars = PHP.unserialize(row["variables"])
290
+
291
+ if vars.is_a?(Hash)
292
+ vars.each_pair do |k, v|
293
+ if msg.scan(k).length() > 0
294
+ msg = msg.gsub(k.to_s, v.to_s)
295
+ else
296
+ # If not inside the message, add var as an additional field
297
+ row["variable_" + k] = v
298
+ end
299
+ end
300
+ end
301
+ end
302
+
303
+ row.delete("message")
304
+ row.delete("variables")
305
+ row.delete("timestamp")
306
+
307
+ row["severity"] = row["severity"].to_i
308
+
309
+ if @add_usernames and @usermap.has_key?(row["uid"])
310
+ row["user"] = @usermap[row["uid"]]
311
+ end
312
+
313
+ entry = {
314
+ "@timestamp" => timestamp,
315
+ "tags" => [],
316
+ "type" => "watchdog",
317
+ "site" => @sitename,
318
+ "message" => msg
319
+ }.merge(row)
320
+
321
+ return LogStash::Event.new(entry)
322
+ end # def build_event
323
+
324
+ end # class LogStash::Inputs::DrupalDblog
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+ require "java"
3
+ require "rubygems"
4
+ require "jdbc/mysql"
5
+
6
+ java_import "com.mysql.jdbc.Driver"
7
+
8
+ # A JDBC mysql connection class.
9
+ # The interface is compatible with the mysql2 API.
10
+ class LogStash::DrupalDblogJavaMysqlConnection
11
+
12
+ def initialize(host, username, password, database, port = nil)
13
+ port ||= 3306
14
+
15
+ address = "jdbc:mysql://#{host}:#{port}/#{database}"
16
+ @connection = java.sql.DriverManager.getConnection(address, username, password)
17
+ end # def initialize
18
+
19
+ def query(sql)
20
+ if sql =~ /select/i
21
+ return select(sql)
22
+ else
23
+ return update(sql)
24
+ end
25
+ end # def query
26
+
27
+ def select(sql)
28
+ stmt = @connection.createStatement
29
+ resultSet = stmt.executeQuery(sql)
30
+
31
+ meta = resultSet.getMetaData
32
+ column_count = meta.getColumnCount
33
+
34
+ rows = []
35
+
36
+ while resultSet.next
37
+ res = {}
38
+
39
+ (1..column_count).each do |i|
40
+ name = meta.getColumnName(i)
41
+ case meta.getColumnType(i)
42
+ when java.sql.Types::INTEGER
43
+ res[name] = resultSet.getInt(name)
44
+ else
45
+ res[name] = resultSet.getString(name)
46
+ end
47
+ end
48
+
49
+ rows << res
50
+ end
51
+
52
+ stmt.close
53
+ return rows
54
+ end # def select
55
+
56
+ def update(sql)
57
+ stmt = @connection.createStatement
58
+ stmt.execute_update(sql)
59
+ stmt.close
60
+ end # def update
61
+
62
+ def close
63
+ @connection.close
64
+ end # def close
65
+
66
+ end # class LogStash::DrupalDblogJavaMysqlConnection
@@ -0,0 +1,41 @@
1
+ Gem::Specification.new do |s|
2
+
3
+ s.name = 'logstash-input-drupal_dblog'
4
+ s.version = '0.1.1'
5
+ s.licenses = ['Apache License (2.0)']
6
+ s.summary = "Retrieve watchdog log events from a Drupal installation with DBLog enabled"
7
+ 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"
8
+ s.authors = ["Elasticsearch"]
9
+ s.email = 'info@elasticsearch.com'
10
+ s.homepage = "http://www.elasticsearch.org/guide/en/logstash/current/index.html"
11
+ s.require_paths = ["lib"]
12
+
13
+ # Files
14
+ s.files = `git ls-files`.split($\)+::Dir.glob('vendor/*')
15
+
16
+ # Tests
17
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
18
+
19
+ # Special flag to let us know this is actually a logstash plugin
20
+ s.metadata = { "logstash_plugin" => "true", "logstash_group" => "input" }
21
+
22
+ # Jar dependencies
23
+ s.requirements << "jar 'mysql:mysql-connector-java', '5.1.33'"
24
+
25
+ # Gem dependencies
26
+ s.add_runtime_dependency 'logstash', '>= 1.4.0', '< 2.0.0'
27
+ s.add_runtime_dependency 'jar-dependencies'
28
+
29
+ s.add_runtime_dependency 'logstash-codec-plain'
30
+ s.add_runtime_dependency 'php_serialize'
31
+
32
+ if RUBY_PLATFORM == 'java'
33
+ s.platform = RUBY_PLATFORM
34
+ s.add_runtime_dependency 'jdbc-mysql'
35
+ else
36
+ s.add_runtime_dependency 'mysql2'
37
+ end
38
+
39
+ s.add_development_dependency 'logstash-devutils'
40
+ end
41
+
@@ -0,0 +1 @@
1
+ require "logstash/devutils/rspec/spec_helper"
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: logstash-input-drupal_dblog
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: java
6
+ authors:
7
+ - Elasticsearch
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: logstash
15
+ version_requirements: !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
+ requirement: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '>='
26
+ - !ruby/object:Gem::Version
27
+ version: 1.4.0
28
+ - - <
29
+ - !ruby/object:Gem::Version
30
+ version: 2.0.0
31
+ prerelease: false
32
+ type: :runtime
33
+ - !ruby/object:Gem::Dependency
34
+ name: jar-dependencies
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ requirement: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ prerelease: false
46
+ type: :runtime
47
+ - !ruby/object:Gem::Dependency
48
+ name: logstash-codec-plain
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirement: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ prerelease: false
60
+ type: :runtime
61
+ - !ruby/object:Gem::Dependency
62
+ name: php_serialize
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirement: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ prerelease: false
74
+ type: :runtime
75
+ - !ruby/object:Gem::Dependency
76
+ name: jdbc-mysql
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirement: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ prerelease: false
88
+ type: :runtime
89
+ - !ruby/object:Gem::Dependency
90
+ name: logstash-devutils
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirement: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ prerelease: false
102
+ type: :development
103
+ 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
104
+ email: info@elasticsearch.com
105
+ executables: []
106
+ extensions: []
107
+ extra_rdoc_files: []
108
+ files:
109
+ - .gitignore
110
+ - Gemfile
111
+ - LICENSE
112
+ - Rakefile
113
+ - lib/logstash/inputs/drupal_dblog.rb
114
+ - lib/logstash/inputs/drupal_dblog/jdbcconnection.rb
115
+ - logstash-input-drupal_dblog.gemspec
116
+ - spec/inputs/drupal_dblog_spec.rb
117
+ homepage: http://www.elasticsearch.org/guide/en/logstash/current/index.html
118
+ licenses:
119
+ - Apache License (2.0)
120
+ metadata:
121
+ logstash_plugin: 'true'
122
+ logstash_group: input
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - '>='
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements:
138
+ - jar 'mysql:mysql-connector-java', '5.1.33'
139
+ rubyforge_project:
140
+ rubygems_version: 2.2.2
141
+ signing_key:
142
+ specification_version: 4
143
+ summary: Retrieve watchdog log events from a Drupal installation with DBLog enabled
144
+ test_files:
145
+ - spec/inputs/drupal_dblog_spec.rb