-
Notifications
You must be signed in to change notification settings - Fork 595
Expand file tree
/
Copy pathamavis.py
More file actions
102 lines (88 loc) · 3.65 KB
/
amavis.py
File metadata and controls
102 lines (88 loc) · 3.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# coding=utf-8
"""
Collector that reports amavis metrics as reported by amavisd-agent
#### Dependencies
* amavisd-agent must be present in PATH
"""
import os
import subprocess
import re
import diamond.collector
import diamond.convertor
from diamond.collector import str_to_bool
class AmavisCollector(diamond.collector.Collector):
# From the source of amavisd-agent and it seems like the three interesting
# formats are these: ("x y/h", "xMB yMB/h", "x s y s/msg"),
# so this, ugly as it is to hardcode it this way, it should be right.
#
# The other option would be to directly read and decode amavis' berkeley
# db, and I don't even want to get there
matchers = [
re.compile(r'^\s*(?P<name>[\w]+)\s+(?P<time>[\d]+) s\s+'
r'(?P<frequency>[\d.]+) s/msg\s+\([\w]+\)\s*$'),
re.compile(r'^\s*(?P<name>[\w.-]+)\s+(?P<count>[\d]+)\s+'
r'(?P<frequency>[\d.]+)/h\s+(?P<percentage>[\d.]+) %'
r'\s\([\w]+\)\s*$'),
re.compile(r'^\s*(?P<name>[\w.-]+)\s+(?P<size>[\d]+)MB\s+'
r'(?P<frequency>[\d.]+)MB/h\s+(?P<percentage>[\d.]+) %'
r'\s\([\w]+\)\s*$'),
]
def get_default_config_help(self):
config_help = super(AmavisCollector, self).get_default_config_help()
config_help.update({
'amavisd_exe': 'The path to amavisd-agent',
'use_sudo': 'Call amavisd-agent using sudo',
'sudo_exe': 'The path to sudo',
'sudo_user': 'The user to use if using sudo',
})
return config_help
def get_default_config(self):
config = super(AmavisCollector, self).get_default_config()
config.update({
'path': 'amavis',
'amavisd_exe': '/usr/sbin/amavisd-agent',
'use_sudo': False,
'sudo_exe': '/usr/bin/sudo',
'sudo_user': 'amavis',
})
return config
def collect(self):
"""
Collect memory stats
"""
try:
if str_to_bool(self.config['use_sudo']):
# Use -u instead of --user as the former is more portable. Not
# all versions of sudo support the long form --user.
cmdline = [
self.config['sudo_exe'], '-u', self.config['sudo_user'],
'--', self.config['amavisd_exe'], '-c', '1'
]
else:
cmdline = [self.config['amavisd_exe'], '-c', '1']
agent = subprocess.Popen(cmdline, stdout=subprocess.PIPE)
agent_out = agent.communicate()[0]
lines = agent_out.strip().split(os.linesep)
for line in lines:
for rex in self.matchers:
res = rex.match(line)
if res:
groups = res.groupdict()
name = groups['name']
for metric, value in list(groups.items()):
if metric == 'name':
continue
mtype = 'GAUGE'
precision = 2
if metric in ('count', 'time'):
mtype = 'COUNTER'
precision = 0
self.publish("{}.{}".format(name, metric),
value, metric_type=mtype,
precision=precision)
except OSError as err:
self.log.error("Could not run %s: %s",
self.config['amavisd_exe'],
err)
return None
return True