initial revision of python plugin for monit (https://mmonit.com/monit/)
Evgeniy Kostenko committed
Aug 2, 2018 at 07:01 UTC
a5b3dcec48aa85f74e727318e7021e9512fb6330
1 file changed
+148
python.d/monit.chart.py
new
+148
@@ -0,0 +1,148 @@
1
+# -*- coding: utf-8 -*-
2
+# Description: monit netdata python.d module
3
+# Author: Evgeniy K. (n0guest)
4
+# SPDX-License-Identifier: GPL-3.0+
5
+
6
+import xml.etree.ElementTree as ET
7
+import pdb
8
+
9
+from bases.FrameworkServices.UrlService import UrlService
10
+
11
+# default module values (can be overridden per job in `config`)
12
+# update_every = 2
13
+priority = 60000
14
+retries = 60
15
+
16
+MONIT_SERVICE_NAMES = [ 'Filesystem', 'Directory', 'File', 'Process', 'Host', 'System', 'Fifo', 'Program', 'Net' ]
17
+DEFAULT_SERVICES_IDS = [ 0, 1, 2, 3, 4, 6, 7, 8 ]
18
+
19
+# charts order (can be overridden if you want less charts, or different order)
20
+ORDER = [ 'filesystem', 'directory', 'file', 'process', 'process_uptime', 'process_threads', 'process_children', 'host', 'host_latency', 'system', 'fifo', 'program', 'net' ]
21
+CHARTS = {
22
+ # id: {
23
+ # 'options': [name, title, units, family, context, charttype],
24
+ # 'lines': [
25
+ # [unique_dimension_name, name, algorithm, multiplier, divisor]
26
+ # ]}
27
+ 'filesystem': {
28
+ 'options': ['filesystems', 'Filesystems', 'filesystems', 'filesystem', 'monit.filesystems', 'line'],
29
+ 'lines': []
30
+ },
31
+ 'directory': {
32
+ 'options': ['directories', 'Directories', 'directories', 'filesystem', 'monit.directories', 'line'],
33
+ 'lines': []
34
+ },
35
+ 'file': {
36
+ 'options': ['files', 'Files', 'files', 'filesystem', 'monit.files', 'line'],
37
+ 'lines': []
38
+ },
39
+ 'fifo': {
40
+ 'options': ['fifos', 'Pipes (fifo)', 'pipes', 'filesystem', 'monit.fifos', 'line'],
41
+ 'lines': []
42
+ },
43
+ 'program': {
44
+ 'options': ['programs', 'Programs statuses', 'programs', 'applications', 'monit.programs', 'line'],
45
+ 'lines': []
46
+ },
47
+ 'process': {
48
+ 'options': ['processes', 'Processes statuses', 'processes', 'applications', 'monit.services', 'line'],
49
+ 'lines': []
50
+ },
51
+ 'process_uptime': {
52
+ 'options': ['processes uptime', 'Processes uptime', 'seconds', 'applications', 'monit.process_uptime', 'line', 'hidden'],
53
+ 'lines': []
54
+ },
55
+ 'process_threads': {
56
+ 'options': ['processes threads', 'Processes threads', 'threads', 'applications', 'monit.process_threads', 'line'],
57
+ 'lines': []
58
+ },
59
+ 'process_children': {
60
+ 'options': ['processes childrens', 'Child processes', 'childrens', 'applications', 'monit.process_childrens', 'line'],
61
+ 'lines': []
62
+ },
63
+ 'host': {
64
+ 'options': ['hosts', 'Hosts', 'hosts', 'network', 'monit.hosts', 'line'],
65
+ 'lines': []
66
+ },
67
+ 'host_latency': {
68
+ 'options': ['hosts latency', 'Hosts latency', 'milliseconds/s', 'network', 'monit.hosts', 'line'],
69
+ 'lines': []
70
+ },
71
+ 'net': {
72
+ 'options': ['interfaces', 'Network interfaces and addresses', 'interfaces', 'network', 'monit.networks', 'line'],
73
+ 'lines': []
74
+ },
75
+}
76
+
77
+class Service(UrlService):
78
+ def __init__(self, configuration=None, name=None):
79
+ UrlService.__init__(self, configuration=configuration, name=name)
80
+ self.url = self.configuration.get('url', "http://127.0.0.1:2812/_status?format=xml&level=full")
81
+ self.order = ORDER
82
+ self.definitions = CHARTS
83
+
84
+ def check(self):
85
+ self._manager = self._build_manager()
86
+ raw_data = self._get_raw_data()
87
+ if raw_data:
88
+ try:
89
+ xml = ET.fromstring(raw_data)
90
+ except ET.ParseError:
91
+ self.debug('%s is not a vaild XML page. Please add "_status?format=xml&level=full" to monit URL.' % self.url)
92
+ return None
93
+ return True
94
+ return None
95
+
96
+ def _get_data(self):
97
+ data = None
98
+ raw_data = self._get_raw_data()
99
+ if raw_data:
100
+ try:
101
+ xml = ET.fromstring(raw_data)
102
+ except ET.ParseError:
103
+ self.debug('%s is not a vaild XML page. Please add "_status?format=xml&level=full" to monit URL.' % self.url)
104
+ return None
105
+ data = {}
106
+
107
+ for svc_id in DEFAULT_SERVICES_IDS:
108
+ if svc_id not in DEFAULT_SERVICES_IDS:
109
+ continue
110
+
111
+ svc_category = MONIT_SERVICE_NAMES[svc_id].lower()
112
+ if svc_category == 'system':
113
+ self.debug("Skipping service from 'System' category, because it's useless in graphs")
114
+ continue
115
+
116
+ xpath_query = "./service[@type='%d']" % (svc_id)
117
+ self.debug("Searching for %s as %s" % (svc_category, xpath_query))
118
+ for svc in xml.findall(xpath_query):
119
+ svc_name = svc.find('name').text
120
+ svc_status = svc.find('status').text
121
+ svc_monitor = svc.find('monitor').text
122
+ self.debug('=> found %s with type=%s, status=%s, monitoring=%s' % (svc_name, svc_id, svc_status, svc_monitor))
123
+
124
+ dimension_key = svc_category + '_' + svc_name
125
+ if dimension_key not in self.charts[svc_category]:
126
+ self.charts[svc_category].add_dimension([dimension_key, svc_name, 'absolute'])
127
+ data[dimension_key] = 1 if svc_status == "0" and svc_monitor == "1" else 0
128
+
129
+ if svc_category == 'process':
130
+ for node in ('uptime', 'threads', 'children'):
131
+ node_value = svc.find(node)
132
+ if node_value != None:
133
+ if node == 'uptime' and int(node_value.text) < 0:
134
+ self.debug('Skipping bugged metrics with negative uptime')
135
+ continue
136
+ dimension_key = 'process_%s_%s' % (node, svc_name)
137
+ if dimension_key not in self.charts['process_' + node]:
138
+ self.charts['process_' + node].add_dimension([dimension_key, svc_name, 'absolute'])
139
+ data[dimension_key] = int(node_value.text)
140
+
141
+ if svc_category == 'host':
142
+ node_value = svc.find('./icmp/responsetime')
143
+ if node_value != None:
144
+ dimension_key = 'host_latency_%s' % (svc_name)
145
+ if dimension_key not in self.charts['host_latency']:
146
+ self.charts['host_latency'].add_dimension([dimension_key, svc_name, 'absolute', 1000, 1000000])
147
+ data[dimension_key] = float(node_value.text) * 1000000
148
+ return data or None