rethinkdb python plugin (#3955)
* rethinkdb python module init version * python readme: add rethinkdb
Ilya Mashchenko committed
Sep 13, 2018 at 16:23 UTC
5c1a47c9366401c2bddecbb3425eec46400ae860
7 files changed
+357
conf.d/Makefile.am
+1
@@ -71,6 +71,7 @@ dist_pythonconfig_DATA = \
71
python.d/puppet.conf \
72
python.d/rabbitmq.conf \
73
python.d/redis.conf \
74
+ python.d/rethinkdbs.conf \
75
python.d/retroshare.conf \
76
python.d/samba.conf \
77
python.d/sensors.conf \
conf.d/python.d.conf
+1
@@ -73,6 +73,7 @@ nginx_log: no
73
# puppet: yes
74
# rabbitmq: yes
75
# redis: yes
76
+# rethinkdbs: yes
77
# retroshare: yes
78
# sensors: yes
79
# spigotmc: yes
conf.d/python.d/rethinkdbs.conf
new
+78
@@ -0,0 +1,78 @@
1
+# netdata python.d.plugin configuration for rethinkdb
2
+#
3
+# This file is in YaML format. Generally the format is:
4
+#
5
+# name: value
6
+#
7
+# There are 2 sections:
8
+# - global variables
9
+# - one or more JOBS
10
+#
11
+# JOBS allow you to collect values from multiple sources.
12
+# Each source will have its own set of charts.
13
+#
14
+# JOB parameters have to be indented (using spaces only, example below).
15
+
16
+# ----------------------------------------------------------------------
17
+# Global Variables
18
+# These variables set the defaults for all JOBs, however each JOB
19
+# may define its own, overriding the defaults.
20
+
21
+# update_every sets the default data collection frequency.
22
+# If unset, the python.d.plugin default is used.
23
+# update_every: 1
24
+
25
+# priority controls the order of charts at the netdata dashboard.
26
+# Lower numbers move the charts towards the top of the page.
27
+# If unset, the default for python.d.plugin is used.
28
+# priority: 60000
29
+
30
+# retries sets the number of retries to be made in case of failures.
31
+# If unset, the default for python.d.plugin is used.
32
+# Attempts to restore the service are made once every update_every
33
+# and only if the module has collected values in the past.
34
+# retries: 60
35
+
36
+# autodetection_retry sets the job re-check interval in seconds.
37
+# The job is not deleted if check fails.
38
+# Attempts to start the job are made once every autodetection_retry.
39
+# This feature is disabled by default.
40
+# autodetection_retry: 0
41
+
42
+# ----------------------------------------------------------------------
43
+# JOBS (data collection sources)
44
+#
45
+# The default JOBS share the same *name*. JOBS with the same name
46
+# are mutually exclusive. Only one of them will be allowed running at
47
+# any time. This allows autodetection to try several alternatives and
48
+# pick the one that works.
49
+#
50
+# Any number of jobs is supported.
51
+#
52
+# All python.d.plugin JOBS (for all its modules) support a set of
53
+# predefined parameters. These are:
54
+#
55
+# job_name:
56
+# name: myname # the JOB's name as it will appear at the
57
+# # dashboard (by default is the job_name)
58
+# # JOBs sharing a name are mutually exclusive
59
+# update_every: 1 # the JOB's data collection frequency
60
+# priority: 60000 # the JOB's order on the dashboard
61
+# retries: 60 # the JOB's number of restoration attempts
62
+# autodetection_retry: 0 # the JOB's re-check interval in seconds
63
+#
64
+# Additionally to the above, rethinkdb also supports the following:
65
+#
66
+# host: IP or HOSTNAME # default is 'localhost'
67
+# port: PORT # default is 28015
68
+# user: USERNAME # default is 'admin'
69
+# password: PASSWORD # not set by default
70
+# timeout: TIMEOUT # default is 2
71
+
72
+# ----------------------------------------------------------------------
73
+# AUTO-DETECTION JOBS
74
+# only one of them will run (they have the same name)
75
+
76
+local:
77
+ name: 'local'
78
+ host: 'localhost'
python.d/Makefile.am
+1
@@ -57,6 +57,7 @@ dist_python_DATA = \
57
puppet.chart.py \
58
rabbitmq.chart.py \
59
redis.chart.py \
60
+ rethinkdbs.chart.py \
61
retroshare.chart.py \
62
samba.chart.py \
63
sensors.chart.py \
python.d/README.md
+35
@@ -2227,6 +2227,41 @@ When no configuration file is found, module tries to connect to TCP/IP socket: `
2227
2228
---
2229
2230
+# rethinkdb
2231
+
2232
+Module monitor rethinkdb health metrics.
2233
+
2234
+Following charts are drawn:
2235
+
2236
+1. **Connected Servers**
2237
+ * connected
2238
+ * missing
2239
+
2240
+2. **Active Clients**
2241
+ * active
2242
+
2243
+3. **Queries** per second
2244
+ * queries
2245
+
2246
+4. **Documents** per second
2247
+ * documents
2248
+
2249
+### configuration
2250
+
2251
+```yaml
2252
+
2253
+localhost:
2254
+ name : 'local'
2255
+ host : '127.0.0.1'
2256
+ port : 28015
2257
+ user : "user"
2258
+ password : "pass"
2259
+```
2260
+
2261
+When no configuration file is found, module tries to connect to `127.0.0.1:28015`.
2262
+
2263
+---
2264
+
2265
# samba
2266
2267
Performance metrics of Samba file sharing.
python.d/rethinkdbs.chart.py
new
+235
@@ -0,0 +1,235 @@
1
+# -*- coding: utf-8 -*-
2
+# Description: rethinkdb netdata python.d module
3
+# Author: Ilya Mashchenko (l2isbad)
4
+# SPDX-License-Identifier: GPL-3.0+
5
+
6
+try:
7
+ import rethinkdb as rdb
8
+ HAS_RETHINKDB = True
9
+except ImportError:
10
+ HAS_RETHINKDB = False
11
+
12
+from bases.FrameworkServices.SimpleService import SimpleService
13
+
14
+ORDER = [
15
+ 'cluster_connected_servers',
16
+ 'cluster_clients_active',
17
+ 'cluster_queries',
18
+ 'cluster_documents',
19
+]
20
+
21
+
22
+def cluster_charts():
23
+ return {
24
+ 'cluster_connected_servers': {
25
+ 'options': [None, 'Connected Servers', 'servers', 'cluster', 'rethinkdb.cluster_connected_servers',
26
+ 'stacked'],
27
+ 'lines': [
28
+ ['cluster_servers_connected', 'connected'],
29
+ ['cluster_servers_missing', 'missing'],
30
+ ]
31
+ },
32
+ 'cluster_clients_active': {
33
+ 'options': [None, 'Active Clients', 'clients', 'cluster', 'rethinkdb.cluster_clients_active',
34
+ 'line'],
35
+ 'lines': [
36
+ ['cluster_clients_active', 'active'],
37
+ ]
38
+ },
39
+ 'cluster_queries': {
40
+ 'options': [None, 'Queries', 'queries/s', 'cluster', 'rethinkdb.cluster_queries', 'line'],
41
+ 'lines': [
42
+ ['cluster_queries_per_sec', 'queries'],
43
+ ]
44
+ },
45
+ 'cluster_documents': {
46
+ 'options': [None, 'Documents', 'documents/s', 'cluster', 'rethinkdb.cluster_documents', 'line'],
47
+ 'lines': [
48
+ ['cluster_read_docs_per_sec', 'reads'],
49
+ ['cluster_written_docs_per_sec', 'writes'],
50
+ ]
51
+ },
52
+ }
53
+
54
+
55
+def server_charts(n):
56
+ o = [
57
+ '{0}_client_connections'.format(n),
58
+ '{0}_clients_active'.format(n),
59
+ '{0}_queries'.format(n),
60
+ '{0}_documents'.format(n),
61
+ ]
62
+ f = 'server {0}'.format(n)
63
+
64
+ c = {
65
+ o[0]: {
66
+ 'options': [None, 'Client Connections', 'connections', f, 'rethinkdb.client_connections', 'line'],
67
+ 'lines': [
68
+ ['{0}_client_connections'.format(n), 'connections'],
69
+ ]
70
+ },
71
+ o[1]: {
72
+ 'options': [None, 'Active Clients', 'clients', f, 'rethinkdb.clients_active', 'line'],
73
+ 'lines': [
74
+ ['{0}_clients_active'.format(n), 'active'],
75
+ ]
76
+ },
77
+ o[2]: {
78
+ 'options': [None, 'Queries', 'queries/s', f, 'rethinkdb.queries', 'line'],
79
+ 'lines': [
80
+ ['{0}_queries_total'.format(n), 'queries', 'incremental'],
81
+ ]
82
+ },
83
+ o[3]: {
84
+ 'options': [None, 'Documents', 'documents/s', f, 'rethinkdb.documents', 'line'],
85
+ 'lines': [
86
+ ['{0}_read_docs_total'.format(n), 'reads', 'incremental'],
87
+ ['{0}_written_docs_total'.format(n), 'writes', 'incremental'],
88
+ ]
89
+ },
90
+ }
91
+
92
+ return o, c
93
+
94
+
95
+class Cluster:
96
+ def __init__(self, raw):
97
+ self.raw = raw
98
+
99
+ def data(self):
100
+ qe = self.raw['query_engine']
101
+
102
+ return {
103
+ 'cluster_clients_active': qe['clients_active'],
104
+ 'cluster_queries_per_sec': qe['queries_per_sec'],
105
+ 'cluster_read_docs_per_sec': qe['read_docs_per_sec'],
106
+ 'cluster_written_docs_per_sec': qe['written_docs_per_sec'],
107
+ 'cluster_servers_connected': 0,
108
+ 'cluster_servers_missing': 0,
109
+ }
110
+
111
+
112
+class Server:
113
+ def __init__(self, raw):
114
+ self.name = raw['server']
115
+ self.raw = raw
116
+
117
+ def error(self):
118
+ return self.raw.get('error')
119
+
120
+ def data(self):
121
+ qe = self.raw['query_engine']
122
+
123
+ d = {
124
+ 'client_connections': qe['client_connections'],
125
+ 'clients_active': qe['clients_active'],
126
+ 'queries_total': qe['queries_total'],
127
+ 'read_docs_total': qe['read_docs_total'],
128
+ 'written_docs_total': qe['written_docs_total'],
129
+ }
130
+
131
+ return dict(('{0}_{1}'.format(self.name, k), d[k]) for k in d)
132
+
133
+
134
+class Service(SimpleService):
135
+ def __init__(self, configuration=None, name=None):
136
+ SimpleService.__init__(self, configuration=configuration, name=name)
137
+ self.order = list(ORDER)
138
+ self.definitions = cluster_charts()
139
+
140
+ self.host = self.configuration.get('host', '127.0.0.1')
141
+ self.port = self.configuration.get('port', 28015)
142
+ self.user = self.configuration.get('user', 'admin')
143
+ self.password = self.configuration.get('password')
144
+ self.timeout = self.configuration.get('timeout', 2)
145
+
146
+ self.conn = None
147
+ self.alive = True
148
+
149
+ def check(self):
150
+ if not HAS_RETHINKDB:
151
+ self.error('"rethinkdb" module is needed to use rethinkdbs.py')
152
+ return False
153
+
154
+ if not self.connect():
155
+ return None
156
+
157
+ stats = self.get_stats()
158
+
159
+ if not stats:
160
+ return None
161
+
162
+ for v in stats[1:]:
163
+ if get_id(v) == 'server':
164
+ o, c = server_charts(v['server'])
165
+ self.order.extend(o)
166
+ self.definitions.update(c)
167
+
168
+ return True
169
+
170
+ def get_data(self):
171
+ if not self.is_alive():
172
+ return None
173
+
174
+ stats = self.get_stats()
175
+
176
+ if not stats:
177
+ return None
178
+
179
+ data = dict()
180
+
181
+ # cluster
182
+ data.update(Cluster(stats[0]).data())
183
+
184
+ # servers
185
+ for v in stats[1:]:
186
+ if get_id(v) != 'server':
187
+ continue
188
+
189
+ s = Server(v)
190
+
191
+ if s.error():
192
+ data['cluster_servers_missing'] += 1
193
+ else:
194
+ data['cluster_servers_connected'] += 1
195
+ data.update(s.data())
196
+
197
+ return data
198
+
199
+ def get_stats(self):
200
+ try:
201
+ return list(rdb.db('rethinkdb').table('stats').run(self.conn).items)
202
+ except rdb.errors.ReqlError:
203
+ self.alive = False
204
+ return None
205
+
206
+ def connect(self):
207
+ try:
208
+ self.conn = rdb.connect(
209
+ host=self.host,
210
+ port=self.port,
211
+ user=self.user,
212
+ password=self.password,
213
+ timeout=self.timeout,
214
+ )
215
+ self.alive = True
216
+ return True
217
+ except rdb.errors.ReqlError as error:
218
+ self.error('Connection to {0}:{1} failed: {2}'.format(self.host, self.port, error))
219
+ return False
220
+
221
+ def reconnect(self):
222
+ # The connection is already closed after rdb.errors.ReqlError,
223
+ # so we do not need to call conn.close()
224
+ if self.connect():
225
+ return True
226
+ return False
227
+
228
+ def is_alive(self):
229
+ if not self.alive:
230
+ return self.reconnect()
231
+ return True
232
+
233
+
234
+def get_id(v):
235
+ return v['id'][0]
web/dashboard_info.js
+6
@@ -220,6 +220,12 @@ netdataDashboard.menu = {
220
info: 'Performance metrics for <b>redis</b>. Redis (REmote DIctionary Server) is a software project that implements data structure servers. It is open-source, networked, in-memory, and stores keys with optional durability.'
221
},
222
223
+ 'rethinkdbs': {
224
+ title: 'RethinkDB',
225
+ icon: '<i class="fas fa-database"></i>',
226
+ info: 'Performance metrics for <b>rethinkdb</b>. RethinkDB is the first open-source scalable database built for realtime applications'
227
+ },
228
+
229
'retroshare': {
230
title: 'RetroShare',
231
icon: '<i class="fas fa-share-alt"></i>',