Skip to content

Commit e0001f6

Browse files
author
alexander popov
committed
Merge branch 'dev'
2 parents 124e9b1 + 6d09526 commit e0001f6

File tree

17 files changed

+264
-43
lines changed

17 files changed

+264
-43
lines changed

mamonsu/lib/parser.py

+35-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
-c, --config <file>
1111
-p, --pid <pid-file>
1212
-d daemonize
13+
--version output version information, then exit
14+
--help show this help, then exit
1315
1416
Export example config with default variables:
1517
Command: export
@@ -38,31 +40,37 @@
3840
Export template for native zabbix agent:
3941
Command: export zabbix-template
4042
Examples:
41-
{prog} export zabbix-template <file>
43+
{prog} export zabbix-template [options] <file>
4244
Options:
4345
--template-name <template name>
4446
--plugin-type <plugin_type> (pg,sys,all)
4547
--application <application name in template>
4648
--pg-version <pg_version>
4749
--add-plugins <directory>
4850
--config <file>
51+
--old-zabbix
4952
Default plugin_type = all, template name = PostgresPro-<platform name>,
5053
application = App-PostgresPro-<platform name>, pg-version = 10,
5154
Note: default pg-version is vanilla, but with PGPRO or PGEE before version number it can be changed. Supported version
5255
numbers are 10, 11, 9.6, 9.5
56+
default template export for currently supported zabbix -server versions, if template for unsupported versions
57+
is needed use --old zabbix flag
5358
Example: PGPRO_10 or PGEE_11 or PGPRO_9.6
5459
5560
5661
Export zabbix template with additional plugins included in config file:
5762
Command: export template
5863
Examples:
59-
{prog} export template <file>
64+
{prog} export template [options] <file>
6065
Options:
6166
--add-plugins <directory>
6267
--template-name <template name>
6368
--application <application name in template>
6469
--config <file>
70+
--old-zabbix
6571
Default template name = PostgresPro-<platform name>, application = App-PostgresPro-<platform name>
72+
Note: default template export for currently supported zabbix -server versions, if template for unsupported versions
73+
is needed use --old zabbix flag
6674
6775
6876
Bootstrap DDL for monitoring:
@@ -117,6 +125,17 @@
117125
{prog} zabbix item error <host name>
118126
{prog} zabbix item lastvalue <host name>
119127
{prog} zabbix item lastclock <host name>
128+
129+
Export metrics to zabbix server
130+
Command: --send-data-zabbix
131+
Example:
132+
{prog} --send-data-zabbix --zabbix-file=localhost.log --zabbix-address=localhost
133+
Options:
134+
--zabbix-address <name of the Zabbix host to send metrics>
135+
--zabbix-port <port of Zabbix server to send metrics> by default 10051
136+
--zabbix-file <path to file with metrics to send metrics>
137+
--zabbix-client <name of the Zabbix host to send metrics> by default localhost
138+
--zabbix-log-level <log level to send metrics> (INFO|DEBUG|WARN) by default INFO
120139
"""
121140

122141
if platform.LINUX:
@@ -261,4 +280,18 @@ def parse_args():
261280
parser.add_option(
262281
'--application', dest='application',
263282
default='App-PostgresPro-{0}'.format(sys.platform.title()))
283+
parser.add_option(
284+
'--old-zabbix',
285+
dest='old_zabbix', action='store_true',
286+
help='Create special template for currently unsupported zabbix versions')
287+
# Zabbix server to send metrics
288+
parser.add_option('--zabbix-address', dest='zabbix_address', default=None)
289+
# port of Zabbix server to send metrics
290+
parser.add_option('--zabbix-port', dest='zabbix_port', default='10051')
291+
# name of the Zabbix host to send metrics
292+
parser.add_option('--zabbix-client', dest='zabbix_client', default='localhost')
293+
# path to file with metrics to send metrics
294+
parser.add_option('--zabbix-file', dest='zabbix_file', default=None)
295+
# log level to send metrics
296+
parser.add_option('--zabbix-log-level', dest='zabbix_log_level', default='INFO')
264297
return parser.parse_args()

mamonsu/lib/plugin.py

+3
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ class Plugin(object):
4242
# for all childs
4343
is_child = True
4444

45+
# old_zabbix_server_version
46+
old_zabbix = False
47+
4548
# const
4649
PATH = "/etc/zabbix/zabbix_agent.d/scripts"
4750
DELTA = Template.DELTA

mamonsu/lib/runner.py

+23-1
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,34 @@ def quit_handler(_signo=None, _stack_frame=None):
5151
from mamonsu.tools.agent.start import run_agent
5252
sys.argv.remove('agent')
5353
return run_agent()
54+
elif tool == '--send-data-zabbix':
55+
args, _ = parse_args()
56+
if not args.zabbix_address:
57+
print('To send metrics to zabbix, please, add option --zabbix-addres')
58+
exit(125)
59+
60+
if not args.zabbix_file:
61+
print ('To send metrics to zabbix, please, add option --zabbix_file')
62+
exit(123)
63+
64+
cfg = Config(args.config_file, args.plugins_dirs)
65+
cfg.config.set('zabbix','address',args.zabbix_address)
66+
cfg.config.set('zabbix','port',args.zabbix_port)
67+
cfg.config.set('zabbix', 'client', args.zabbix_client)
68+
cfg.config.set('log', 'level', args.zabbix_log_level)
69+
70+
supervisor = Supervisor(cfg)
71+
supervisor.send_file_zabbix(cfg,args.zabbix_file)
72+
exit(0)
73+
5474
elif tool == 'export':
5575
args, commands = parse_args()
5676
# get PG version
5777
version_args = args.pg_version.split('_')
5878
define_pg_version(version_args)
5979
cfg = Config(args.config_file, args.plugins_dirs)
80+
if args.old_zabbix:
81+
Plugin.old_zabbix = True
6082
if not len(commands) == 2 and not len(commands) == 3:
6183
print_total_help()
6284
if commands[1] == 'zabbix-parameters':
@@ -122,7 +144,7 @@ def quit_handler(_signo=None, _stack_frame=None):
122144
commands.append('postgrespro.xml')
123145
print('Template for mamonsu have been saved in postgrespro.conf file')
124146
for klass in Plugin.only_child_subclasses():
125-
if klass.__name__ == "PgWaitSampling": # check if plugin is for EE
147+
if klass.__name__ == "PgWaitSampling" or klass.__name__ == "Cfs" : # check if plugin is for EE
126148
if Plugin.VersionPG['type'] == 'PGEE':
127149
plugins.append(klass(cfg))
128150
else:

mamonsu/lib/senders/zbx.py

+35-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import mamonsu.lib.platform as platform
1313
from mamonsu.lib.plugin import Plugin
1414
from mamonsu.lib.queue import Queue
15-
15+
from itertools import islice
1616

1717
class ZbxSender(Plugin):
1818

@@ -64,6 +64,40 @@ def _flush(self):
6464
})
6565
self._send_data(data)
6666

67+
def send_file_to_zabbix (self,path):
68+
zabbix_client = self.config.fetch('zabbix', 'client')
69+
self.log.setLevel((self.config.fetch('log', 'level')).upper())
70+
71+
metrics = []
72+
with open(path, 'r') as f:
73+
while True:
74+
lines=list(islice(f, 100))
75+
for line in lines:
76+
try:
77+
split_line = line.rstrip('\n').split('\t')
78+
if len(split_line) == 3:
79+
metric = {
80+
'host': zabbix_client,
81+
'key': split_line[2],
82+
'value': split_line[1],
83+
'clock': int(split_line[0])}
84+
metrics.append(metric)
85+
else:
86+
self.log.error('Can\'t load metric in line: "{0}". The line must have the format: time <tab> value <tab> metric\'s name.'.format(line.rstrip('\n')))
87+
except Exception as e:
88+
self.log.error('Can\'t load metric in line: "{0}". Error : {1} '.format(line.rstrip('\n'),e,))
89+
90+
data = json.dumps({
91+
'request': 'sender data',
92+
'data': metrics,
93+
'clock': int(time.time())
94+
})
95+
self._send_data(data)
96+
self.log.info('sended {0} metrics'.format(str(len(metrics))))
97+
metrics = []
98+
if not lines:
99+
break
100+
67101
def _send_data(self, data):
68102
data_len = struct.pack('<Q', len(data))
69103
if platform.PY3:

mamonsu/lib/supervisor.py

+5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from mamonsu.lib.senders import *
77
from mamonsu.tools.agent import *
88
from mamonsu.plugins import *
9+
from mamonsu.lib.senders.zbx import ZbxSender
910

1011

1112
class Supervisor(object):
@@ -62,3 +63,7 @@ def _loop(self):
6263
else:
6364
self._sender.send('mamonsu.plugin.errors[]', '')
6465
plugin_errors, plugin_probes = 0, 0
66+
67+
def send_file_zabbix(self,cfg,path):
68+
zbxSender = ZbxSender (cfg)
69+
zbxSender.send_file_to_zabbix(path)

mamonsu/lib/zbx_template.py

+42-5
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class ZbxTemplate(object):
5555
('snmpv3_contextname', None), ('snmpv3_securityname', None),
5656
('snmpv3_securitylevel', 0), ('snmpv3_authprotocol', 0),
5757
('snmpv3_authpassphrase', None), ('snmpv3_privprotocol', 0),
58-
('snmpv3_privpassphrase', None), ('formula', 1),
58+
('snmpv3_privpassphrase', None), ('logtimefmt', None), ('formula', 1),
5959
('delay_flex', None), ('params', None),
6060
('ipmi_sensor', None), ('data_type', 0), ('authtype', 0),
6161
('username', None), ('password', None), ('publickey', None),
@@ -89,14 +89,20 @@ class ZbxTemplate(object):
8989
('calc_fnc', 2), ('type', Template.GRAPH_TYPE.normal)
9090
]
9191

92+
condition_defaults = [
93+
('macro', None), ('value', 0),
94+
('operator', None),
95+
('formulaid', None)
96+
]
97+
9298
discovery_defaults = [
9399
('name', None), ('type', 2), ('snmp_community', None),
94100
('snmp_oid', None), ('delay', 60), ('status', 0),
95101
('allowed_hosts', None), ('snmpv3_contextname', None),
96102
('snmpv3_securityname', None), ('snmpv3_securitylevel', 0),
97103
('snmpv3_authprotocol', 0), ('snmpv3_authpassphrase', None),
98104
('snmpv3_privprotocol', 0), ('snmpv3_privpassphrase', None),
99-
('delay_flex', None), ('params', None), ('filter', None),
105+
('delay_flex', None), ('params', None),
100106
('ipmi_sensor', None), ('authtype', 0),
101107
('username', None), ('password', None), ('publickey', None),
102108
('privatekey', None), ('port', None), ('lifetime', 7),
@@ -194,7 +200,23 @@ def graph(self, args={}, xml_key='graph'):
194200
self._format_args(self.graph_values_defaults, args),
195201
graph_items, xml_key)
196202

197-
def discovery_rule(self, rule={}, items=[], triggers=[], graphs=[]):
203+
# condition for template creation for zabbix version 4.4
204+
def condition(self, args={}, xml_key='condition'):
205+
try:
206+
conditions = args['condition']
207+
except KeyError:
208+
raise LookupError(
209+
'Miss item in conditions: {0}.'.format(args))
210+
res = ''
211+
for idx, item in enumerate(conditions):
212+
res += '<{1}>{0}</{1}>'.format(
213+
self._format_args(self.condition_defaults, item),
214+
xml_key)
215+
res = '<conditions>' + res + '</conditions>' + '<formula/><evaltype>0</evaltype>'
216+
217+
return res
218+
219+
def discovery_rule(self, rule={},conditions=[], items=[], triggers=[], graphs=[]):
198220

199221
result_items = '<item_prototypes>'
200222
for item in items:
@@ -214,10 +236,25 @@ def discovery_rule(self, rule={}, items=[], triggers=[], graphs=[]):
214236
graph, xml_key='graph_prototype')
215237
result_graphs += '</graph_prototypes>'
216238

217-
result = '<discovery_rule>{0}{1}{2}{3}</discovery_rule>'
239+
if len(conditions) > 0:
240+
241+
result_conditions = '<filter>'
242+
for condition in conditions:
243+
result_conditions += self.condition(
244+
condition, xml_key='condition')
245+
result_conditions += '</filter>'
246+
else:
247+
result = '<discovery_rule>{0}{1}{2}{3}</discovery_rule>'
248+
if ('filter', None) not in self.discovery_defaults:
249+
self.discovery_defaults.append(('filter', None))
250+
return result.format(
251+
self._format_args(self.discovery_defaults, rule),
252+
result_items, result_triggers, result_graphs)
253+
254+
result = '<discovery_rule>{0}{1}{2}{3}{4}</discovery_rule>'
218255
return result.format(
219256
self._format_args(self.discovery_defaults, rule),
220-
result_items, result_triggers, result_graphs)
257+
result_conditions, result_items, result_triggers, result_graphs)
221258

222259
def _application(self):
223260
result = '<applications><application><name>{0}'

mamonsu/plugins/pgsql/cfs.py

+21-6
Original file line numberDiff line numberDiff line change
@@ -159,21 +159,36 @@ def graphs(self, template):
159159
def discovery_rules(self, template):
160160
rule = {
161161
'name': 'Compressed relations discovery',
162-
'key': 'pgsql.cfs.discovery_compressed_relations[]',
163-
'filter': '{#COMPRESSED_RELATION}:.*'
162+
'key': 'pgsql.cfs.discovery_compressed_relations[]'
163+
# 'filter': '{#COMPRESSED_RELATION}:.*'
164164
}
165+
if Plugin.old_zabbix:
166+
rule['filter'] = '{#DATABASE}:.*'
167+
conditions = []
168+
else:
169+
conditions = [
170+
{
171+
'condition': [
172+
{'macro': '{#COMPRESSED_RELATION}',
173+
'value': '.*',
174+
'operator': '',
175+
'formulaid': 'A'}
176+
]
177+
}
178+
179+
]
165180
items = [
166181
{'key': 'pgsql.cfs.compress_ratio[{#COMPRESSED_RELATION}]',
167-
'name': 'Relation {#COMPRESSED_RELATION}: compress ratio',
168-
'delay': self.timeRatioInterval}
182+
'name': 'Relation {#COMPRESSED_RELATION}: compress ratio',
183+
'delay': self.timeRatioInterval}
169184
]
170185
graphs = [
171186
{
172187
'name': 'Relation {#COMPRESSED_RELATION}: compress ratio',
173188
'delay': self.timeRatioInterval,
174189
'items': [
175190
{'color': '00CC00',
176-
'key': 'pgsql.cfs.compress_ratio[{#COMPRESSED_RELATION}]'}]
191+
'key': 'pgsql.cfs.compress_ratio[{#COMPRESSED_RELATION}]'}]
177192
},
178193
]
179-
return template.discovery_rule(rule=rule, items=items, graphs=graphs)
194+
return template.discovery_rule(rule=rule, conditions=conditions, items=items, graphs=graphs)

mamonsu/plugins/pgsql/databases.py

+17-2
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,23 @@ def discovery_rules(self, template):
6464
rule = {
6565
'name': 'Database discovery',
6666
'key': self.key_db_discovery.format('[{0}]'.format(self.Macros[self.Type])),
67-
'filter': '{#DATABASE}:.*'
67+
6868
}
69+
if Plugin.old_zabbix:
70+
conditions = []
71+
rule['filter'] = '{#DATABASE}:.*'
72+
else:
73+
conditions = [
74+
{
75+
'condition': [
76+
{'macro': '{#DATABASE}',
77+
'value': '.*',
78+
'operator': '',
79+
'formulaid': 'A'}
80+
]
81+
}
82+
83+
]
6984
items = [
7085
{'key': self.right_type(self.key_db_size, var_discovery="{#DATABASE},"),
7186
'name': 'Database {#DATABASE}: size',
@@ -106,7 +121,7 @@ def discovery_rules(self, template):
106121
'yaxisside': 1}]
107122
}
108123
]
109-
return template.discovery_rule(rule=rule, items=items, graphs=graphs)
124+
return template.discovery_rule(rule=rule, conditions=conditions, items=items, graphs=graphs)
110125

111126
def keys_and_queries(self, template_zabbix):
112127
result = []

mamonsu/plugins/pgsql/driver/connection.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def _close(self):
7474
self.log.error('close error: {0}'.format(e))
7575

7676
def _connect(self):
77-
self.log.debug('connecting')
77+
self.log.info('connecting')
7878
host, unix_sock = self.host, None
7979
if host.startswith('/'):
8080
unix_sock, host = host, None
@@ -87,7 +87,7 @@ def _connect(self):
8787
database=self.db,
8888
application_name=self.appname
8989
)
90-
self.log.debug('connected')
90+
self.log.info('connected')
9191
self.conn.autocommit = True
9292
cur = self.conn.cursor()
9393
cur.execute('set statement_timeout to {0}'.format(self.timeout * 1000))

mamonsu/plugins/pgsql/driver/pool.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ class Pool(object):
3232
'select public.mamonsu_count_autovacuum()'
3333
),
3434
'buffer_cache': (
35-
"select sum(1) * 8 * 1024 as size, "
36-
" sum(case when usagecount > 1 then 1 else 0 end) * 8 * 1024 as twice_used, "
37-
" sum(case isdirty when true then 1 else 0 end) * 8 * 1024 as dirty "
35+
"select sum(1) * (current_setting('block_size')::int8) as size, "
36+
" sum(case when usagecount > 1 then 1 else 0 end) * (current_setting('block_size')::int8) as twice_used, "
37+
" sum(case isdirty when true then 1 else 0 end) * (current_setting('block_size')::int8) as dirty "
3838
" from public.pg_buffercache",
3939
'select size, twice_used, dirty from public.mamonsu_buffer_cache()'
4040
),

0 commit comments

Comments
 (0)