|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | + |
| 3 | +from mamonsu.plugins.pgsql.plugin import PgsqlPlugin as Plugin |
| 4 | +from .pool import Pooler |
| 5 | +from mamonsu.lib.plugin import PluginDisableException |
| 6 | + |
| 7 | + |
| 8 | +class RelationsSize(Plugin): |
| 9 | + def __init__(self, config): |
| 10 | + super(Plugin, self).__init__(config) |
| 11 | + self.query = None |
| 12 | + self.key_rel_size_discovery = "pgsql.relation.size{0}" |
| 13 | + |
| 14 | + |
| 15 | + def create_query(self): |
| 16 | + query_template = """SELECT relation.schema |
| 17 | + , relation.name |
| 18 | + , CASE WHEN l.mode = 'AccessExclusiveLock' THEN '-1' |
| 19 | + ELSE (pg_total_relation_size(cl.oid)) |
| 20 | + END AS pg_total_relation_size |
| 21 | + , CASE WHEN l.mode = 'AccessExclusiveLock' THEN '-1' |
| 22 | + ELSE (sum(pg_total_relation_size(inh.inhrelid))) |
| 23 | + END AS pg_total_relation_size_part |
| 24 | +FROM (VALUES {values}) as relation (schema,name) |
| 25 | +LEFT JOIN pg_catalog.pg_class cl ON cl.relname = relation.name |
| 26 | +LEFT JOIN pg_catalog.pg_namespace ns ON ns.oid = cl.relnamespace AND ns.nspname=relation.schema |
| 27 | +LEFT JOIN pg_catalog.pg_inherits inh ON inh.inhparent = cl.oid |
| 28 | +LEFT JOIN pg_catalog.pg_locks l ON l.relation = cl.oid AND l.mode= 'AccessExclusiveLock' AND l.locktype = 'relation' |
| 29 | +LEFT JOIN pg_catalog.pg_locks l_part ON l_part.relation = inh.inhrelid AND l.mode= 'AccessExclusiveLock' AND l.locktype = 'relation' |
| 30 | +GROUP BY relation.schema |
| 31 | + , relation.name |
| 32 | + , l.mode |
| 33 | + , cl.oid""" |
| 34 | + |
| 35 | + config_relations = self._plugin_config.get('relations', None) |
| 36 | + if config_relations is None or config_relations == '': |
| 37 | + self.disable() |
| 38 | + raise PluginDisableException ("""Disable plugin and exit, because the parameter 'relations' in section [relationssize] is not set. Set this parameter like relations=pg_catalog.pg_class,pg_catalog.pg_user to count size if needed and restart.""") |
| 39 | + |
| 40 | + values = [] |
| 41 | + for relation in config_relations.split(','): |
| 42 | + tmp_rel = relation.split('.') |
| 43 | + if len(tmp_rel) == 0: |
| 44 | + pass |
| 45 | + elif len(tmp_rel) == 1: |
| 46 | + values.append("(NULL, '{relation}')".format(relation=tmp_rel[0].strip())) |
| 47 | + elif len(tmp_rel) == 2: |
| 48 | + values.append( |
| 49 | + "('{schema}', '{relation}')".format(schema=tmp_rel[0].strip(), relation=tmp_rel[1].strip())) |
| 50 | + else: |
| 51 | + self.log.error( |
| 52 | + 'The relation "{relation}" is not correct. You need to specify "schema.table" in the configuration file for mamonsu. Section: [relationssize], parameter: relations '.format( |
| 53 | + relation=relation)) |
| 54 | + |
| 55 | + self.query = query_template.format(values=',\n '.join(values)) |
| 56 | + |
| 57 | + def run(self, zbx): |
| 58 | + if not self.query: |
| 59 | + self.create_query() |
| 60 | + result = Pooler.query(self.query) |
| 61 | + rels = [] |
| 62 | + for schema, name, pg_total_relation_size, pg_total_relation_size_part in result: |
| 63 | + if not schema: |
| 64 | + full_name_relation = name |
| 65 | + else: |
| 66 | + full_name_relation = schema + '.' + name |
| 67 | + rels.append({'{#RELATIONNAME}': full_name_relation }) |
| 68 | + |
| 69 | + if pg_total_relation_size is None and pg_total_relation_size_part is None: |
| 70 | + self.log.error('The relation: "{full_name_relation}" in not correct'.format(full_name_relation = full_name_relation)) |
| 71 | + size = -1 |
| 72 | + elif pg_total_relation_size ==-1 or pg_total_relation_size_part ==-1: |
| 73 | + self.log.error( |
| 74 | + "The relation: {full_name_relation} is lock. " |
| 75 | + "You can find this lock in query: " |
| 76 | + "SELECT relation::regclass AS lock_relation, mode FROM pg_locks WHERE relation::regclass = 'pg_locks'::regclass;".format(full_name_relation=full_name_relation)) |
| 77 | + size = -1 |
| 78 | + else: |
| 79 | + size = (pg_total_relation_size or 0) + (pg_total_relation_size_part or 0) |
| 80 | + |
| 81 | + zbx.send('pgsql.relation.size[{0}]'.format(full_name_relation), int(size)) |
| 82 | + |
| 83 | + zbx.send('pgsql.relation.size[]', zbx.json({'data': rels})) |
| 84 | + |
| 85 | + |
| 86 | + def items(self, template): |
| 87 | + |
| 88 | + return '' |
| 89 | + |
| 90 | + def discovery_rules(self, template): |
| 91 | + rule = { |
| 92 | + 'name': 'Relation size discovery', |
| 93 | + 'key': self.key_rel_size_discovery.format('[{0}]'.format(self.Macros[self.Type])), |
| 94 | + } |
| 95 | + if Plugin.old_zabbix: |
| 96 | + conditions = [] |
| 97 | + rule['filter'] = '{#RELATIONNAME}:.*' |
| 98 | + else: |
| 99 | + conditions = [ |
| 100 | + { |
| 101 | + 'condition': [ |
| 102 | + {'macro': '{#RELATIONNAME}', |
| 103 | + 'value': '.*', |
| 104 | + 'operator': None, |
| 105 | + 'formulaid': 'A'} |
| 106 | + ] |
| 107 | + } |
| 108 | + ] |
| 109 | + items = [ |
| 110 | + {'key': self.right_type(self.key_rel_size_discovery, var_discovery="{#RELATIONNAME},"), |
| 111 | + 'name': 'Relation size: {#RELATIONNAME}', |
| 112 | + 'units': Plugin.UNITS.bytes, |
| 113 | + 'value_type': Plugin.VALUE_TYPE.numeric_unsigned, |
| 114 | + 'delay': self.plugin_config('interval')}, |
| 115 | + ] |
| 116 | + graphs = [ |
| 117 | + { |
| 118 | + 'name': 'PostgreSQL relation size: {#RELATIONNAME}', |
| 119 | + 'type': 1, |
| 120 | + 'items': [ |
| 121 | + {'color': '00CC00', |
| 122 | + 'key': self.right_type(self.key_rel_size_discovery, var_discovery="{#RELATIONNAME},")}] |
| 123 | + }, |
| 124 | + ] |
| 125 | + return template.discovery_rule(rule=rule, conditions=conditions, items=items, graphs=graphs) |
0 commit comments