sensu-plugins-mongodb 1.0.0 → 1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -2
- data/README.md +3 -1
- data/bin/check-mongodb-metric.rb +143 -0
- data/bin/check-mongodb.py +10 -4
- data/bin/metrics-mongodb-replication.rb +261 -0
- data/bin/metrics-mongodb.rb +44 -112
- data/lib/sensu-plugins-mongodb/metics.rb +340 -0
- data/lib/sensu-plugins-mongodb/version.rb +1 -1
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fb4941553a69ae6bcca4130d5b4b0f70f275fbcc
|
4
|
+
data.tar.gz: 78c8ea6169c2d1276add39c49fd61bcf524f1c3f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 831b34ee26b5e760745c3239a9e2ddcf2ff5141f0c95aecc4e6d1b797da08b05ad6b0631a69295433f4c6c3194df84e8f4ef503b22b2f078150350793737d02f
|
7
|
+
data.tar.gz: d6ca2cdba45c44e292f39cff53cb1bdb8de6bb063acf76ed7b5a6b80f0b04f85a95e0764327d0dd4e0553330363584d8001b5c766e3c61415616e91d35f804a4
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,22 @@ This CHANGELOG follows the format listed at [Keep A Changelog](http://keepachang
|
|
5
5
|
|
6
6
|
## [Unreleased]
|
7
7
|
|
8
|
+
## [1.1.0] - 2016-10-17
|
9
|
+
### Added
|
10
|
+
- Inclusion of check-mongodb-metrics.rb to perform checks against the same data metrics-mongodb.rb produces. (@stefano-pogliani)
|
11
|
+
- Inclusion of lib/sensu-plugins-mongodb/metics.rb to share metric collection logic. (@stefano-pogliani)
|
12
|
+
- Tests to the metrics processing shared code. (@stefano-pogliani)
|
13
|
+
- Support for SSL certificates for clients. (@b0d0nne11)
|
14
|
+
- Inclusion of metrics-mongodb-replication.rb to produce replication metrics including lag statistics (@stefano-pogliani)
|
15
|
+
- Updated metrics-mongodb.rb to include version checks to ensure execution in mongodb > 3.2.x (@RycroftSolutions)
|
16
|
+
- Additional metrics not included in original metrics-mongodb.rb (@RycroftSolutions)
|
17
|
+
|
18
|
+
### Changed
|
19
|
+
- Moved most of metrics-mongodb.rb code to shared library. (@stefano-pogliani)
|
20
|
+
- MongoDB version checks to skip missing metrics. (@stefano-pogliani)
|
21
|
+
- Renamed some metrics to become standard with MongoDB 3.2 equivalent
|
22
|
+
(so checks/queries don't have to bother with version detection). (@stefano-pogliani)
|
23
|
+
|
8
24
|
## [1.0.0] - 2016-06-03
|
9
25
|
### Removed
|
10
26
|
- support for Rubies 1.9.3 and 2.0
|
@@ -14,7 +30,7 @@ This CHANGELOG follows the format listed at [Keep A Changelog](http://keepachang
|
|
14
30
|
|
15
31
|
### Changed
|
16
32
|
- Update to rubocop 0.40 and cleanup
|
17
|
-
- Update to mongo gem 2.2.x and
|
33
|
+
- Update to mongo gem 2.2.x and bson 4.x for MongoDB 3.2 support
|
18
34
|
|
19
35
|
### Fixed
|
20
36
|
- Long was added as a numeric type
|
@@ -64,7 +80,8 @@ This CHANGELOG follows the format listed at [Keep A Changelog](http://keepachang
|
|
64
80
|
### Added
|
65
81
|
- initial release
|
66
82
|
|
67
|
-
[Unreleased]: https://github.com/sensu-plugins/sensu-plugins-mongodb/compare/1.
|
83
|
+
[Unreleased]: https://github.com/sensu-plugins/sensu-plugins-mongodb/compare/1.1.0...HEAD
|
84
|
+
[1.1.0]: https://github.com/sensu-plugins/sensu-plugins-mongodb/compare/1.0.0...1.1.0
|
68
85
|
[1.0.0]: https://github.com/sensu-plugins/sensu-plugins-mongodb/compare/0.0.8...1.0.0
|
69
86
|
[0.0.8]: https://github.com/sensu-plugins/sensu-plugins-mongodb/compare/0.0.7...0.0.8
|
70
87
|
[0.0.7]: https://github.com/sensu-plugins/sensu-plugins-mongodb/compare/0.0.6...0.0.7
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
## Sensu-Plugins-mongodb
|
2
2
|
|
3
|
-
[
|
3
|
+
[](https://travis-ci.org/sensu-plugins/sensu-plugins-mongodb)
|
4
4
|
[](http://badge.fury.io/rb/sensu-plugins-mongodb)
|
5
5
|
[](https://codeclimate.com/github/sensu-plugins/sensu-plugins-mongodb)
|
6
6
|
[](https://codeclimate.com/github/sensu-plugins/sensu-plugins-mongodb)
|
@@ -11,7 +11,9 @@
|
|
11
11
|
## Files
|
12
12
|
* bin/check-mongodb.py
|
13
13
|
* bin/check-mongodb.rb - wrapper for check-mongodb.py
|
14
|
+
* bin/check-mongodb-metric.rb
|
14
15
|
* bin/metrics-mongodb.rb
|
16
|
+
* bin/metrics-mongodb-replication.rb
|
15
17
|
|
16
18
|
## Usage
|
17
19
|
|
@@ -0,0 +1,143 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# check-mongodb-metric.rb
|
4
|
+
#
|
5
|
+
# DESCRIPTION:
|
6
|
+
#
|
7
|
+
# OUTPUT:
|
8
|
+
# plain text
|
9
|
+
#
|
10
|
+
# PLATFORMS:
|
11
|
+
# Linux
|
12
|
+
#
|
13
|
+
# DEPENDENCIES:
|
14
|
+
# gem: sensu-plugin
|
15
|
+
# gem: mongo
|
16
|
+
# gem: bson
|
17
|
+
# gem: bson_ext
|
18
|
+
#
|
19
|
+
# USAGE:
|
20
|
+
# #YELLOW
|
21
|
+
#
|
22
|
+
# NOTES:
|
23
|
+
#
|
24
|
+
# LICENSE:
|
25
|
+
# Copyright 2016 Conversocial https://github.com/conversocial
|
26
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
27
|
+
# for details.
|
28
|
+
#
|
29
|
+
|
30
|
+
require 'sensu-plugin/check/cli'
|
31
|
+
require 'sensu-plugins-mongodb/metics'
|
32
|
+
require 'mongo'
|
33
|
+
include Mongo
|
34
|
+
|
35
|
+
#
|
36
|
+
# Mongodb
|
37
|
+
#
|
38
|
+
|
39
|
+
class CheckMongodbMetric < Sensu::Plugin::Check::CLI
|
40
|
+
option :host,
|
41
|
+
description: 'MongoDB host',
|
42
|
+
long: '--host HOST',
|
43
|
+
default: 'localhost'
|
44
|
+
|
45
|
+
option :port,
|
46
|
+
description: 'MongoDB port',
|
47
|
+
long: '--port PORT',
|
48
|
+
default: 27_017
|
49
|
+
|
50
|
+
option :user,
|
51
|
+
description: 'MongoDB user',
|
52
|
+
long: '--user USER',
|
53
|
+
default: nil
|
54
|
+
|
55
|
+
option :password,
|
56
|
+
description: 'MongoDB password',
|
57
|
+
long: '--password PASSWORD',
|
58
|
+
default: nil
|
59
|
+
|
60
|
+
option :ssl,
|
61
|
+
description: 'Connect using SSL',
|
62
|
+
long: '--ssl',
|
63
|
+
default: false
|
64
|
+
|
65
|
+
option :ssl_cert,
|
66
|
+
description: 'The certificate file used to identify the local connection against mongod',
|
67
|
+
long: '--ssl-cert SSL_CERT',
|
68
|
+
default: ''
|
69
|
+
|
70
|
+
option :ssl_key,
|
71
|
+
description: 'The private key used to identify the local connection against mongod',
|
72
|
+
long: '--ssl-key SSL_KEY',
|
73
|
+
default: ''
|
74
|
+
|
75
|
+
option :ssl_ca_cert,
|
76
|
+
description: 'The set of concatenated CA certificates, which are used to validate certificates passed from the other end of the connection',
|
77
|
+
long: '--ssl-ca-cert SSL_CA_CERT',
|
78
|
+
default: ''
|
79
|
+
|
80
|
+
option :ssl_verify,
|
81
|
+
description: 'Whether or not to do peer certification validation',
|
82
|
+
long: '--ssl-verify',
|
83
|
+
default: false
|
84
|
+
|
85
|
+
option :debug,
|
86
|
+
description: 'Enable debug',
|
87
|
+
long: '--debug',
|
88
|
+
default: false
|
89
|
+
|
90
|
+
option :require_master,
|
91
|
+
description: 'Require the node to be a master node',
|
92
|
+
long: '--require-master',
|
93
|
+
default: false
|
94
|
+
|
95
|
+
option :metric,
|
96
|
+
description: 'Name of the metric to check',
|
97
|
+
long: '--metric METRIC',
|
98
|
+
short: '-m METRIC'
|
99
|
+
|
100
|
+
option :warn,
|
101
|
+
description: 'Warn if values are above this threshold',
|
102
|
+
short: '-w WARN',
|
103
|
+
proc: proc(&:to_i),
|
104
|
+
default: 0
|
105
|
+
|
106
|
+
option :crit,
|
107
|
+
description: 'Fail if values are above this threshold',
|
108
|
+
short: '-c CRIT',
|
109
|
+
proc: proc(&:to_i),
|
110
|
+
default: 0
|
111
|
+
|
112
|
+
def run
|
113
|
+
Mongo::Logger.logger.level = Logger::FATAL
|
114
|
+
@debug = config[:debug]
|
115
|
+
if @debug
|
116
|
+
Mongo::Logger.logger.level = Logger::DEBUG
|
117
|
+
config_debug = config.clone
|
118
|
+
config_debug[:password] = '***'
|
119
|
+
puts 'Arguments: ' + config_debug.inspect
|
120
|
+
end
|
121
|
+
|
122
|
+
# Get the metrics.
|
123
|
+
collector = SensuPluginsMongoDB::Metrics.new(config)
|
124
|
+
collector.connect_mongo_db('admin')
|
125
|
+
exit(1) if config[:require_master] && !collector.master?
|
126
|
+
metrics = collector.server_metrics
|
127
|
+
|
128
|
+
# Make sure the requested value is available.
|
129
|
+
unless metrics.key?(config[:metric])
|
130
|
+
unknown "Unable to find a value for metric '#{config[:metric]}'"
|
131
|
+
end
|
132
|
+
|
133
|
+
# Check the requested value against the thresholds.
|
134
|
+
value = metrics[config[:metric]]
|
135
|
+
if value >= config[:crit]
|
136
|
+
critical "The value of '#{config[:metric]}' exceeds #{config[:crit]}."
|
137
|
+
end
|
138
|
+
if value >= config[:warn]
|
139
|
+
warning "The value of '#{config[:metric]}' exceeds #{config[:warn]}."
|
140
|
+
end
|
141
|
+
ok "The value of '#{config[:metric]}' is below all threshold."
|
142
|
+
end
|
143
|
+
end
|
data/bin/check-mongodb.py
CHANGED
@@ -153,6 +153,9 @@ def main(argv):
|
|
153
153
|
p.add_option('-d', '--database', action='store', dest='database', default='admin', help='Specify the database to check')
|
154
154
|
p.add_option('--all-databases', action='store_true', dest='all_databases', default=False, help='Check all databases (action database_size)')
|
155
155
|
p.add_option('-s', '--ssl-enabled', dest='ssl_enabled', default=False, action='callback', callback=optional_arg(True), help='Connect using SSL')
|
156
|
+
p.add_option('-e', '--ssl-certfile', dest='ssl_certfile', default=None, action='store', help='The certificate file used to identify the local connection against mongod')
|
157
|
+
p.add_option('-k', '--ssl-keyfile', dest='ssl_keyfile', default=None, action='store', help='The private key used to identify the local connection against mongod')
|
158
|
+
p.add_option('-a', '--ssl-ca-certs', dest='ssl_ca_certs', default=None, action='store', help='The set of concatenated CA certificates, which are used to validate certificates passed from the other end of the connection')
|
156
159
|
p.add_option('-r', '--replicaset', dest='replicaset', default=None, action='callback', callback=optional_arg(True), help='Connect to replicaset')
|
157
160
|
p.add_option('-q', '--querytype', action='store', dest='query_type', default='query', help='The query type to check [query|insert|update|delete|getmore|command] from queries_per_second')
|
158
161
|
p.add_option('-c', '--collection', action='store', dest='collection', default='admin', help='Specify the collection to check')
|
@@ -178,6 +181,9 @@ def main(argv):
|
|
178
181
|
max_lag = options.max_lag
|
179
182
|
database = options.database
|
180
183
|
ssl_enabled = options.ssl_enabled
|
184
|
+
ssl_certfile = options.ssl_certfile
|
185
|
+
ssl_keyfile = options.ssl_keyfile
|
186
|
+
ssl_ca_certs = options.ssl_ca_certs
|
181
187
|
replicaset = options.replicaset
|
182
188
|
|
183
189
|
if action == 'replica_primary' and replicaset is None:
|
@@ -189,7 +195,7 @@ def main(argv):
|
|
189
195
|
# moving the login up here and passing in the connection
|
190
196
|
#
|
191
197
|
start = time.time()
|
192
|
-
err, con = mongo_connect(host, port, ssl_enabled, user, passwd, replicaset)
|
198
|
+
err, con = mongo_connect(host, port, ssl_enabled, ssl_certfile, ssl_keyfile, ssl_ca_certs, user, passwd, replicaset)
|
193
199
|
if err != 0:
|
194
200
|
return err
|
195
201
|
|
@@ -267,14 +273,14 @@ def main(argv):
|
|
267
273
|
return check_connect(host, port, warning, critical, perf_data, user, passwd, conn_time)
|
268
274
|
|
269
275
|
|
270
|
-
def mongo_connect(host=None, port=None, ssl_enabled=False, user=None, passwd=None, replica=None):
|
276
|
+
def mongo_connect(host=None, port=None, ssl_enabled=False, ssl_certfile=None, ssl_keyfile=None, ssl_ca_certs=None, user=None, passwd=None, replica=None):
|
271
277
|
try:
|
272
278
|
# ssl connection for pymongo > 2.3
|
273
279
|
if pymongo.version >= "2.3":
|
274
280
|
if replica is None:
|
275
|
-
con = pymongo.MongoClient(host, port, ssl=ssl_enabled)
|
281
|
+
con = pymongo.MongoClient(host, port, ssl=ssl_enabled, ssl_certfile=ssl_certfile, ssl_keyfile=ssl_keyfile, ssl_ca_certs=ssl_ca_certs)
|
276
282
|
else:
|
277
|
-
con = pymongo.Connection(host, port, read_preference=pymongo.ReadPreference.SECONDARY, ssl=ssl_enabled, replicaSet=replica, network_timeout=10)
|
283
|
+
con = pymongo.Connection(host, port, read_preference=pymongo.ReadPreference.SECONDARY, ssl=ssl_enabled, ssl_certfile=ssl_certfile, ssl_keyfile=ssl_keyfile, ssl_ca_certs=ssl_ca_certs, replicaSet=replica, network_timeout=10)
|
278
284
|
else:
|
279
285
|
if replica is None:
|
280
286
|
con = pymongo.Connection(host, port, slave_okay=True, network_timeout=10)
|
@@ -0,0 +1,261 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# metrics-mongodb-replication.rb
|
4
|
+
#
|
5
|
+
# DESCRIPTION:
|
6
|
+
#
|
7
|
+
# OUTPUT:
|
8
|
+
# metric data
|
9
|
+
#
|
10
|
+
# PLATFORMS:
|
11
|
+
# Linux
|
12
|
+
#
|
13
|
+
# DEPENDENCIES:
|
14
|
+
# gem: sensu-plugin
|
15
|
+
# gem: mongo
|
16
|
+
# gem: bson
|
17
|
+
# gem: bson_ext
|
18
|
+
#
|
19
|
+
# USAGE:
|
20
|
+
# #YELLOW
|
21
|
+
#
|
22
|
+
# NOTES::
|
23
|
+
# Basics from github.com/sensu-plugins/sensu-plugins-mongodb/bin/metrics-mongodb
|
24
|
+
#
|
25
|
+
# Replication lag is calculated by obtaining the last optime from primary and
|
26
|
+
# secondary members. The last optime of the secondary is subtracted from the
|
27
|
+
# last optime of the primary to produce the difference in seconds, minutes and hours
|
28
|
+
#
|
29
|
+
# LICENSE:
|
30
|
+
# Copyright 2016 Rycroft Solutions
|
31
|
+
# Released under the same terms as Sensu (the MIT license); see LICENSE
|
32
|
+
# for details.
|
33
|
+
#
|
34
|
+
|
35
|
+
require 'sensu-plugin/metric/cli'
|
36
|
+
require 'mongo'
|
37
|
+
require 'date'
|
38
|
+
include Mongo
|
39
|
+
|
40
|
+
#
|
41
|
+
# Mongodb
|
42
|
+
#
|
43
|
+
|
44
|
+
class MongoDB < Sensu::Plugin::Metric::CLI::Graphite
|
45
|
+
option :host,
|
46
|
+
description: 'MongoDB host',
|
47
|
+
long: '--host HOST',
|
48
|
+
default: 'localhost'
|
49
|
+
|
50
|
+
option :port,
|
51
|
+
description: 'MongoDB port',
|
52
|
+
long: '--port PORT',
|
53
|
+
default: 27_017
|
54
|
+
|
55
|
+
option :user,
|
56
|
+
description: 'MongoDB user',
|
57
|
+
long: '--user USER',
|
58
|
+
default: nil
|
59
|
+
|
60
|
+
option :password,
|
61
|
+
description: 'MongoDB password',
|
62
|
+
long: '--password PASSWORD',
|
63
|
+
default: nil
|
64
|
+
|
65
|
+
option :ssl,
|
66
|
+
description: 'Connect using SSL',
|
67
|
+
long: '--ssl',
|
68
|
+
default: false
|
69
|
+
|
70
|
+
option :ssl_cert,
|
71
|
+
description: 'The certificate file used to identify the local connection against mongod',
|
72
|
+
long: '--ssl-cert SSL_CERT',
|
73
|
+
default: ''
|
74
|
+
|
75
|
+
option :ssl_key,
|
76
|
+
description: 'The private key used to identify the local connection against mongod',
|
77
|
+
long: '--ssl-key SSL_KEY',
|
78
|
+
default: ''
|
79
|
+
|
80
|
+
option :ssl_ca_cert,
|
81
|
+
description: 'The set of concatenated CA certificates, which are used to validate certificates passed from the other end of the connection',
|
82
|
+
long: '--ssl-ca-cert SSL_CA_CERT',
|
83
|
+
default: ''
|
84
|
+
|
85
|
+
option :ssl_verify,
|
86
|
+
description: 'Whether or not to do peer certification validation',
|
87
|
+
long: '--ssl-verify',
|
88
|
+
default: false
|
89
|
+
|
90
|
+
option :scheme,
|
91
|
+
description: 'Metric naming scheme',
|
92
|
+
long: '--scheme SCHEME',
|
93
|
+
short: '-s SCHEME',
|
94
|
+
default: "#{Socket.gethostname}.mongodb"
|
95
|
+
|
96
|
+
option :password,
|
97
|
+
description: 'MongoDB password',
|
98
|
+
long: '--password PASSWORD',
|
99
|
+
default: nil
|
100
|
+
|
101
|
+
option :debug,
|
102
|
+
description: 'Enable debug',
|
103
|
+
long: '--debug',
|
104
|
+
default: false
|
105
|
+
|
106
|
+
def get_mongo_doc(command)
|
107
|
+
rs = @db.command(command)
|
108
|
+
unless rs.successful?
|
109
|
+
return nil
|
110
|
+
end
|
111
|
+
rs.documents[0]
|
112
|
+
end
|
113
|
+
|
114
|
+
# connects to mongo and sets @db, works with MongoClient < 2.0.0
|
115
|
+
def connect_mongo_db
|
116
|
+
if Gem.loaded_specs['mongo'].version < Gem::Version.new('2.0.0')
|
117
|
+
mongo_client = MongoClient.new(host, port)
|
118
|
+
@db = mongo_client.db(db_name)
|
119
|
+
@db.authenticate(db_user, db_password) unless db_user.nil?
|
120
|
+
else
|
121
|
+
address_str = "#{config[:host]}:#{config[:port]}"
|
122
|
+
client_opts = {}
|
123
|
+
client_opts[:database] = 'admin'
|
124
|
+
unless config[:user].nil?
|
125
|
+
client_opts[:user] = config[:user]
|
126
|
+
client_opts[:password] = config[:password]
|
127
|
+
end
|
128
|
+
if config[:ssl]
|
129
|
+
client_opts[:ssl] = true
|
130
|
+
client_opts[:ssl_cert] = config[:ssl_cert]
|
131
|
+
client_opts[:ssl_key] = config[:ssl_key]
|
132
|
+
client_opts[:ssl_ca_cert] = config[:ssl_ca_cert]
|
133
|
+
client_opts[:ssl_verify] = config[:ssl_verify]
|
134
|
+
end
|
135
|
+
mongo_client = Mongo::Client.new([address_str], client_opts)
|
136
|
+
@db = mongo_client.database
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def run
|
141
|
+
Mongo::Logger.logger.level = Logger::FATAL
|
142
|
+
@debug = config[:debug]
|
143
|
+
if @debug
|
144
|
+
Mongo::Logger.logger.level = Logger::DEBUG
|
145
|
+
config_debug = config.clone
|
146
|
+
config_debug[:password] = '***'
|
147
|
+
puts 'arguments:' + config_debug.inspect
|
148
|
+
end
|
149
|
+
|
150
|
+
connect_mongo_db
|
151
|
+
|
152
|
+
_result = false
|
153
|
+
# check if master
|
154
|
+
begin
|
155
|
+
@is_master = get_mongo_doc('isMaster' => 1)
|
156
|
+
unless @is_master.nil?
|
157
|
+
_result = @is_master['ok'] == 1
|
158
|
+
end
|
159
|
+
rescue StandardError => e
|
160
|
+
if @debug
|
161
|
+
puts 'Error checking isMaster:' + e.message
|
162
|
+
puts e.backtrace.inspect
|
163
|
+
end
|
164
|
+
exit(1)
|
165
|
+
end
|
166
|
+
|
167
|
+
replication_status = get_mongo_doc('replSetGetStatus' => 1)
|
168
|
+
|
169
|
+
# get the replication metrics
|
170
|
+
begin
|
171
|
+
metrics = {}
|
172
|
+
if !replication_status.nil? && replication_status['ok'] == 1
|
173
|
+
metrics.update(gather_replication_metrics(replication_status))
|
174
|
+
timestamp = Time.now.to_i
|
175
|
+
metrics.each do |k, v|
|
176
|
+
unless v.nil?
|
177
|
+
output [config[:scheme], 'replication', k].join('.'), v, timestamp
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
rescue StandardError => e
|
182
|
+
if @debug
|
183
|
+
puts 'Error checking replicationStatus:' + e.message
|
184
|
+
puts e.backtrace.inspect
|
185
|
+
end
|
186
|
+
exit(2)
|
187
|
+
end
|
188
|
+
|
189
|
+
# Get the repllication member metrics
|
190
|
+
begin
|
191
|
+
metrics = {}
|
192
|
+
replication_members = replication_status['members']
|
193
|
+
unless replication_members.nil?
|
194
|
+
replication_members.each do |replication_member_details|
|
195
|
+
metrics.update(gather_replication_member_metrics(replication_member_details))
|
196
|
+
member_id = replication_member_details['_id']
|
197
|
+
timestamp = Time.now.to_i
|
198
|
+
metrics.each do |k, v|
|
199
|
+
unless v.nil?
|
200
|
+
output [config[:scheme], "member_#{member_id}", k].join('.'), v, timestamp
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
rescue StandardError => e
|
206
|
+
if @debug
|
207
|
+
puts 'Error checking replicationMemberStatus:' + e.message
|
208
|
+
puts e.backtrace.inspect
|
209
|
+
end
|
210
|
+
exit(2)
|
211
|
+
end
|
212
|
+
|
213
|
+
# done!
|
214
|
+
ok
|
215
|
+
end
|
216
|
+
|
217
|
+
def gather_replication_metrics(replication_status)
|
218
|
+
replication_metrics = {}
|
219
|
+
|
220
|
+
replication_metrics['replica_set'] = replication_status['set']
|
221
|
+
replication_metrics['date'] = replication_status['date']
|
222
|
+
replication_metrics['myState'] = replication_status['myState']
|
223
|
+
replication_metrics['term'] = replication_status['term']
|
224
|
+
replication_metrics['heartbeatIntervalMillis'] = replication_status['heartbeatIntervalMillis']
|
225
|
+
|
226
|
+
replication_metrics
|
227
|
+
end
|
228
|
+
|
229
|
+
def gather_replication_member_metrics(replication_member_details)
|
230
|
+
replication_member_metrics = {}
|
231
|
+
|
232
|
+
replication_member_metrics['id'] = replication_member_details['_id']
|
233
|
+
replication_member_metrics['name'] = replication_member_details['name']
|
234
|
+
replication_member_metrics['health'] = replication_member_details['health']
|
235
|
+
replication_member_metrics['state'] = replication_member_details['state']
|
236
|
+
replication_member_metrics['stateStr'] = replication_member_details['stateStr']
|
237
|
+
member_hierarchy = replication_member_details['stateStr']
|
238
|
+
if member_hierarchy == 'PRIMARY'
|
239
|
+
@primary_optime_date = replication_member_details['optimeDate']
|
240
|
+
replication_member_metrics['primary.startOptimeDate'] = @primary_optime_date
|
241
|
+
end
|
242
|
+
if member_hierarchy == 'SECONDARY'
|
243
|
+
@secondary_optime_date = replication_member_details['optimeDate']
|
244
|
+
difference_in_seconds = (@primary_optime_date - @secondary_optime_date).to_i
|
245
|
+
difference_in_minutes = ((@primary_optime_date - @secondary_optime_date) / 60).to_i
|
246
|
+
difference_in_hours = ((@primary_optime_date - @secondary_optime_date) / 3600).to_i
|
247
|
+
replication_member_metrics['secondsBehindPrimary'] = difference_in_seconds
|
248
|
+
replication_member_metrics['minutesBehindPrimary'] = difference_in_minutes
|
249
|
+
replication_member_metrics['hoursBehindPrimary'] = difference_in_hours
|
250
|
+
end
|
251
|
+
replication_member_metrics['optimeDate'] = replication_member_details['optimeDate']
|
252
|
+
replication_member_metrics['uptime'] = replication_member_details['uptime']
|
253
|
+
replication_member_metrics['lastHeartbeat'] = replication_member_details['lastHeartbeat']
|
254
|
+
replication_member_metrics['lastHeartbeatRecv'] = replication_member_details['lastHeartbeatiRecv']
|
255
|
+
replication_member_metrics['pingMs'] = replication_member_details['pingMs']
|
256
|
+
replication_member_metrics['syncingTo'] = replication_member_details['syncingTo']
|
257
|
+
replication_member_metrics['configVersion'] = replication_member_details['configVersion']
|
258
|
+
|
259
|
+
replication_member_metrics
|
260
|
+
end
|
261
|
+
end
|
data/bin/metrics-mongodb.rb
CHANGED
@@ -29,6 +29,7 @@
|
|
29
29
|
#
|
30
30
|
|
31
31
|
require 'sensu-plugin/metric/cli'
|
32
|
+
require 'sensu-plugins-mongodb/metics'
|
32
33
|
require 'mongo'
|
33
34
|
include Mongo
|
34
35
|
|
@@ -57,48 +58,46 @@ class MongoDB < Sensu::Plugin::Metric::CLI::Graphite
|
|
57
58
|
long: '--password PASSWORD',
|
58
59
|
default: nil
|
59
60
|
|
60
|
-
option :
|
61
|
-
description: '
|
62
|
-
long: '--
|
63
|
-
|
64
|
-
default: "#{Socket.gethostname}.mongodb"
|
61
|
+
option :ssl,
|
62
|
+
description: 'Connect using SSL',
|
63
|
+
long: '--ssl',
|
64
|
+
default: false
|
65
65
|
|
66
|
-
option :
|
67
|
-
description: '
|
68
|
-
long: '--
|
69
|
-
default:
|
66
|
+
option :ssl_cert,
|
67
|
+
description: 'The certificate file used to identify the local connection against mongod',
|
68
|
+
long: '--ssl-cert SSL_CERT',
|
69
|
+
default: ''
|
70
|
+
|
71
|
+
option :ssl_key,
|
72
|
+
description: 'The private key used to identify the local connection against mongod',
|
73
|
+
long: '--ssl-key SSL_KEY',
|
74
|
+
default: ''
|
75
|
+
|
76
|
+
option :ssl_ca_cert,
|
77
|
+
description: 'The set of concatenated CA certificates, which are used to validate certificates passed from the other end of the connection',
|
78
|
+
long: '--ssl-ca-cert SSL_CA_CERT',
|
79
|
+
default: ''
|
80
|
+
|
81
|
+
option :ssl_verify,
|
82
|
+
description: 'Whether or not to do peer certification validation',
|
83
|
+
long: '--ssl-verify',
|
84
|
+
default: false
|
70
85
|
|
71
86
|
option :debug,
|
72
87
|
description: 'Enable debug',
|
73
88
|
long: '--debug',
|
74
89
|
default: false
|
75
90
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
rs.documents[0]
|
82
|
-
end
|
91
|
+
option :scheme,
|
92
|
+
description: 'Metric naming scheme',
|
93
|
+
long: '--scheme SCHEME',
|
94
|
+
short: '-s SCHEME',
|
95
|
+
default: "#{Socket.gethostname}.mongodb"
|
83
96
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
@db = mongo_client.db(db_name)
|
89
|
-
@db.authenticate(db_user, db_password) unless db_user.nil?
|
90
|
-
else
|
91
|
-
address_str = "#{host}:#{port}"
|
92
|
-
client_opts = {}
|
93
|
-
client_opts[:database] = db_name
|
94
|
-
unless db_user.nil?
|
95
|
-
client_opts[:user] = db_user
|
96
|
-
client_opts[:password] = db_password
|
97
|
-
end
|
98
|
-
mongo_client = Mongo::Client.new([address_str], client_opts)
|
99
|
-
@db = mongo_client.database
|
100
|
-
end
|
101
|
-
end
|
97
|
+
option :require_master,
|
98
|
+
description: 'Require the node to be a master node',
|
99
|
+
long: '--require-master',
|
100
|
+
default: false
|
102
101
|
|
103
102
|
def run
|
104
103
|
Mongo::Logger.logger.level = Logger::FATAL
|
@@ -107,89 +106,22 @@ class MongoDB < Sensu::Plugin::Metric::CLI::Graphite
|
|
107
106
|
Mongo::Logger.logger.level = Logger::DEBUG
|
108
107
|
config_debug = config.clone
|
109
108
|
config_debug[:password] = '***'
|
110
|
-
puts '
|
111
|
-
end
|
112
|
-
host = config[:host]
|
113
|
-
port = config[:port]
|
114
|
-
db_name = 'admin'
|
115
|
-
db_user = config[:user]
|
116
|
-
db_password = config[:password]
|
117
|
-
|
118
|
-
connect_mongo_db(host, port, db_name, db_user, db_password)
|
119
|
-
|
120
|
-
_result = false
|
121
|
-
# check if master
|
122
|
-
begin
|
123
|
-
@is_master = get_mongo_doc('isMaster' => 1)
|
124
|
-
unless @is_master.nil?
|
125
|
-
_result = @is_master['ok'] == 1
|
126
|
-
end
|
127
|
-
rescue StandardError => e
|
128
|
-
if @debug
|
129
|
-
puts 'Error checking isMaster:' + e.message
|
130
|
-
puts e.backtrace.inspect
|
131
|
-
end
|
132
|
-
exit(1)
|
109
|
+
puts 'Arguments: ' + config_debug.inspect
|
133
110
|
end
|
134
111
|
|
135
|
-
#
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
end
|
146
|
-
rescue StandardError => e
|
147
|
-
if @debug
|
148
|
-
puts 'Error checking serverStatus:' + e.message
|
149
|
-
puts e.backtrace.inspect
|
150
|
-
end
|
151
|
-
exit(2)
|
112
|
+
# Get the metrics.
|
113
|
+
collector = SensuPluginsMongoDB::Metrics.new(config)
|
114
|
+
collector.connect_mongo_db('admin')
|
115
|
+
exit(1) if config[:require_master] && !collector.master?
|
116
|
+
metrics = collector.server_metrics
|
117
|
+
|
118
|
+
# Print them in graphite format.
|
119
|
+
timestamp = Time.now.to_i
|
120
|
+
metrics.each do |k, v|
|
121
|
+
output [config[:scheme], k].join('.'), v, timestamp
|
152
122
|
end
|
153
123
|
|
154
124
|
# done!
|
155
125
|
ok
|
156
126
|
end
|
157
|
-
|
158
|
-
def gather_replication_metrics(server_status)
|
159
|
-
mongo_version = server_status['version'].gsub(/[^0-9\.]/i, '') # Handle versions like "2.6.11-pre" etc
|
160
|
-
server_metrics = {}
|
161
|
-
|
162
|
-
server_metrics['lock.ratio'] = sprintf('%.5f', server_status['globalLock']['ratio']).to_s unless server_status['globalLock']['ratio'].nil?
|
163
|
-
|
164
|
-
server_metrics['lock.queue.total'] = server_status['globalLock']['currentQueue']['total']
|
165
|
-
server_metrics['lock.queue.readers'] = server_status['globalLock']['currentQueue']['readers']
|
166
|
-
server_metrics['lock.queue.writers'] = server_status['globalLock']['currentQueue']['writers']
|
167
|
-
|
168
|
-
server_metrics['connections.current'] = server_status['connections']['current']
|
169
|
-
server_metrics['connections.available'] = server_status['connections']['available']
|
170
|
-
|
171
|
-
if Gem::Version.new(mongo_version) < Gem::Version.new('3.0.0')
|
172
|
-
if server_status['indexCounters']['btree'].nil?
|
173
|
-
server_metrics['indexes.missRatio'] = sprintf('%.5f', server_status['indexCounters']['missRatio']).to_s
|
174
|
-
server_metrics['indexes.hits'] = server_status['indexCounters']['hits']
|
175
|
-
server_metrics['indexes.misses'] = server_status['indexCounters']['misses']
|
176
|
-
else
|
177
|
-
server_metrics['indexes.missRatio'] = sprintf('%.5f', server_status['indexCounters']['btree']['missRatio']).to_s
|
178
|
-
server_metrics['indexes.hits'] = server_status['indexCounters']['btree']['hits']
|
179
|
-
server_metrics['indexes.misses'] = server_status['indexCounters']['btree']['misses']
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
server_metrics['cursors.open'] = server_status['metrics']['cursor']['open']['total']
|
184
|
-
server_metrics['cursors.timedOut'] = server_status['metrics']['cursor']['timedOut']
|
185
|
-
|
186
|
-
server_metrics['mem.residentMb'] = server_status['mem']['resident']
|
187
|
-
server_metrics['mem.virtualMb'] = server_status['mem']['virtual']
|
188
|
-
server_metrics['mem.mapped'] = server_status['mem']['mapped']
|
189
|
-
server_metrics['mem.pageFaults'] = server_status['extra_info']['page_faults']
|
190
|
-
|
191
|
-
server_metrics['asserts.warnings'] = server_status['asserts']['warning']
|
192
|
-
server_metrics['asserts.errors'] = server_status['asserts']['msg']
|
193
|
-
server_metrics
|
194
|
-
end
|
195
127
|
end
|
@@ -0,0 +1,340 @@
|
|
1
|
+
require 'mongo'
|
2
|
+
include Mongo
|
3
|
+
|
4
|
+
module SensuPluginsMongoDB
|
5
|
+
class Metrics
|
6
|
+
# Initializes a Metrics collector.
|
7
|
+
#
|
8
|
+
# @param config [Mesh]
|
9
|
+
# the config object parsed from the command line.
|
10
|
+
# Must include: :host, :port, :user, :password, :debug
|
11
|
+
def initialize(config)
|
12
|
+
@config = config
|
13
|
+
@connected = false
|
14
|
+
@db = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
# Connects to a mongo database.
|
18
|
+
#
|
19
|
+
# @param db_name [String] the name of the db to connect to.
|
20
|
+
def connect_mongo_db(db_name)
|
21
|
+
if @connected
|
22
|
+
raise 'Already connected to a database'
|
23
|
+
end
|
24
|
+
|
25
|
+
@connected = true
|
26
|
+
host = @config[:host]
|
27
|
+
port = @config[:port]
|
28
|
+
db_user = @config[:user]
|
29
|
+
db_password = @config[:password]
|
30
|
+
ssl = @config[:ssl]
|
31
|
+
ssl_cert = @config[:ssl_cert]
|
32
|
+
ssl_key = @config[:ssl_key]
|
33
|
+
ssl_ca_cert = @config[:ssl_ca_cert]
|
34
|
+
ssl_verify = @config[:ssl_verify]
|
35
|
+
|
36
|
+
if Gem.loaded_specs['mongo'].version < Gem::Version.new('2.0.0')
|
37
|
+
mongo_client = MongoClient.new(host, port)
|
38
|
+
@db = mongo_client.db(db_name)
|
39
|
+
@db.authenticate(db_user, db_password) unless db_user.nil?
|
40
|
+
else
|
41
|
+
address_str = "#{host}:#{port}"
|
42
|
+
client_opts = {}
|
43
|
+
client_opts[:database] = db_name
|
44
|
+
unless db_user.nil?
|
45
|
+
client_opts[:user] = db_user
|
46
|
+
client_opts[:password] = db_password
|
47
|
+
end
|
48
|
+
if ssl
|
49
|
+
client_opts[:ssl] = true
|
50
|
+
client_opts[:ssl_cert] = ssl_cert
|
51
|
+
client_opts[:ssl_key] = ssl_key
|
52
|
+
client_opts[:ssl_ca_cert] = ssl_ca_cert
|
53
|
+
client_opts[:ssl_verify] = ssl_verify
|
54
|
+
end
|
55
|
+
mongo_client = Mongo::Client.new([address_str], client_opts)
|
56
|
+
@db = mongo_client.database
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Fetches a document from the mongo db.
|
61
|
+
#
|
62
|
+
# @param command [Mesh] the command to search documents with.
|
63
|
+
# @return [Mesh, nil] the first document or nil.
|
64
|
+
def get_mongo_doc(command)
|
65
|
+
unless @connected
|
66
|
+
raise 'Cannot fetch documents before connecting.'
|
67
|
+
end
|
68
|
+
unless @db
|
69
|
+
raise 'Cannot fetch documents without a db.'
|
70
|
+
end
|
71
|
+
|
72
|
+
rs = @db.command(command)
|
73
|
+
unless rs.successful?
|
74
|
+
return nil
|
75
|
+
end
|
76
|
+
rs.documents[0]
|
77
|
+
end
|
78
|
+
|
79
|
+
# Checks if the connected node is the master node.
|
80
|
+
#
|
81
|
+
# @return [true, false] true when the node is a master node.
|
82
|
+
def master?
|
83
|
+
result = false
|
84
|
+
begin
|
85
|
+
@is_master = get_mongo_doc('isMaster' => 1)
|
86
|
+
unless @is_master.nil?
|
87
|
+
result = @is_master['ok'] == 1 && @is_master['ismaster']
|
88
|
+
end
|
89
|
+
rescue StandardError => e
|
90
|
+
if @config[:debug]
|
91
|
+
puts 'Error checking isMaster: ' + e.message
|
92
|
+
puts e.backtrace.inspect
|
93
|
+
end
|
94
|
+
end
|
95
|
+
result
|
96
|
+
end
|
97
|
+
|
98
|
+
# Fetches the status of the server (which includes the metrics).
|
99
|
+
#
|
100
|
+
# @return [Mash, nil] the document showing the server status or nil.
|
101
|
+
def server_status
|
102
|
+
status = get_mongo_doc('serverStatus' => 1)
|
103
|
+
return nil if status.nil? || status['ok'] != 1
|
104
|
+
return status
|
105
|
+
rescue StandardError => e
|
106
|
+
if @debug
|
107
|
+
puts 'Error checking serverStatus: ' + e.message
|
108
|
+
puts e.backtrace.inspect
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Fetches metrics for the server we are connected to.
|
113
|
+
#
|
114
|
+
# @return [Mash] the metrics for the server.
|
115
|
+
# rubocop:disable Metrics/AbcSize
|
116
|
+
def server_metrics
|
117
|
+
server_status = self.server_status
|
118
|
+
server_metrics = {}
|
119
|
+
# Handle versions like "2.6.11-pre" etc
|
120
|
+
mongo_version = server_status['version'].gsub(/[^0-9\.]/i, '')
|
121
|
+
|
122
|
+
server_metrics['lock.ratio'] = sprintf('%.5f', server_status['globalLock']['ratio']).to_s unless server_status['globalLock']['ratio'].nil?
|
123
|
+
|
124
|
+
# Asserts
|
125
|
+
asserts = server_status['asserts']
|
126
|
+
server_metrics['asserts.warnings'] = asserts['warning']
|
127
|
+
server_metrics['asserts.errors'] = asserts['msg']
|
128
|
+
server_metrics['asserts.regular'] = asserts['regular']
|
129
|
+
server_metrics['asserts.user'] = asserts['user']
|
130
|
+
server_metrics['asserts.rollovers'] = asserts['rollovers']
|
131
|
+
|
132
|
+
# Background flushing
|
133
|
+
if server_status.key?('backgroundFlushing')
|
134
|
+
bg_flushing = server_status['backgroundFlushing']
|
135
|
+
server_metrics['backgroundFlushing.flushes'] = bg_flushing['flushes']
|
136
|
+
server_metrics['backgroundFlushing.total_ms'] = bg_flushing['total_ms']
|
137
|
+
server_metrics['backgroundFlushing.average_ms'] = bg_flushing['average_ms']
|
138
|
+
server_metrics['backgroundFlushing.last_ms'] = bg_flushing['last_ms']
|
139
|
+
end
|
140
|
+
|
141
|
+
# Connections
|
142
|
+
connections = server_status['connections']
|
143
|
+
server_metrics['connections.current'] = connections['current']
|
144
|
+
server_metrics['connections.available'] = connections['available']
|
145
|
+
server_metrics['connections.totalCreated'] = connections['totalCreated']
|
146
|
+
|
147
|
+
# Cursors (use new metrics.cursor from mongo 2.6+)
|
148
|
+
if Gem::Version.new(mongo_version) < Gem::Version.new('2.6.0')
|
149
|
+
cursors = server_status['cursors']
|
150
|
+
server_metrics['clientCursors.size'] = cursors['clientCursors_size']
|
151
|
+
server_metrics['cursors.timedOut'] = cursors['timedOut']
|
152
|
+
|
153
|
+
# Metric names match the version 2.6+ format for standardization!
|
154
|
+
server_metrics['cursors.open.NoTimeout'] = cursors['totalNoTimeout']
|
155
|
+
server_metrics['cursors.open.pinned'] = cursors['pinned']
|
156
|
+
server_metrics['cursors.open.total'] = cursors['totalOpen']
|
157
|
+
else
|
158
|
+
cursors = server_status['metrics']['cursor']
|
159
|
+
server_metrics['cursors.timedOut'] = cursors['timedOut']
|
160
|
+
# clientCursors.size has been replaced by cursors.open.total
|
161
|
+
|
162
|
+
open = cursors['open']
|
163
|
+
server_metrics['cursors.open.noTimeout'] = open['noTimeout']
|
164
|
+
server_metrics['cursors.open.pinned'] = open['pinned']
|
165
|
+
server_metrics['cursors.open.total'] = open['total']
|
166
|
+
|
167
|
+
unless Gem::Version.new(mongo_version) < Gem::Version.new('3.0.0')
|
168
|
+
server_metrics['cursors.open.multiTarget'] = open['multiTarget']
|
169
|
+
server_metrics['cursors.open.singleTarget'] = open['singleTarget']
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# Journaling (durability)
|
174
|
+
if server_status.key?('dur')
|
175
|
+
dur = server_status['dur']
|
176
|
+
server_metrics['journal.commits'] = dur['commits']
|
177
|
+
server_metrics['journaled_MB'] = dur['journaledMB']
|
178
|
+
server_metrics['journal.timeMs.writeToDataFiles'] = dur['timeMs']['writeToDataFiles']
|
179
|
+
server_metrics['journal.writeToDataFilesMB'] = dur['writeToDataFilesMB']
|
180
|
+
server_metrics['journal.compression'] = dur['compression']
|
181
|
+
server_metrics['journal.commitsInWriteLock'] = dur['commitsInWriteLock']
|
182
|
+
server_metrics['journal.timeMs.dt'] = dur['timeMs']['dt']
|
183
|
+
server_metrics['journal.timeMs.prepLogBuffer'] = dur['timeMs']['prepLogBuffer']
|
184
|
+
server_metrics['journal.timeMs.writeToJournal'] = dur['timeMs']['writeToJournal']
|
185
|
+
server_metrics['journal.timeMs.remapPrivateView'] = dur['timeMs']['remapPrivateView']
|
186
|
+
end
|
187
|
+
|
188
|
+
# Extra info
|
189
|
+
extra_info = server_status['extra_info']
|
190
|
+
server_metrics['mem.heap_usage_bytes'] = extra_info['heap_usage_bytes']
|
191
|
+
server_metrics['mem.pageFaults'] = extra_info['page_faults']
|
192
|
+
|
193
|
+
# Global Lock
|
194
|
+
global_lock = server_status['globalLock']
|
195
|
+
server_metrics['lock.totalTime'] = global_lock['totalTime']
|
196
|
+
server_metrics['lock.queue_total'] = global_lock['currentQueue']['total']
|
197
|
+
server_metrics['lock.queue_readers'] = global_lock['currentQueue']['readers']
|
198
|
+
server_metrics['lock.queue_writers'] = global_lock['currentQueue']['writers']
|
199
|
+
server_metrics['lock.clients_total'] = global_lock['activeClients']['total']
|
200
|
+
server_metrics['lock.clients_readers'] = global_lock['activeClients']['readers']
|
201
|
+
server_metrics['lock.clients_writers'] = global_lock['activeClients']['writers']
|
202
|
+
|
203
|
+
# Index counters
|
204
|
+
if Gem::Version.new(mongo_version) < Gem::Version.new('3.0.0')
|
205
|
+
index_counters = server_status['indexCounters']
|
206
|
+
index_counters = server_status['indexCounters']['btree'] unless server_status['indexCounters']['btree'].nil?
|
207
|
+
|
208
|
+
server_metrics['indexes.missRatio'] = sprintf('%.5f', index_counters['missRatio']).to_s
|
209
|
+
server_metrics['indexes.hits'] = index_counters['hits']
|
210
|
+
server_metrics['indexes.misses'] = index_counters['misses']
|
211
|
+
server_metrics['indexes.accesses'] = index_counters['accesses']
|
212
|
+
server_metrics['indexes.resets'] = index_counters['resets']
|
213
|
+
end
|
214
|
+
|
215
|
+
# Locks (from mongo 3.0+ only)
|
216
|
+
unless Gem::Version.new(mongo_version) < Gem::Version.new('3.0.0')
|
217
|
+
locks = server_status['locks']
|
218
|
+
lock_namespaces = %w(
|
219
|
+
Collection Global Database Metadata
|
220
|
+
MMAPV1Journal oplog
|
221
|
+
)
|
222
|
+
lock_dimentions = %w(
|
223
|
+
acquireCount acquireWaitCount
|
224
|
+
timeAcquiringMicros deadlockCount
|
225
|
+
)
|
226
|
+
|
227
|
+
lock_namespaces.each do |ns|
|
228
|
+
lock_dimentions.each do |dm|
|
229
|
+
next unless locks.key?(ns) && locks[ns].key?(dm)
|
230
|
+
lock = locks[ns][dm]
|
231
|
+
server_metrics["locks.#{ns}.#{dm}_r"] = lock['r'] if lock.key?('r')
|
232
|
+
server_metrics["locks.#{ns}.#{dm}_w"] = lock['r'] if lock.key?('w')
|
233
|
+
server_metrics["locks.#{ns}.#{dm}_R"] = lock['r'] if lock.key?('R')
|
234
|
+
server_metrics["locks.#{ns}.#{dm}_W"] = lock['r'] if lock.key?('W')
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
# Network
|
240
|
+
network = server_status['network']
|
241
|
+
server_metrics['network.bytesIn'] = network['bytesIn']
|
242
|
+
server_metrics['network.bytesOut'] = network['bytesOut']
|
243
|
+
server_metrics['network.numRequests'] = network['numRequests']
|
244
|
+
|
245
|
+
# Opcounters
|
246
|
+
opcounters = server_status['opcounters']
|
247
|
+
server_metrics['opcounters.insert'] = opcounters['insert']
|
248
|
+
server_metrics['opcounters.query'] = opcounters['query']
|
249
|
+
server_metrics['opcounters.update'] = opcounters['update']
|
250
|
+
server_metrics['opcounters.delete'] = opcounters['delete']
|
251
|
+
server_metrics['opcounters.getmore'] = opcounters['getmore']
|
252
|
+
server_metrics['opcounters.command'] = opcounters['command']
|
253
|
+
|
254
|
+
# Opcounters Replication
|
255
|
+
opcounters_repl = server_status['opcountersRepl']
|
256
|
+
server_metrics['opcountersRepl.insert'] = opcounters_repl['insert']
|
257
|
+
server_metrics['opcountersRepl.query'] = opcounters_repl['query']
|
258
|
+
server_metrics['opcountersRepl.update'] = opcounters_repl['update']
|
259
|
+
server_metrics['opcountersRepl.delete'] = opcounters_repl['delete']
|
260
|
+
server_metrics['opcountersRepl.getmore'] = opcounters_repl['getmore']
|
261
|
+
server_metrics['opcountersRepl.command'] = opcounters_repl['command']
|
262
|
+
|
263
|
+
# Memory
|
264
|
+
mem = server_status['mem']
|
265
|
+
server_metrics['mem.residentMb'] = mem['resident']
|
266
|
+
server_metrics['mem.virtualMb'] = mem['virtual']
|
267
|
+
server_metrics['mem.mapped'] = mem['mapped']
|
268
|
+
server_metrics['mem.mappedWithJournal'] = mem['mappedWithJournal']
|
269
|
+
|
270
|
+
# Metrics (documents)
|
271
|
+
document = server_status['metrics']['document']
|
272
|
+
server_metrics['metrics.document.deleted'] = document['deleted']
|
273
|
+
server_metrics['metrics.document.inserted'] = document['inserted']
|
274
|
+
server_metrics['metrics.document.returned'] = document['returned']
|
275
|
+
server_metrics['metrics.document.updated'] = document['updated']
|
276
|
+
|
277
|
+
# Metrics (getLastError)
|
278
|
+
get_last_error = server_status['metrics']['getLastError']
|
279
|
+
server_metrics['metrics.getLastError.wtime_num'] = get_last_error['wtime']['num']
|
280
|
+
server_metrics['metrics.getLastError.wtime_totalMillis'] = get_last_error['wtime']['totalMillis']
|
281
|
+
server_metrics['metrics.getLastError.wtimeouts'] = get_last_error['wtimeouts']
|
282
|
+
|
283
|
+
# Metrics (operation)
|
284
|
+
operation = server_status['metrics']['operation']
|
285
|
+
server_metrics['metrics.operation.fastmod'] = operation['fastmod']
|
286
|
+
server_metrics['metrics.operation.idhack'] = operation['idhack']
|
287
|
+
server_metrics['metrics.operation.scanAndOrder'] = operation['scanAndOrder']
|
288
|
+
|
289
|
+
# Metrics (operation)
|
290
|
+
query_executor = server_status['metrics']['queryExecutor']
|
291
|
+
server_metrics['metrics.queryExecutor.scanned'] = query_executor['scanned']
|
292
|
+
server_metrics['metrics.queryExecutor.scannedObjects'] = query_executor['scannedObjects']
|
293
|
+
server_metrics['metrics.record.moves'] = server_status['metrics']['record']['moves']
|
294
|
+
|
295
|
+
# Metrics (repl)
|
296
|
+
repl = server_status['metrics']['repl']
|
297
|
+
server_metrics['metrics.repl.apply.batches_num'] = repl['apply']['batches']['num']
|
298
|
+
server_metrics['metrics.repl.apply.batches_totalMillis'] = repl['apply']['batches']['totalMillis']
|
299
|
+
server_metrics['metrics.repl.apply.ops'] = repl['apply']['ops']
|
300
|
+
server_metrics['metrics.repl.buffer.count'] = repl['buffer']['count']
|
301
|
+
server_metrics['metrics.repl.buffer.maxSizeBytes'] = repl['buffer']['maxSizeBytes']
|
302
|
+
server_metrics['metrics.repl.buffer.sizeBytes'] = repl['buffer']['sizeBytes']
|
303
|
+
server_metrics['metrics.repl.network.bytes'] = repl['network']['bytes']
|
304
|
+
server_metrics['metrics.repl.network.getmores_num'] = repl['network']['getmores']['num']
|
305
|
+
server_metrics['metrics.repl.network.getmores_totalMillis'] = repl['network']['getmores']['totalMillis']
|
306
|
+
server_metrics['metrics.repl.network.ops'] = repl['network']['ops']
|
307
|
+
server_metrics['metrics.repl.network.readersCreated'] = repl['network']['readersCreated']
|
308
|
+
server_metrics['metrics.repl.preload.docs_num'] = repl['preload']['docs']['num']
|
309
|
+
server_metrics['metrics.repl.preload.docs_totalMillis'] = repl['preload']['docs']['totalMillis']
|
310
|
+
server_metrics['metrics.repl.preload.indexes_num'] = repl['preload']['indexes']['num']
|
311
|
+
server_metrics['metrics.repl.preload.indexes_totalMillis'] = repl['preload']['indexes']['totalMillis']
|
312
|
+
|
313
|
+
# Metrics (storage)
|
314
|
+
if Gem::Version.new(mongo_version) >= Gem::Version.new('2.6.0')
|
315
|
+
freelist = server_status['metrics']['storage']['freelist']
|
316
|
+
server_metrics['metrics.storage.freelist.search_bucketExhauseted'] = freelist['search']['bucketExhausted']
|
317
|
+
server_metrics['metrics.storage.freelist.search_requests'] = freelist['search']['requests']
|
318
|
+
server_metrics['metrics.storage.freelist.search_scanned'] = freelist['search']['scanned']
|
319
|
+
end
|
320
|
+
|
321
|
+
# Metrics (ttl)
|
322
|
+
ttl = server_status['metrics']['ttl']
|
323
|
+
server_metrics['metrics.ttl.deletedDocuments'] = ttl['deletedDocuments']
|
324
|
+
server_metrics['metrics.ttl.passes'] = ttl['passes']
|
325
|
+
|
326
|
+
# Return metrics map.
|
327
|
+
# MongoDB returns occasional nils and floats as {"floatApprox": x}.
|
328
|
+
# Clean up the results once here to avoid per-metric logic.
|
329
|
+
clean_metrics = {}
|
330
|
+
server_metrics.each do |k, v|
|
331
|
+
next if v.nil?
|
332
|
+
if v.is_a?(Hash) && v.key?('floatApprox')
|
333
|
+
v = v['floatApprox']
|
334
|
+
end
|
335
|
+
clean_metrics[k] = v
|
336
|
+
end
|
337
|
+
clean_metrics
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sensu-plugins-mongodb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sensu-Plugins and contributors
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-10-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bson
|
@@ -187,7 +187,9 @@ description: |-
|
|
187
187
|
more.
|
188
188
|
email: "<sensu-users@googlegroups.com>"
|
189
189
|
executables:
|
190
|
+
- check-mongodb-metric.rb
|
190
191
|
- check-mongodb.rb
|
192
|
+
- metrics-mongodb-replication.rb
|
191
193
|
- metrics-mongodb.rb
|
192
194
|
extensions: []
|
193
195
|
extra_rdoc_files: []
|
@@ -195,10 +197,13 @@ files:
|
|
195
197
|
- CHANGELOG.md
|
196
198
|
- LICENSE
|
197
199
|
- README.md
|
200
|
+
- bin/check-mongodb-metric.rb
|
198
201
|
- bin/check-mongodb.py
|
199
202
|
- bin/check-mongodb.rb
|
203
|
+
- bin/metrics-mongodb-replication.rb
|
200
204
|
- bin/metrics-mongodb.rb
|
201
205
|
- lib/sensu-plugins-mongodb.rb
|
206
|
+
- lib/sensu-plugins-mongodb/metics.rb
|
202
207
|
- lib/sensu-plugins-mongodb/version.rb
|
203
208
|
homepage: https://github.com/sensu-plugins/sensu-plugins-mongodb
|
204
209
|
licenses:
|
@@ -231,4 +236,3 @@ signing_key:
|
|
231
236
|
specification_version: 4
|
232
237
|
summary: Sensu plugins for mongodb
|
233
238
|
test_files: []
|
234
|
-
has_rdoc:
|