Compare commits
2 Commits
ebb084aa9d
...
24d1214855
| Author | SHA1 | Date | |
|---|---|---|---|
| 24d1214855 | |||
| 3c39d8aa97 |
@ -8,14 +8,21 @@ metrics:
|
|||||||
0: >
|
0: >
|
||||||
SELECT datname AS dbname
|
SELECT datname AS dbname
|
||||||
FROM pg_database
|
FROM pg_database
|
||||||
|
|
||||||
|
# Note: If the user lacks sufficient privileges, these fields will be NULL.
|
||||||
|
# The WHERE clause is intended to prevent Zabbix from discovering a
|
||||||
|
# connection it cannot monitor. Ideally this would generate an error
|
||||||
|
# instead.
|
||||||
discover_rep:
|
discover_rep:
|
||||||
type: set
|
type: set
|
||||||
query:
|
query:
|
||||||
0: >
|
0: >
|
||||||
SELECT client_addr || '_' || regexp_replace(application_name, '[ ,]', '_', 'g') AS repid,
|
SELECT host(client_addr) || '_' || regexp_replace(application_name, '[ ,]', '_', 'g') AS repid,
|
||||||
client_addr,
|
client_addr,
|
||||||
state
|
state
|
||||||
FROM pg_stat_replication
|
FROM pg_stat_replication
|
||||||
|
WHERE state IS NOT NULL
|
||||||
|
|
||||||
discover_slots:
|
discover_slots:
|
||||||
type: set
|
type: set
|
||||||
query:
|
query:
|
||||||
@ -36,6 +43,7 @@ metrics:
|
|||||||
active
|
active
|
||||||
FROM pg_replication_slots
|
FROM pg_replication_slots
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# cluster-wide metrics
|
# cluster-wide metrics
|
||||||
##
|
##
|
||||||
@ -85,7 +93,6 @@ metrics:
|
|||||||
FROM pg_stat_bgwriter bg
|
FROM pg_stat_bgwriter bg
|
||||||
CROSS JOIN pg_stat_checkpointer cp
|
CROSS JOIN pg_stat_checkpointer cp
|
||||||
|
|
||||||
|
|
||||||
io_per_backend:
|
io_per_backend:
|
||||||
type: set
|
type: set
|
||||||
query:
|
query:
|
||||||
@ -108,6 +115,7 @@ metrics:
|
|||||||
FROM pg_stat_io
|
FROM pg_stat_io
|
||||||
GROUP BY backend_type
|
GROUP BY backend_type
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Per-database metrics
|
# Per-database metrics
|
||||||
##
|
##
|
||||||
@ -210,14 +218,20 @@ metrics:
|
|||||||
# FROM pg_class c
|
# FROM pg_class c
|
||||||
# CROSS JOIN LATERAL pg_sequence_parameters(c.oid) AS s
|
# CROSS JOIN LATERAL pg_sequence_parameters(c.oid) AS s
|
||||||
# WHERE c.relkind = 'S'
|
# WHERE c.relkind = 'S'
|
||||||
100000: >
|
100000: SELECT COALESCE(MAX(last_value::float / max_value), 0) AS max_usage FROM pg_sequences;
|
||||||
SELECT COALESCE(MAX(pg_sequence_last_value(c.oid)::float / sp.maximum_value), 0) AS max_usage
|
|
||||||
FROM pg_class c
|
|
||||||
CROSS JOIN LATERAL pg_sequence_parameters(c.oid) AS sp
|
|
||||||
WHERE c.relkind = 'S'
|
|
||||||
test_args:
|
test_args:
|
||||||
dbname: postgres
|
dbname: postgres
|
||||||
|
|
||||||
|
sequence_visibility:
|
||||||
|
type: row
|
||||||
|
query:
|
||||||
|
100000: >
|
||||||
|
SELECT COUNT(*) FILTER (WHERE has_sequence_privilege(c.oid, 'SELECT,USAGE'::text)) AS readable_sequences,
|
||||||
|
COUNT(*) AS total_sequences
|
||||||
|
FROM pg_class AS c
|
||||||
|
WHERE relkind = 'S';
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Per-replication metrics
|
# Per-replication metrics
|
||||||
##
|
##
|
||||||
@ -237,7 +251,7 @@ metrics:
|
|||||||
NULL AS replay_lag,
|
NULL AS replay_lag,
|
||||||
sync_state
|
sync_state
|
||||||
FROM pg_stat_replication
|
FROM pg_stat_replication
|
||||||
WHERE client_addr || '_' || regexp_replace(application_name, '[ ,]', '_', 'g') = %(repid)s
|
WHERE host(client_addr) || '_' || regexp_replace(application_name, '[ ,]', '_', 'g') = %(repid)s
|
||||||
100000: >
|
100000: >
|
||||||
SELECT pid, usename,
|
SELECT pid, usename,
|
||||||
EXTRACT(EPOCH FROM backend_start)::integer AS backend_start,
|
EXTRACT(EPOCH FROM backend_start)::integer AS backend_start,
|
||||||
@ -250,7 +264,8 @@ metrics:
|
|||||||
COALESCE(EXTRACT(EPOCH FROM flush_lag), 0)::integer AS flush_lag,
|
COALESCE(EXTRACT(EPOCH FROM flush_lag), 0)::integer AS flush_lag,
|
||||||
COALESCE(EXTRACT(EPOCH FROM replay_lag), 0)::integer AS replay_lag,
|
COALESCE(EXTRACT(EPOCH FROM replay_lag), 0)::integer AS replay_lag,
|
||||||
sync_state
|
sync_state
|
||||||
FROM pg_stat_replication WHERE client_addr || '_' || regexp_replace(application_name, '[ ,]', '_', 'g') = %(repid)s
|
FROM pg_stat_replication
|
||||||
|
WHERE host(client_addr) || '_' || regexp_replace(application_name, '[ ,]', '_', 'g') = %(repid)s
|
||||||
test_args:
|
test_args:
|
||||||
repid: 127.0.0.1_test_rep
|
repid: 127.0.0.1_test_rep
|
||||||
|
|
||||||
@ -264,24 +279,25 @@ metrics:
|
|||||||
90400: >
|
90400: >
|
||||||
SELECT NULL as active_pid,
|
SELECT NULL as active_pid,
|
||||||
xmin,
|
xmin,
|
||||||
pg_xlog_location_diff(pg_current_xlog_location(), restart_lsn) AS restart_bytes,
|
pg_xlog_location_diff(pg_current_xlog_location(), restart_lsn)::bigint AS restart_bytes,
|
||||||
NULL AS confirmed_flush_bytes
|
NULL AS confirmed_flush_bytes
|
||||||
FROM pg_replication_slots WHERE slot_name = %(slot)s
|
FROM pg_replication_slots WHERE slot_name = %(slot)s
|
||||||
90600: >
|
90600: >
|
||||||
SELECT active_pid,
|
SELECT active_pid,
|
||||||
xmin,
|
xmin,
|
||||||
pg_xlog_location_diff(pg_current_xlog_location(), restart_lsn) AS restart_bytes,
|
pg_xlog_location_diff(pg_current_xlog_location(), restart_lsn)::bigint AS restart_bytes,
|
||||||
pg_xlog_location_diff(pg_current_xlog_location(), confirmed_flush_lsn) AS confirmed_flush_bytes
|
pg_xlog_location_diff(pg_current_xlog_location(), confirmed_flush_lsn)::bigint AS confirmed_flush_bytes
|
||||||
FROM pg_replication_slots WHERE slot_name = %(slot)s
|
FROM pg_replication_slots WHERE slot_name = %(slot)s
|
||||||
100000: >
|
100000: >
|
||||||
SELECT active_pid,
|
SELECT active_pid,
|
||||||
xmin,
|
xmin,
|
||||||
pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) AS restart_bytes,
|
pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)::bigint AS restart_bytes,
|
||||||
pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn) AS confirmed_flush_bytes
|
pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn)::bigint AS confirmed_flush_bytes
|
||||||
FROM pg_replication_slots WHERE slot_name = %(slot)s
|
FROM pg_replication_slots WHERE slot_name = %(slot)s
|
||||||
test_args:
|
test_args:
|
||||||
slot: test_slot
|
slot: test_slot
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Debugging
|
# Debugging
|
||||||
##
|
##
|
||||||
|
|||||||
16
src/pgmon.py
16
src/pgmon.py
@ -27,6 +27,8 @@ from urllib.parse import urlparse, parse_qs
|
|||||||
import requests
|
import requests
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
VERSION = "1.0.3"
|
VERSION = "1.0.3"
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
@ -391,6 +393,16 @@ def get_query(metric, version):
|
|||||||
raise MetricVersionError("Missing metric query for PostgreSQL {}".format(version))
|
raise MetricVersionError("Missing metric query for PostgreSQL {}".format(version))
|
||||||
|
|
||||||
|
|
||||||
|
def json_encode_special(obj):
|
||||||
|
"""
|
||||||
|
Encoder function to handle types the standard JSON package doesn't know what
|
||||||
|
to do with
|
||||||
|
"""
|
||||||
|
if isinstance(obj, Decimal):
|
||||||
|
return float(obj)
|
||||||
|
raise TypeError(f'Cannot serialize object of {type(obj)}')
|
||||||
|
|
||||||
|
|
||||||
def run_query_no_retry(pool, return_type, query, args):
|
def run_query_no_retry(pool, return_type, query, args):
|
||||||
"""
|
"""
|
||||||
Run the query with no explicit retry code
|
Run the query with no explicit retry code
|
||||||
@ -408,11 +420,11 @@ def run_query_no_retry(pool, return_type, query, args):
|
|||||||
elif return_type == "row":
|
elif return_type == "row":
|
||||||
if len(res) == 0:
|
if len(res) == 0:
|
||||||
return "[]"
|
return "[]"
|
||||||
return json.dumps(res[0])
|
return json.dumps(res[0], default=json_encode_special)
|
||||||
elif return_type == "column":
|
elif return_type == "column":
|
||||||
if len(res) == 0:
|
if len(res) == 0:
|
||||||
return "[]"
|
return "[]"
|
||||||
return json.dumps([list(r.values())[0] for r in res])
|
return json.dumps([list(r.values())[0] for r in res], default=json_encode_special)
|
||||||
elif return_type == "set":
|
elif return_type == "set":
|
||||||
return json.dumps(res)
|
return json.dumps(res)
|
||||||
except:
|
except:
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import tempfile
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
import pgmon
|
import pgmon
|
||||||
|
|
||||||
# Silence most logging output
|
# Silence most logging output
|
||||||
@ -789,3 +791,17 @@ metrics:
|
|||||||
# Make sure we can pull the RSS file (we assume the 9.6 series won't be getting
|
# Make sure we can pull the RSS file (we assume the 9.6 series won't be getting
|
||||||
# any more updates)
|
# any more updates)
|
||||||
self.assertEqual(pgmon.get_latest_version(), 90624)
|
self.assertEqual(pgmon.get_latest_version(), 90624)
|
||||||
|
|
||||||
|
def test_json_encode_special(self):
|
||||||
|
# Confirm that we're getting the right type
|
||||||
|
self.assertFalse(isinstance(Decimal('0.5'), float))
|
||||||
|
self.assertTrue(isinstance(pgmon.json_encode_special(Decimal('0.5')), float))
|
||||||
|
|
||||||
|
# Make sure we get sane values
|
||||||
|
self.assertEqual(pgmon.json_encode_special(Decimal('0.5')), 0.5)
|
||||||
|
self.assertEqual(pgmon.json_encode_special(Decimal('12')), 12.0)
|
||||||
|
|
||||||
|
# Make sure we can still fail for other types
|
||||||
|
self.assertRaises(
|
||||||
|
TypeError, pgmon.json_encode_special, object
|
||||||
|
)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user