34 Commits

Author SHA1 Message Date
39c34ee31f wip 2026-03-15 23:54:27 -04:00
65f01ea826 Implement FUSE interface using pyfuse 2026-02-04 00:36:54 -05:00
17b55d3c46 Merge branch 'dev/tmpfiles' into develop 2025-12-03 01:45:50 -05:00
9b48535a09 Add archive ready and temp file items to template
- Add the initital item definitions to the template for archive ready
  files and temp files.

- Fix the temp file query to be able to return both columns in all
  cases.
2025-12-02 01:43:24 -05:00
590425fae7 Handle situations where directories don't exist
- The pgsql_tmp and archive_ready directories don't always exist.  Since
  PG <=9.4 doesn't have the "missing_ok" parameter, we have to work
  around the missing directories explicitly.
2025-12-02 01:05:16 -05:00
174cac4ca6 Add queries for tmp and ready files 2025-11-29 02:42:04 -05:00
f740c4012d Merge branch 'main' into develop 2025-11-29 00:35:05 -05:00
c1dcc6c87b Merge branch 'rel/1.1.0' into develop 2025-11-29 00:34:17 -05:00
4fa3a7b669 Merge branch 'rel/1.1.0' 2025-11-29 00:30:33 -05:00
8182ad75b9 Fix activity query
* Modify the activity query to ensure each state is always reported.

* Fix the activity preprocessor to unwrap the value from the array
  containing it.
2025-10-18 12:49:09 -04:00
175fd85f9f Remove Debian 10
* The Debain 10 Docker image may have been removed.  Remove it from the
  list of supported distros until a source can be found.
2025-10-18 02:47:50 -04:00
e9c97d65cb Fix OEL7 and AL2 targets 2025-10-18 02:42:02 -04:00
af5d9cf186 Add Amazon Linux 2 support, prepare for PG18
* Add Amazon Linux 2 as a supported OS.

* Dynamically select the package manager for Amazon and Oracle Linux.

* Prepare for supporting PostgreSQL 18.  Specifically, the Docker image
  seems to have moved the data directory, so get that dynamically.
2025-10-18 02:11:08 -04:00
17c15e7e48 Add support for Amazon Linux 2023, bump version to 1.1.0-rc1
* Add support for packaging for Amazon Linux 2023

* Bump version to 1.1.0-rc1

* Tidy up the Makefile a bit
2025-10-18 01:00:30 -04:00
f55bcdcfae Merge branch 'dev/locks' into develop 2025-10-17 01:35:43 -04:00
e7b97a9e88 Add items to template
* Add items to the Zabbix template for:
    - Backgroubd writer / checkpoint stats
    - Lock stats
    - Connection states
2025-10-17 01:24:33 -04:00
3ade30c04a Add script to shot tempalte coverage
* Add a script to compare the defined metrics with those used in the
  Zabbix template.

* Add a Makefile target to run the above script.
2025-10-09 02:21:17 -04:00
ab039dc412 Improve test coverage
* Refactor some functions to improve unit test coverage.

* Use the "coverage" module if available along with unit tests.
2025-10-08 23:53:45 -04:00
75c5d76047 Add a metric for tracking the number of granted locks 2025-09-23 01:14:50 -04:00
43cd162313 Refactor to make pylint happy 2025-09-23 01:12:49 -04:00
29bfd07dad Run code through black 2025-07-14 01:58:08 -04:00
60589c2058 Update undiscovered item behavior 2025-07-14 01:39:57 -04:00
ea3aca3455 Filter out initial logical replication sync workers
* Slots are crated for each table during the initial sync, which only
  live for the duration of the copy for that table.

* The initial sync backend workers' names are also based on the table
  being copied.

* Filter out the above in Zabbix discovery based on application_name and
  slot_name.
2025-07-07 13:15:03 -04:00
cc71547f5f Include application_name in replication discovery data 2025-07-07 13:07:11 -04:00
107d5056d6 Merge branch 'main' into develop 2025-07-06 03:37:37 -04:00
e930178e9c Merge branch 'rel/1.0.4' 2025-07-06 03:35:39 -04:00
5afc940df8 Bump release version to 1.0.4 2025-07-06 03:35:00 -04:00
3961aa3448 Add Gentoo ebuild for 1.0.4-rc1 2025-07-06 03:32:27 -04:00
8fd57032e7 Update Makefile to support rc versions, bump version
* Support packaging RC versions for deb and rpm packages

* Bump version to 1.0.4-rc1
2025-07-06 03:28:36 -04:00
5ede7dea07 Fix package-all make target
* Fix the package-all target in the Makefile

* Remove storage of raw sequence stats
2025-07-05 12:28:36 -04:00
5ea007c3f6 Merge branch 'dev/sequences' into develop 2025-07-05 01:18:01 -04:00
7cb0f7ad40 Fix typo in activity query 2025-07-05 01:17:35 -04:00
83fa12ec54 Correct types for slot LSN lag metrics 2025-07-04 02:46:25 -04:00
98b74d9aed Add sequence metrics to Zabbix template 2025-07-04 02:45:43 -04:00
19 changed files with 2434 additions and 554 deletions

1
.gitignore vendored
View File

@@ -8,3 +8,4 @@ missing
__pycache__
venv
build
.coverage

74
GENTOO/pgmon-1.0.4.ebuild Normal file
View File

@@ -0,0 +1,74 @@
# Copyright 2024 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
EAPI=8
PYTHON_COMPAT=( python3_{6..13} )
inherit python-r1 systemd
DESCRIPTION="PostgreSQL monitoring bridge"
HOMEPAGE="None"
LICENSE="BSD"
SLOT="0"
KEYWORDS="amd64"
SRC_URI="https://code2.shh-dot-com.org/james/${PN}/releases/download/v${PV}/${P}.tar.bz2"
IUSE="-systemd"
DEPEND="
${PYTHON_DEPS}
dev-python/psycopg:2
dev-python/pyyaml
dev-python/requests
app-admin/logrotate
"
RDEPEND="${DEPEND}"
BDEPEND=""
#RESTRICT="fetch"
#S="${WORKDIR}/${PN}"
#pkg_nofetch() {
# einfo "Please download"
# einfo " - ${P}.tar.bz2"
# einfo "from ${HOMEPAGE} and place it in your DISTDIR directory."
# einfo "The file should be owned by portage:portage."
#}
src_compile() {
true
}
src_install() {
# Install init script
if ! use systemd ; then
newinitd "openrc/pgmon.initd" pgmon
newconfd "openrc/pgmon.confd" pgmon
fi
# Install systemd unit
if use systemd ; then
systemd_dounit "systemd/pgmon.service"
fi
# Install script
exeinto /usr/bin
newexe "src/pgmon.py" pgmon
# Install default config
diropts -o root -g root -m 0755
insinto /etc/pgmon
doins "sample-config/pgmon.yml"
doins "sample-config/pgmon-metrics.yml"
# Install logrotate config
insinto /etc/logrotate.d
newins "logrotate/pgmon.logrotate" pgmon
# Install man page
doman manpages/pgmon.1
}

View File

@@ -0,0 +1,74 @@
# Copyright 2024 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
EAPI=8
PYTHON_COMPAT=( python3_{6..13} )
inherit python-r1 systemd
DESCRIPTION="PostgreSQL monitoring bridge"
HOMEPAGE="None"
LICENSE="BSD"
SLOT="0"
KEYWORDS="amd64"
SRC_URI="https://code2.shh-dot-com.org/james/${PN}/releases/download/v${PV}/${P}.tar.bz2"
IUSE="-systemd"
DEPEND="
${PYTHON_DEPS}
dev-python/psycopg:2
dev-python/pyyaml
dev-python/requests
app-admin/logrotate
"
RDEPEND="${DEPEND}"
BDEPEND=""
#RESTRICT="fetch"
#S="${WORKDIR}/${PN}"
#pkg_nofetch() {
# einfo "Please download"
# einfo " - ${P}.tar.bz2"
# einfo "from ${HOMEPAGE} and place it in your DISTDIR directory."
# einfo "The file should be owned by portage:portage."
#}
src_compile() {
true
}
src_install() {
# Install init script
if ! use systemd ; then
newinitd "openrc/pgmon.initd" pgmon
newconfd "openrc/pgmon.confd" pgmon
fi
# Install systemd unit
if use systemd ; then
systemd_dounit "systemd/pgmon.service"
fi
# Install script
exeinto /usr/bin
newexe "src/pgmon.py" pgmon
# Install default config
diropts -o root -g root -m 0755
insinto /etc/pgmon
doins "sample-config/pgmon.yml"
doins "sample-config/pgmon-metrics.yml"
# Install logrotate config
insinto /etc/logrotate.d
newins "logrotate/pgmon.logrotate" pgmon
# Install man page
doman manpages/pgmon.1
}

228
Makefile
View File

@@ -3,7 +3,29 @@ PACKAGE_NAME := pgmon
SCRIPT := src/$(PACKAGE_NAME).py
VERSION := $(shell grep -m 1 '^VERSION = ' "$(SCRIPT)" | sed -ne 's/.*"\(.*\)".*/\1/p')
# Figure out the version components
# Note: The release is for RPM packages, where prerelease releases are written as 0.<release>
FULL_VERSION := $(shell grep -m 1 '^VERSION = ' "$(SCRIPT)" | sed -ne 's/.*"\(.*\)".*/\1/p')
VERSION := $(shell echo $(FULL_VERSION) | sed -n 's/\(.*\)\(-rc.*\|$$\)/\1/p')
RELEASE := $(shell echo $(FULL_VERSION) | sed -n 's/.*-rc\([0-9]\+\)$$/\1/p')
# Package version formatting
ifeq ($(RELEASE),)
RPM_RELEASE := 1
RPM_VERSION := $(VERSION)-$(RPM_RELEASE)
DEB_VERSION := $(VERSION)
else
RPM_RELEASE := 0.$(RELEASE)
RPM_VERSION := $(VERSION)-$(RPM_RELEASE)
DEB_VERSION := $(VERSION)~rc$(RELEASE)
endif
# Python stuff
PYTHON ?= python3
PYLINT ?= pylint
BLACK ?= black
HAVE_COVERAGE := $(shell $(PYTHON) -c 'import coverage' 2>/dev/null && echo yes)
# Where packages are built
BUILD_DIR := build
@@ -12,64 +34,77 @@ BUILD_DIR := build
SUPPORTED := ubuntu-20.04 \
ubuntu-22.04 \
ubuntu-24.04 \
debian-10 \
debian-11 \
debian-12 \
debian-13 \
rockylinux-8 \
rockylinux-9 \
rockylinux-10 \
oraclelinux-7 \
amazonlinux-2 \
amazonlinux-2023 \
gentoo
##
# These targets are the main ones to use for most things.
##
.PHONY: all clean tgz test query-tests install-common install-openrc install-systemd
.PHONY: all clean tgz lint format test query-tests template-coverage
all: package-all
# Build all packages
.PHONY: package-all
all: $(foreach distro_release, $(SUPPORTED), package-$(distro_release))
# Gentoo package (tar.gz) creation
.PHONY: package-gentoo
package-gentoo:
mkdir -p $(BUILD_DIR)/gentoo
tar --transform "s,^,$(PACKAGE_NAME)-$(VERSION)/," -acjf $(BUILD_DIR)/gentoo/$(PACKAGE_NAME)-$(VERSION).tar.bz2 --exclude .gitignore $(shell git ls-tree --full-tree --name-only -r HEAD)
# Create a deb package
.PHONY: package-%
package-%: PARTS=$(subst -, ,$*)
package-%: DISTRO=$(word 1, $(PARTS))
package-%: RELEASE=$(word 2, $(PARTS))
package-%:
mkdir -p $(BUILD_DIR)
docker run --rm \
-v .:/src:ro \
-v ./$(BUILD_DIR):/output \
--user $(shell id -u):$(shell id -g) \
"$(DISTRO)-packager:$(RELEASE)"
# Create a tarball
tgz:
rm -rf $(BUILD_DIR)/tgz/root
mkdir -p $(BUILD_DIR)/tgz/root
$(MAKE) install-openrc DESTDIR=$(BUILD_DIR)/tgz/root
tar -cz -f $(BUILD_DIR)/tgz/$(PACKAGE_NAME)-$(VERSION).tgz -C $(BUILD_DIR)/tgz/root .
# Dump information related to the current version
version:
@echo "full version=$(FULL_VERSION) version=$(VERSION) rel=$(RELEASE) rpm=$(RPM_VERSION) deb=$(DEB_VERSION)"
# Clean up the build directory
clean:
rm -rf $(BUILD_DIR)
# Run unit tests for the script
# Check for lint
lint:
$(PYLINT) src/pgmon.py
$(PYLINT) src/test_pgmon.py
$(BLACK) --check --diff src/pgmon.py
$(BLACK) --check --diff src/test_pgmon.py
# Format the code using black
format:
$(BLACK) src/pgmon.py
$(BLACK) src/test_pgmon.py
# Run unit tests for the script (with coverage if it's available)
test:
cd src ; python3 -m unittest
ifeq ($(HAVE_COVERAGE),yes)
cd src ; $(PYTHON) -m coverage run -m unittest && python3 -m coverage report -m
else
cd src ; $(PYTHON) -m unittest
endif
# Run query tests
query-tests:
cd tests ; ./run-tests.sh
# Compare the sample metrics with the Zabbix template
template-coverage:
$(PYTHON) zabbix_templates/coverage.py sample-config/pgmon-metrics.yml zabbix_templates/pgmon_templates.yaml
# Create a tarball (openrc version)
tgz:
rm -rf $(BUILD_DIR)/tgz/root
mkdir -p $(BUILD_DIR)/tgz/root
$(MAKE) install-openrc DESTDIR=$(BUILD_DIR)/tgz/root
tar -cz -f $(BUILD_DIR)/tgz/$(PACKAGE_NAME)-$(FULL_VERSION).tgz -C $(BUILD_DIR)/tgz/root .
##
# Install targets
#
# These are mostly used by the various package building images to actually install the script
##
# Install the script at the specified base directory (common components)
.PHONY: install-common
install-common:
# Set up directories
mkdir -p $(DESTDIR)/etc/$(PACKAGE_NAME)
@@ -92,6 +127,7 @@ install-common:
cp logrotate/${PACKAGE_NAME}.logrotate ${DESTDIR}/etc/logrotate.d/${PACKAGE_NAME}
# Install for systemd
.PHONY: install-systemd
install-systemd:
# Install the common stuff
$(MAKE) install-common
@@ -103,6 +139,7 @@ install-systemd:
cp systemd/* $(DESTDIR)/lib/systemd/system/
# Install for open-rc
.PHONY: install-openrc
install-openrc:
# Install the common stuff
$(MAKE) install-common
@@ -119,46 +156,93 @@ install-openrc:
cp openrc/pgmon.confd $(DESTDIR)/etc/conf.d/pgmon
# Run all of the install tests
.PHONY: install-tests debian-%-install-test rockylinux-%-install-test ubuntu-%-install-test gentoo-install-test
install-tests: $(foreach distro_release, $(SUPPORTED), $(distro_release)-install-test)
##
# Packaging targets
#
# These targets create packages for the supported distro versions
##
# Build all packages
.PHONY: package-all
package-all: all-package-images $(foreach distro_release, $(SUPPORTED), package-$(distro_release))
# Gentoo package (tar.bz2) creation
.PHONY: package-gentoo
package-gentoo:
mkdir -p $(BUILD_DIR)/gentoo
tar --transform "s,^,$(PACKAGE_NAME)-$(FULL_VERSION)/," -acjf $(BUILD_DIR)/gentoo/$(PACKAGE_NAME)-$(FULL_VERSION).tar.bz2 --exclude .gitignore $(shell git ls-tree --full-tree --name-only -r HEAD)
cp $(BUILD_DIR)/gentoo/$(PACKAGE_NAME)-$(FULL_VERSION).tar.bz2 $(BUILD_DIR)/
# Create a deb/rpm package
.PHONY: package-%
package-%: PARTS=$(subst -, ,$*)
package-%: DISTRO=$(word 1, $(PARTS))
package-%: RELEASE=$(word 2, $(PARTS))
package-%:
mkdir -p $(BUILD_DIR)
docker run --rm \
-v .:/src:ro \
-v ./$(BUILD_DIR):/output \
--user $(shell id -u):$(shell id -g) \
"$(DISTRO)-packager:$(RELEASE)"
##
# Install test targets
#
# These targets test installing the package on the supported distro versions
##
# Run all of the install tests
.PHONY: install-tests debian-%-install-test rockylinux-%-install-test ubuntu-%-install-test amazonlinux-%-install-test gentoo-install-test
install-tests: $(foreach distro_release, $(SUPPORTED), $(distro_release)-install-test)
# Run a Debian install test
debian-%-install-test:
docker run --rm \
-v ./$(BUILD_DIR):/output \
debian:$* \
bash -c 'apt-get update && apt-get install -y /output/$(PACKAGE_NAME)-$(VERSION)-debian-$*.deb'
bash -c 'apt-get update && apt-get install -y /output/$(PACKAGE_NAME)-$(DEB_VERSION)-debian-$*.deb'
# Run a RedHat install test
rockylinux-%-install-test:
docker run --rm \
-v ./$(BUILD_DIR):/output \
rockylinux:$* \
bash -c 'dnf makecache && dnf install -y /output/$(PACKAGE_NAME)-$(VERSION)-1.el$*.noarch.rpm'
rockylinux/rockylinux:$* \
bash -c 'dnf makecache && dnf install -y /output/$(PACKAGE_NAME)-$(RPM_VERSION).el$*.noarch.rpm'
# Run an Ubuntu install test
ubuntu-%-install-test:
docker run --rm \
-v ./$(BUILD_DIR):/output \
ubuntu:$* \
bash -c 'apt-get update && apt-get install -y /output/$(PACKAGE_NAME)-$(VERSION)-ubuntu-$*.deb'
bash -c 'apt-get update && apt-get install -y /output/$(PACKAGE_NAME)-$(DEB_VERSION)-ubuntu-$*.deb'
# Run an OracleLinux install test (this is for EL7 since CentOS7 images no longer exist)
oraclelinux-%-install-test: MGR=$(intcmp $*, 7, yum, yum, dnf)
oraclelinux-%-install-test:
docker run --rm \
-v ./$(BUILD_DIR):/output \
oraclelinux:7 \
bash -c 'yum makecache && yum install -y /output/$(PACKAGE_NAME)-$(VERSION)-1.el7.noarch.rpm'
oraclelinux:$* \
bash -c '$(MGR) makecache && $(MGR) install -y /output/$(PACKAGE_NAME)-$(RPM_VERSION).el7.noarch.rpm'
# Run a Amazon Linux install test
# Note: AL2 is too old for dnf
amazonlinux-%-install-test: MGR=$(intcmp $*, 2, yum, yum, dnf)
amazonlinux-%-install-test:
docker run --rm \
-v ./$(BUILD_DIR):/output \
amazonlinux:$* \
bash -c '$(MGR) makecache && $(MGR) install -y /output/$(PACKAGE_NAME)-$(RPM_VERSION).amzn$*.noarch.rpm'
# Run a Gentoo install test
gentoo-install-test:
# May impliment this in the future, but would require additional headaches to set up a repo
true
echo "This would take a while ... skipping for now"
##
# Container targets
# Packaging image targets
#
# These targets build the docker images used to create packages
##
@@ -167,6 +251,11 @@ gentoo-install-test:
.PHONY: all-package-images
all-package-images: $(foreach distro_release, $(SUPPORTED), package-image-$(distro_release))
# Nothing needs to be created to build te tarballs for Gentoo
.PHONY: package-image-gentoo
package-image-gentoo:
echo "Noting to do"
# Generic target for creating images that actually build the packages
# The % is expected to be: distro-release
# The build/.package-image-% target actually does the work and touches a state file to avoid excessive building
@@ -182,38 +271,63 @@ package-image-%:
# Inside-container targets
#
# These targets are used inside containers. They expect the repo to be mounted
# at /src and the package manager specific build directory to be mounted at
# /output.
# at /src and the build directory to be mounted at /output.
##
.PHONY: actually-package-debian-% actually-package-rockylinux-% actually-package-ubuntu-% actually-package-oraclelinux-%
.PHONY: actually-package-debian-% actually-package-rockylinux-% actually-package-ubuntu-% actually-package-oraclelinux-% actually-package-amazonlinux-%
# Debian package creation
actually-package-debian-%:
$(MAKE) install-systemd DESTDIR=/output/debian-$*
cp -r --preserve=mode DEBIAN /output/debian-$*/
dpkg-deb -Zgzip --build /output/debian-$* "/output/$(PACKAGE_NAME)-$(VERSION)-debian-$*.deb"
dpkg-deb -Zgzip --build /output/debian-$* "/output/$(PACKAGE_NAME)-$(DEB_VERSION)-debian-$*.deb"
# RedHat package creation
actually-package-rockylinux-%:
mkdir -p /output/rockylinux-$*/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
sed -e "s/@@VERSION@@/$(VERSION)/g" RPM/$(PACKAGE_NAME).spec > /output/rockylinux-$*/SPECS/$(PACKAGE_NAME).spec
sed -e "s/@@VERSION@@/$(VERSION)/g" -e "s/@@RELEASE@@/$(RPM_RELEASE)/g" RPM/$(PACKAGE_NAME).spec > /output/rockylinux-$*/SPECS/$(PACKAGE_NAME).spec
rpmbuild --define '_topdir /output/rockylinux-$*' \
--define 'version $(VERSION)' \
--define 'version $(RPM_VERSION)' \
-bb /output/rockylinux-$*/SPECS/$(PACKAGE_NAME).spec
cp /output/rockylinux-$*/RPMS/noarch/$(PACKAGE_NAME)-$(VERSION)-1.el$*.noarch.rpm /output/
cp /output/rockylinux-$*/RPMS/noarch/$(PACKAGE_NAME)-$(RPM_VERSION).el$*.noarch.rpm /output/
# Ubuntu package creation
actually-package-ubuntu-%:
$(MAKE) install-systemd DESTDIR=/output/ubuntu-$*
cp -r --preserve=mode DEBIAN /output/ubuntu-$*/
dpkg-deb -Zgzip --build /output/ubuntu-$* "/output/$(PACKAGE_NAME)-$(VERSION)-ubuntu-$*.deb"
dpkg-deb -Zgzip --build /output/ubuntu-$* "/output/$(PACKAGE_NAME)-$(DEB_VERSION)-ubuntu-$*.deb"
# OracleLinux package creation
# Note: This needs to work inside OEL7, so we can't use intcmp
actually-package-oraclelinux-7:
mkdir -p /output/oraclelinux-7/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
sed -e "s/@@VERSION@@/$(VERSION)/g" -e "s/@@RELEASE@@/$(RPM_RELEASE)/g" RPM/$(PACKAGE_NAME)-el7.spec > /output/oraclelinux-7/SPECS/$(PACKAGE_NAME).spec
rpmbuild --define '_topdir /output/oraclelinux-7' \
--define 'version $(RPM_VERSION)' \
-bb /output/oraclelinux-7/SPECS/$(PACKAGE_NAME).spec
cp /output/oraclelinux-7/RPMS/noarch/$(PACKAGE_NAME)-$(RPM_VERSION).el7.noarch.rpm /output/
actually-package-oraclelinux-%:
mkdir -p /output/oraclelinux-$*/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
sed -e "s/@@VERSION@@/$(VERSION)/g" RPM/$(PACKAGE_NAME)-el7.spec > /output/oraclelinux-$*/SPECS/$(PACKAGE_NAME).spec
sed -e "s/@@VERSION@@/$(VERSION)/g" -e "s/@@RELEASE@@/$(RPM_RELEASE)/g" RPM/$(PACKAGE_NAME).spec > /output/oraclelinux-$*/SPECS/$(PACKAGE_NAME).spec
rpmbuild --define '_topdir /output/oraclelinux-$*' \
--define 'version $(VERSION)' \
--define 'version $(RPM_VERSION)' \
-bb /output/oraclelinux-$*/SPECS/$(PACKAGE_NAME).spec
cp /output/oraclelinux-$*/RPMS/noarch/$(PACKAGE_NAME)-$(VERSION)-1.el$*.noarch.rpm /output/
cp /output/oraclelinux-$*/RPMS/noarch/$(PACKAGE_NAME)-$(RPM_VERSION).el$*.noarch.rpm /output/
# Amazon Linux package creation
# Note: This needs to work inside AL2, so we can't use intcmp
actually-package-amazonlinux-2:
mkdir -p /output/amazonlinux-2/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
sed -e "s/@@VERSION@@/$(VERSION)/g" -e "s/@@RELEASE@@/$(RPM_RELEASE)/g" RPM/$(PACKAGE_NAME)-el7.spec > /output/amazonlinux-2/SPECS/$(PACKAGE_NAME).spec
rpmbuild --define '_topdir /output/amazonlinux-2' \
--define 'version $(RPM_VERSION)' \
-bb /output/amazonlinux-2/SPECS/$(PACKAGE_NAME).spec
cp /output/amazonlinux-2/RPMS/noarch/$(PACKAGE_NAME)-$(RPM_VERSION).amzn2.noarch.rpm /output/
actually-package-amazonlinux-%:
mkdir -p /output/amazonlinux-$*/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
sed -e "s/@@VERSION@@/$(VERSION)/g" -e "s/@@RELEASE@@/$(RPM_RELEASE)/g" RPM/$(PACKAGE_NAME).spec > /output/amazonlinux-$*/SPECS/$(PACKAGE_NAME).spec
rpmbuild --define '_topdir /output/amazonlinux-$*' \
--define 'version $(RPM_VERSION)' \
-bb /output/amazonlinux-$*/SPECS/$(PACKAGE_NAME).spec
cp /output/amazonlinux-$*/RPMS/noarch/$(PACKAGE_NAME)-$(RPM_VERSION).amzn$*.noarch.rpm /output/

View File

@@ -1,6 +1,6 @@
Name: pgmon
Version: @@VERSION@@
Release: 1%{?dist}
Release: @@RELEASE@@%{?dist}
Summary: A bridge to sit between monitoring tools and PostgreSQL
License: MIT

View File

@@ -1,6 +1,6 @@
Name: pgmon
Version: @@VERSION@@
Release: 1%{?dist}
Release: @@RELEASE@@%{?dist}
Summary: A bridge to sit between monitoring tools and PostgreSQL
License: MIT

View File

@@ -0,0 +1,22 @@
# Dockerfile.rpm
ARG DISTRO=amazonlinux
ARG RELEASE=2023
FROM ${DISTRO}:${RELEASE}
ARG DISTRO
ARG RELEASE
RUN if [ ${RELEASE} -le 2 ] ; then MGR=yum ; else MGR=dnf ; fi && \
${MGR} install -y \
rpm-build \
make \
&& ${MGR} clean all
RUN echo -e "#!/bin/bash\nmake actually-package-${DISTRO}-${RELEASE}" > /init.sh \
&& chmod 755 /init.sh
WORKDIR /src
CMD ["/bin/bash", "/init.sh"]

View File

@@ -8,11 +8,12 @@ FROM ${DISTRO}:${RELEASE}
ARG DISTRO
ARG RELEASE
RUN yum install -y \
RUN if [ ${RELEASE} -le 7 ] ; then MGR=yum ; else MGR=dnf ; fi && \
${MGR} install -y \
rpm-build \
make \
oracle-epel-release-el7 \
&& yum clean all
oracle-epel-release-el${RELEASE} \
&& ${MGR} clean all
RUN echo -e "#!/bin/bash\nmake actually-package-${DISTRO}-${RELEASE}" > /init.sh \
&& chmod 755 /init.sh

View File

@@ -3,7 +3,7 @@
ARG DISTRO=rockylinux
ARG RELEASE=9
FROM ${DISTRO}:${RELEASE}
FROM rockylinux/${DISTRO}:${RELEASE}
ARG DISTRO
ARG RELEASE

4
pylintrc Normal file
View File

@@ -0,0 +1,4 @@
[MASTER]
py-version=3.5
disable=fixme

View File

@@ -1,2 +1,4 @@
psycopg
psycopg2
pyyaml
llfuse
requests

View File

@@ -18,6 +18,7 @@ metrics:
query:
0: >
SELECT host(client_addr) || '_' || regexp_replace(application_name, '[ ,]', '_', 'g') AS repid,
application_name,
client_addr,
state
FROM pg_stat_replication
@@ -115,6 +116,63 @@ metrics:
FROM pg_stat_io
GROUP BY backend_type
temp_files:
type: row
query:
120000: >
SELECT count(*) AS count,
coalesce(sum(size), 0) AS size
FROM pg_ls_tmpdir()
WHERE name LIKE 'pgsql_tmp%%'
90500: >
SELECT count(*) AS count,
coalesce(sum((pg_stat_file(name)).size), 0) AS size
FROM pg_ls_dir('base/pgsql_tmp/', true, false) AS name
WHERE name LIKE 'pgsql_tmp%%'
0: >
SELECT count(*) AS count,
coalesce(sum((pg_stat_file(files.name)).size), 0) AS size
FROM (
SELECT name
FROM pg_ls_dir('base') AS name
WHERE name = 'pgsql_tmp') AS dir
LEFT JOIN (
SELECT name
FROM pg_ls_dir('base/pgsql_tmp/') AS name
WHERE name LIKE 'pgsql_tmp%%') AS files
ON dir.name IS NOT NULL
ready_archive_files:
type: value
query:
120000: >
SELECT count(*) AS count
FROM pg_ls_archive_statusdir()
WHERE name LIKE '%%.ready'
100000: >
SELECT count(*) AS count
FROM pg_ls_dir('pg_wal/archive_status/', true, false) AS name
WHERE name LIKE '%%.ready'
90500: >
SELECT count(*) AS count
FROM pg_ls_dir('pg_xlog/archive_status/', true, false) AS name
WHERE name LIKE '%%.ready'
0: >
SELECT
CASE WHEN (
SELECT count(*)
FROM pg_ls_dir('pg_xlog/') AS f
WHERE f = 'archive_status') = 0
THEN (
SELECT 0 AS count
)
ELSE (
SELECT count(*) AS count
FROM pg_ls_dir('pg_xlog/archive_status/') AS name
WHERE name LIKE '%%.ready')
END
##
# Per-database metrics
@@ -195,12 +253,28 @@ metrics:
type: set
query:
0: >
SELECT state,
count(*) AS backend_count,
COALESCE(EXTRACT(EPOCH FROM max(now() - state_change)) 0) AS max_state_time
FROM pg_stat_activity
WHERE datname = %(dbname)s
GROUP BY state
SELECT
states.state,
COALESCE(a.backend_count, 0) AS backend_count,
COALESCE(a.max_state_time, 0) AS max_state_time
FROM (
SELECT state,
count(*) AS backend_count,
COALESCE(EXTRACT(EPOCH FROM now() - min(state_change)), 0) AS max_state_time
FROM pg_stat_activity
WHERE datname = %(dbname)s
GROUP BY state
) AS a
RIGHT JOIN
unnest(ARRAY[
'active',
'idle',
'idle in transaction',
'idle in transaction (aborted)',
'fastpath function call',
'disabled'
]) AS states(state)
USING (state);
test_args:
dbname: postgres
@@ -226,10 +300,22 @@ metrics:
type: row
query:
100000: >
SELECT COUNT(*) FILTER (WHERE has_sequence_privilege(c.oid, 'SELECT,USAGE')) AS readable_sequences,
SELECT COUNT(*) FILTER (WHERE has_sequence_privilege(c.oid, 'SELECT,USAGE')) AS visible_sequences,
COUNT(*) AS total_sequences
FROM pg_class AS c
WHERE relkind = 'S';
WHERE relkind = 'S'
locks:
type: row
query:
0: >
SELECT COUNT(*) AS total,
SUM(CASE WHEN granted THEN 1 ELSE 0 END) AS granted
FROM pg_locks
90400: >
SELECT COUNT(*) AS total,
COUNT(*) FILTER (WHERE granted) AS granted
FROM pg_locks
##
@@ -305,3 +391,5 @@ metrics:
type: value
query:
0: SELECT count(*) AS ntables FROM pg_stat_user_tables
#sequence_usage:

View File

@@ -1,8 +1,22 @@
# The address the agent binds to
#address: 127.0.0.1
# # The name for this agent instance (controles the FUSE directory name)
#name: pgmon
# The port the agent listens on for requests
#port: 5400
# Mode to set on FUSE files (in octal)
#fuse_mode: 0o400
# Owner to set on FUSE files
#fuse_owner: zabbix
fuse_owner: james
# Group to set on FUSE files
#fuse_group: zabbix
fuse_group: james
# User the agent runs as
agent_user: james
# Groupthe agent runs as
agent_group: james
# Min PostgreSQL connection pool size (per database)
#min_pool_size: 0
@@ -16,21 +30,28 @@
# Log level for stderr logging (see https://docs.python.org/3/library/logging.html#logging-levels)
# Possible values are: debug, info, warning, error, critical
#log_level: 'error'
log_level: 'info'
# Base directory for FUSE file system
fuse_base: /tmp/pgmon
# Database user to connect as
#dbuser: 'postgres'
# Database host
#dbhost: '/var/run/postgresql'
dbhost: 127.0.0.1
# Database port
#dbport: 5432
dbport: 54315
# Default database to connect to when none is specified for a metric
#dbname: 'postgres'
# SSL connection mode
#ssl_mode: require
ssl_mode: allow
# Timeout for getting a connection slot from a pool
#pool_slot_timeout: 5

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -20,7 +20,7 @@ services:
POSTGRES_PASSWORD: secret
healthcheck:
#test: [ "CMD", "pg_isready", "-U", "postgres" ]
test: [ "CMD-SHELL", "pg_controldata /var/lib/postgresql/data/ | grep -q 'in production'" ]
test: [ "CMD-SHELL", "pg_controldata $(psql -At -U postgres -c 'show data_directory') | grep -q 'in production'" ]
interval: 5s
timeout: 2s
retries: 40

View File

@@ -24,6 +24,7 @@ images["14"]='14-bookworm'
images["15"]='15-bookworm'
images["16"]='16-bookworm'
images["17"]='17-bookworm'
images["18"]='18-trixie'
declare -A results=()

129
zabbix_templates/coverage.py Executable file
View File

@@ -0,0 +1,129 @@
#!/usr/bin/env python3
# Compare the items defined in a Zabbix template with the metrics defined in a config file.
import sys
import yaml
# Special built in metrics
SPECIAL = {
"agent_version",
"latest_version_info"
}
class NonMetricItemError(Exception):
"""
A given item does not directly use a metric
"""
def read_metrics(file):
"""
Read the metrics from a config file and return the list of names
params:
file: the name of the file to read
returns:
list of metric named defined in the file
raises:
yaml.parser.ParserError: invalid yaml file
"""
names = set()
config = None
with open(file, "r", encoding="utf-8") as f:
config = yaml.safe_load(f)
try:
for m in config["metrics"].keys():
names.add(m)
except KeyError:
pass
return names
def extract_metric(item):
"""
Extract the metric from an item definition
params:
item: the item/discovery/prototype definition dict
returns:
the name of the metric used in the item
raises:
NonMetricItemError: the item does not directly use a metric
"""
try:
if item["type"] == "HTTP_AGENT":
url = item["url"]
if url.startswith("http://localhost:{$AGENT_PORT}"):
return url.split("/")[-1]
except KeyError:
raise NonMetricItemError()
raise NonMetricItemError()
def read_template(file):
"""
Read the items from a Zabbix template and return the list of metric names
params:
file: the name of the file to read
returns:
list of metric named used in the file
raises:
yaml.parser.ParserError: invalid yaml file
"""
names = set()
config = None
with open(file, "r", encoding="utf-8") as f:
config = yaml.safe_load(f)
try:
for template in config["zabbix_export"]["templates"]:
for item in template["items"]:
try:
names.add(extract_metric(item))
except NonMetricItemError:
pass
for rule in template["discovery_rules"]:
try:
names.add(extract_metric(rule))
except NonMetricItemError:
pass
for proto in rule["item_prototypes"]:
try:
names.add(extract_metric(proto))
except NonMetricItemError:
pass
except KeyError:
pass
return names
if __name__ == '__main__':
config_file = sys.argv[1]
config_metrics = read_metrics(config_file)
template_file = sys.argv[2]
template_metrics = read_template(template_file) - SPECIAL
config_only = config_metrics - template_metrics
template_only = template_metrics - config_metrics
print("Config only: {}".format(sorted(list(config_only))))
print("Template only: {}".format(sorted(list(template_only))))

View File

@@ -49,6 +49,206 @@ zabbix_export:
tags:
- tag: Application
value: PostgreSQL
- uuid: 1dd74025ca0e463bb9eee5cb473f30db
name: 'Total buffers allocated'
type: DEPENDENT
key: 'pgmon.bgwriter[buffers_alloc,total]'
delay: '0'
history: 90d
description: 'Total number of shared buffers that have been allocated'
preprocessing:
- type: JSONPATH
parameters:
- $.buffers_alloc
master_item:
key: 'pgmon[bgwriter]'
tags:
- tag: Application
value: PostgreSQL
- uuid: 4ab405996e71444a8113b95c65d73be2
name: 'Total buffers written by backends'
type: DEPENDENT
key: 'pgmon.bgwriter[buffers_backend,total]'
delay: '0'
history: 90d
description: 'Total number of shared buffers written by backends'
preprocessing:
- type: JSONPATH
parameters:
- $.buffers_backend
master_item:
key: 'pgmon[bgwriter]'
tags:
- tag: Application
value: PostgreSQL
- uuid: e8b440a1d6ff4ca6b3cb27e2e76f9d06
name: 'Total number of fsyncs from backends'
type: DEPENDENT
key: 'pgmon.bgwriter[buffers_backend_fsync,total]'
delay: '0'
history: 90d
description: 'Total number of times backends have issued their own fsync calls'
preprocessing:
- type: JSONPATH
parameters:
- $.buffers_backend_fsync
master_item:
key: 'pgmon[bgwriter]'
tags:
- tag: Application
value: PostgreSQL
- uuid: f8a14885edf34b5cbf2e92432e8fa4c2
name: 'Total buffers written during checkpoints'
type: DEPENDENT
key: 'pgmon.bgwriter[buffers_checkpoint,total]'
delay: '0'
history: 90d
description: 'Total number of shared buffers written during checkpoints'
preprocessing:
- type: JSONPATH
parameters:
- $.buffers_checkpoint
master_item:
key: 'pgmon[bgwriter]'
tags:
- tag: Application
value: PostgreSQL
- uuid: f09956f7aaad4b99b0d67339edf26dcf
name: 'Total buffers written by the background writer'
type: DEPENDENT
key: 'pgmon.bgwriter[buffers_clean,total]'
delay: '0'
history: 90d
description: 'Total number of shared buffers written by the background writer'
preprocessing:
- type: JSONPATH
parameters:
- $.buffers_clean
master_item:
key: 'pgmon[bgwriter]'
tags:
- tag: Application
value: PostgreSQL
- uuid: f1c6bd9346b14964bd492d7ccf8baf50
name: 'Total checkpoints due to changes'
type: DEPENDENT
key: 'pgmon.bgwriter[checkpoints_changes,total]'
delay: '0'
history: 90d
description: 'Total number of checkpoints that have occurred due to the number of row changes'
preprocessing:
- type: JSONPATH
parameters:
- $.checkpoints_req
master_item:
key: 'pgmon[bgwriter]'
tags:
- tag: Application
value: PostgreSQL
- uuid: 04c4587d2f2f4f5fbad866d70938cbb3
name: 'Total checkpoints due to time limit'
type: DEPENDENT
key: 'pgmon.bgwriter[checkpoints_timed,total]'
delay: '0'
history: 90d
description: 'Total number of checkpoints that have occurred due to the configured time limit'
preprocessing:
- type: JSONPATH
parameters:
- $.checkpoints_timed
master_item:
key: 'pgmon[bgwriter]'
tags:
- tag: Application
value: PostgreSQL
- uuid: 580a7e632b644aafa1166c534185ba92
name: 'Total time spent syncing files for checkpoints'
type: DEPENDENT
key: 'pgmon.bgwriter[checkpoint_sync_time,total]'
delay: '0'
history: 90d
units: s
description: 'Total time spent syncing files for checkpoints'
preprocessing:
- type: JSONPATH
parameters:
- $.checkpoint_sync_time
- type: MULTIPLIER
parameters:
- '0.001'
master_item:
key: 'pgmon[bgwriter]'
tags:
- tag: Application
value: PostgreSQL
- uuid: 4faa33b55fae4fc68561020636573a46
name: 'Total time spent writing checkpoints'
type: DEPENDENT
key: 'pgmon.bgwriter[checkpoint_write_time,total]'
delay: '0'
history: 90d
units: s
description: 'Total time spent writing checkpoints'
preprocessing:
- type: JSONPATH
parameters:
- $.checkpoint_write_time
- type: MULTIPLIER
parameters:
- '0.001'
master_item:
key: 'pgmon[bgwriter]'
tags:
- tag: Application
value: PostgreSQL
- uuid: c0c829c6cdc046a4b5d216e10362e4bb
name: 'Total number of times the background writer stopped'
type: DEPENDENT
key: 'pgmon.bgwriter[maxwritten_clean,total]'
delay: '0'
history: 90d
description: 'Total number of times the background writer stopped due to reaching the maximum number of buffers it''s allowed to write in a single scan'
preprocessing:
- type: JSONPATH
parameters:
- $.maxwritten_clean
master_item:
key: 'pgmon[bgwriter]'
tags:
- tag: Application
value: PostgreSQL
- uuid: 645fef7b55cd48c69b11de3201e88d78
name: 'Number of locks'
type: DEPENDENT
key: pgmon.locks.count
delay: '0'
history: 90d
description: 'Total number of locks in any database'
preprocessing:
- type: JSONPATH
parameters:
- $.total
master_item:
key: 'pgmon[locks]'
tags:
- tag: Application
value: PostgreSQL
- uuid: a56ad753b1f341928867a47b14ed8b77
name: 'Number of granted locks'
type: DEPENDENT
key: pgmon.locks.granted
delay: '0'
history: 90d
description: 'Total number of granted locks in any database'
preprocessing:
- type: JSONPATH
parameters:
- $.granted
master_item:
key: 'pgmon[locks]'
tags:
- tag: Application
value: PostgreSQL
- uuid: de1fa757395440118026f4c7a7c4ebbe
name: 'PostgreSQL latest supported version'
type: DEPENDENT
@@ -82,6 +282,39 @@ zabbix_export:
expression: 'last(/PostgreSQL by pgmon/pgmon.release.supported)<>1'
name: 'PostgreSQL major release is lo longer supported'
priority: INFO
- uuid: d0651ffc203949e3a24b1e1a2beb3dd7
name: 'Temp file size'
type: DEPENDENT
key: 'pgmon.temp_files[bytes]'
delay: '0'
history: 90d
units: b
description: 'Total size of all temp files'
preprocessing:
- type: JSONPATH
parameters:
- $.size
master_item:
key: 'pgmon[temp_files]'
tags:
- tag: Application
value: PostgreSQL
- uuid: deb355b26c37441189c85ac82465f21e
name: 'Temp file count'
type: DEPENDENT
key: 'pgmon.temp_files[count]'
delay: '0'
history: 90d
description: 'Total number of temp flies'
preprocessing:
- type: JSONPATH
parameters:
- $.count
master_item:
key: 'pgmon[temp_files]'
tags:
- tag: Application
value: PostgreSQL
- uuid: 763920af8da84db8a9a2667d9653cb21
name: 'PostgreSQL Agent Version'
type: HTTP_AGENT
@@ -95,6 +328,32 @@ zabbix_export:
tags:
- tag: Application
value: PostgreSQL
- uuid: a0bd4a987b7643c5a86e160dd9f9afcb
name: 'PostgreSQL Archive ready count'
type: HTTP_AGENT
key: 'pgmon[archive_ready]'
history: 90d
trends: '0'
description: 'Number of WAL files ready and waiting to be archived'
url: 'http://localhost:{$AGENT_PORT}/ready_archive_files'
tags:
- tag: Application
value: PostgreSQL
- uuid: 91baea76ebb240b19c5a5d3913d0b989
name: 'PostgreSQL BGWriter Info'
type: HTTP_AGENT
key: 'pgmon[bgwriter]'
delay: 5m
history: '0'
value_type: TEXT
trends: '0'
description: 'Maximum age of any frozen XID and MXID in any database'
url: 'http://localhost:{$AGENT_PORT}/bgwriter'
tags:
- tag: Application
value: PostgreSQL
- tag: Type
value: Raw
- uuid: 06b1d082ed1e4796bc31cc25f7db6326
name: 'PostgreSQL Backend IO Info'
type: HTTP_AGENT
@@ -124,6 +383,21 @@ zabbix_export:
value: PostgreSQL
- tag: Type
value: Raw
- uuid: 4627c156923f4d53bc04789b9b88c133
name: 'PostgreSQL Lock Info'
type: HTTP_AGENT
key: 'pgmon[locks]'
delay: 5m
history: '0'
value_type: TEXT
trends: '0'
description: 'Maximum age of any frozen XID and MXID in any database'
url: 'http://localhost:{$AGENT_PORT}/locks'
tags:
- tag: Application
value: PostgreSQL
- tag: Type
value: Raw
- uuid: 8706eccb7edc4fa394f552fc31f401a9
name: 'PostgreSQL ID Age Info'
type: HTTP_AGENT
@@ -139,6 +413,20 @@ zabbix_export:
value: PostgreSQL
- tag: Type
value: Raw
- uuid: bd3026ef3b82419d8a004e2d4684554a
name: 'PostgreSQL Temp Ffle info'
type: HTTP_AGENT
key: 'pgmon[temp_files]'
history: '0'
value_type: TEXT
trends: '0'
description: 'PostgreSQL temp file stats'
url: 'http://localhost:{$AGENT_PORT}/temp_files'
tags:
- tag: Application
value: PostgreSQL
- tag: Type
value: Raw
- uuid: ee88f5f4d2384f97946d049af5af4502
name: 'PostgreSQL version'
type: HTTP_AGENT
@@ -167,8 +455,286 @@ zabbix_export:
operator: NOT_MATCHES_REGEX
formulaid: A
lifetime: 30d
enabled_lifetime_type: DISABLE_NEVER
enabled_lifetime_type: DISABLE_AFTER
enabled_lifetime: 1d
item_prototypes:
- uuid: 28d5fe3a4f6848149afed33aa645f677
name: 'Max connection age: active on {#DBNAME}'
type: DEPENDENT
key: 'pgmon_connection_states[active,age,{#DBNAME}]'
delay: '0'
history: 90d
value_type: FLOAT
description: 'Number of disk blocks read in this database'
preprocessing:
- type: JSONPATH
parameters:
- '$[?(@.state == "active")].max_state_time.first()'
master_item:
key: 'pgmon_connection_states[{#DBNAME}]'
tags:
- tag: Application
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- uuid: ff1b817c3d1f43dc8b49bfd0dcb0d10a
name: 'Connection count: active on {#DBNAME}'
type: DEPENDENT
key: 'pgmon_connection_states[active,count,{#DBNAME}]'
delay: '0'
history: 90d
description: 'Number of disk blocks read in this database'
preprocessing:
- type: JSONPATH
parameters:
- '$[?(@.state == "active")].backend_count.first()'
master_item:
key: 'pgmon_connection_states[{#DBNAME}]'
tags:
- tag: Application
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- uuid: 4c0b9ca43adb45b895e3ba2e200e501e
name: 'Max connection age: disabled on {#DBNAME}'
type: DEPENDENT
key: 'pgmon_connection_states[disabled,age,{#DBNAME}]'
delay: '0'
history: 90d
value_type: FLOAT
description: 'Number of disk blocks read in this database'
preprocessing:
- type: JSONPATH
parameters:
- '$[?(@.state == "disabled")].max_state_time.first()'
master_item:
key: 'pgmon_connection_states[{#DBNAME}]'
tags:
- tag: Application
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- uuid: 280dfc9a84e8425399164e6f3e91cf92
name: 'Connection count: disabled on {#DBNAME}'
type: DEPENDENT
key: 'pgmon_connection_states[disabled,count,{#DBNAME}]'
delay: '0'
history: 90d
description: 'Number of disk blocks read in this database'
preprocessing:
- type: JSONPATH
parameters:
- '$[?(@.state == "disabled")].backend_count.first()'
master_item:
key: 'pgmon_connection_states[{#DBNAME}]'
tags:
- tag: Application
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- uuid: 63e62108657f47aaa29f7ec6499e45fc
name: 'Max connection age: fastpath function call on {#DBNAME}'
type: DEPENDENT
key: 'pgmon_connection_states[fastpath_function,age,{#DBNAME}]'
delay: '0'
history: 90d
value_type: FLOAT
description: 'Number of disk blocks read in this database'
preprocessing:
- type: JSONPATH
parameters:
- '$[?(@.state == "fastpath function call")].max_state_time.first()'
master_item:
key: 'pgmon_connection_states[{#DBNAME}]'
tags:
- tag: Application
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- uuid: 33193e62f1ad4da5b2e30677581e5305
name: 'Connection count: fastpath function call on {#DBNAME}'
type: DEPENDENT
key: 'pgmon_connection_states[fastpath_function,count,{#DBNAME}]'
delay: '0'
history: 90d
description: 'Number of disk blocks read in this database'
preprocessing:
- type: JSONPATH
parameters:
- '$[?(@.state == "fastpath function call")].backend_count.first()'
master_item:
key: 'pgmon_connection_states[{#DBNAME}]'
tags:
- tag: Application
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- uuid: 92e2366a56424bc18a88606417eae6e4
name: 'Max connection age: idle on {#DBNAME}'
type: DEPENDENT
key: 'pgmon_connection_states[idle,age,{#DBNAME}]'
delay: '0'
history: 90d
value_type: FLOAT
description: 'Number of disk blocks read in this database'
preprocessing:
- type: JSONPATH
parameters:
- '$[?(@.state == "idle")].max_state_time.first()'
master_item:
key: 'pgmon_connection_states[{#DBNAME}]'
tags:
- tag: Application
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- uuid: 505bbbb4c7b745d8bab8f3b33705b76b
name: 'Connection count: idle on {#DBNAME}'
type: DEPENDENT
key: 'pgmon_connection_states[idle,count,{#DBNAME}]'
delay: '0'
history: 90d
description: 'Number of disk blocks read in this database'
preprocessing:
- type: JSONPATH
parameters:
- '$[?(@.state == "idle")].backend_count.first()'
master_item:
key: 'pgmon_connection_states[{#DBNAME}]'
tags:
- tag: Application
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- uuid: 282494d5900c4c2e8abd298160c7cbb6
name: 'Max connection age: idle in transaction (aborted) on {#DBNAME}'
type: DEPENDENT
key: 'pgmon_connection_states[idle_aborted,age,{#DBNAME}]'
delay: '0'
history: 90d
value_type: FLOAT
description: 'Number of disk blocks read in this database'
preprocessing:
- type: JSONPATH
parameters:
- '$[?(@.state == "idle in transaction (aborted)")].max_state_time.first()'
master_item:
key: 'pgmon_connection_states[{#DBNAME}]'
tags:
- tag: Application
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- uuid: 0da5075d79234602836fc7967a31f1cc
name: 'Connection count: idle in transaction (aborted) on {#DBNAME}'
type: DEPENDENT
key: 'pgmon_connection_states[idle_aborted,count,{#DBNAME}]'
delay: '0'
history: 90d
description: 'Number of disk blocks read in this database'
preprocessing:
- type: JSONPATH
parameters:
- '$[?(@.state == "idle in transaction (aborted)")].backend_count.first()'
master_item:
key: 'pgmon_connection_states[{#DBNAME}]'
tags:
- tag: Application
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- uuid: 47aa3f7f4ff1473aae425b4c89472ab4
name: 'Max connection age: idle in transaction on {#DBNAME}'
type: DEPENDENT
key: 'pgmon_connection_states[idle_transaction,age,{#DBNAME}]'
delay: '0'
history: 90d
value_type: FLOAT
description: 'Number of disk blocks read in this database'
preprocessing:
- type: JSONPATH
parameters:
- '$[?(@.state == "idle in transaction")].max_state_time.first()'
master_item:
key: 'pgmon_connection_states[{#DBNAME}]'
tags:
- tag: Application
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- uuid: 95519bf0aefd49799601e1bbb488ec90
name: 'Connection count: idle in transaction on {#DBNAME}'
type: DEPENDENT
key: 'pgmon_connection_states[idle_transaction,count,{#DBNAME}]'
delay: '0'
history: 90d
description: 'Number of disk blocks read in this database'
preprocessing:
- type: JSONPATH
parameters:
- '$[?(@.state == "idle in transaction")].backend_count.first()'
master_item:
key: 'pgmon_connection_states[{#DBNAME}]'
tags:
- tag: Application
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- uuid: b2ae38a5733d49ceb1a31e774c11785b
name: 'Max connection age: starting on {#DBNAME}'
type: DEPENDENT
key: 'pgmon_connection_states[starting,age,{#DBNAME}]'
delay: '0'
history: 90d
value_type: FLOAT
description: 'Number of disk blocks read in this database'
preprocessing:
- type: JSONPATH
parameters:
- '$[?(@.state == "starting")].max_state_time.first()'
master_item:
key: 'pgmon_connection_states[{#DBNAME}]'
tags:
- tag: Application
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- uuid: c1890f2d7ce84a7ebaaadf266d3ffc51
name: 'Connection count: starting on {#DBNAME}'
type: DEPENDENT
key: 'pgmon_connection_states[starting,count,{#DBNAME}]'
delay: '0'
history: 90d
description: 'Number of disk blocks read in this database'
preprocessing:
- type: JSONPATH
parameters:
- '$[?(@.state == "starting")].backend_count.first()'
master_item:
key: 'pgmon_connection_states[{#DBNAME}]'
tags:
- tag: Application
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- uuid: 131653f883f448a7b861b16bc4366dfd
name: 'Database Connection States for {#DBNAME}'
type: HTTP_AGENT
key: 'pgmon_connection_states[{#DBNAME}]'
history: '0'
value_type: TEXT
trends: '0'
url: 'http://localhost:{$AGENT_PORT}/activity'
query_fields:
- name: dbname
value: '{#DBNAME}'
tags:
- tag: Application
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- tag: Type
value: Raw
- uuid: a30babe4a6f4440bba2a3ee46eff7ce2
name: 'Time spent executing statements on {#DBNAME}'
type: DEPENDENT
@@ -785,6 +1351,77 @@ zabbix_export:
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- uuid: 5960120dd01c4926b0fc1fbe9c011507
name: 'Database max sequence usage in {#DBNAME}'
type: HTTP_AGENT
key: 'pgmon_db_max_sequence[{#DBNAME}]'
delay: 5m
value_type: FLOAT
units: '%'
description: 'The percent of the currently configured value range for the most utilized sequence.'
url: 'http://localhost:{$AGENT_PORT}/sequence_usage'
query_fields:
- name: dbname
value: '{#DBNAME}'
tags:
- tag: Application
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- uuid: 48b9cc80ac4d4aee9e9f3a5d6f7d4a95
name: 'Total number of sequences on {#DBNAME}'
type: DEPENDENT
key: 'pgmon_db_sequences[total,{#DBNAME}]'
delay: '0'
description: 'Total number of sequences in the database.'
preprocessing:
- type: JSONPATH
parameters:
- $.total_sequences
master_item:
key: 'pgmon_db_sequence_visibility[{#DBNAME}]'
tags:
- tag: Application
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- uuid: 6521a9bab2ac47bf85429832d289bbac
name: 'Visible sequences on {#DBNAME}'
type: DEPENDENT
key: 'pgmon_db_sequences[visible,{#DBNAME}]'
delay: '0'
description: 'Number of sequences in the database for which Zabbix can see stats.'
preprocessing:
- type: JSONPATH
parameters:
- $.visible_sequences
master_item:
key: 'pgmon_db_sequence_visibility[{#DBNAME}]'
tags:
- tag: Application
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- uuid: 00f2da3eb99940839410a6ecd5df153f
name: 'Database sequence visibility in {#DBNAME}'
type: HTTP_AGENT
key: 'pgmon_db_sequence_visibility[{#DBNAME}]'
delay: 30m
history: '0'
value_type: TEXT
trends: '0'
description: 'Statistics about the number of sequences that exist and the number Zabbix can actually see stats for.'
url: 'http://localhost:{$AGENT_PORT}/sequence_visibility'
query_fields:
- name: dbname
value: '{#DBNAME}'
tags:
- tag: Application
value: PostgreSQL
- tag: Database
value: '{#DBNAME}'
- tag: Type
value: Raw
- uuid: 492b3cac15f348c2b85f97b69c114d1b
name: 'Database Stats for {#DBNAME}'
type: HTTP_AGENT
@@ -803,6 +1440,17 @@ zabbix_export:
value: '{#DBNAME}'
- tag: Type
value: Raw
trigger_prototypes:
- uuid: d29d0fd9d9d34b5ebd649592b0829ce5
expression: 'last(/PostgreSQL by pgmon/pgmon_db_sequences[total,{#DBNAME}]) <> last(/PostgreSQL by pgmon/pgmon_db_sequences[visible,{#DBNAME}])'
name: 'Sequences not visible to Zabbix on {#DBNAME}'
priority: WARNING
description: 'There are sequences for which Zabbix cannot see usage statistics'
tags:
- tag: Application
value: PostgreSQL
- tag: Component
value: Sequence
graph_prototypes:
- uuid: 1f7de43b77714f819e61c31273712b70
name: 'DML Totals for {#DBNAME}'
@@ -900,6 +1548,9 @@ zabbix_export:
type: DEPENDENT
key: pgmon_discover_io_backend_types
delay: '0'
lifetime: 30d
enabled_lifetime_type: DISABLE_AFTER
enabled_lifetime: 1h
item_prototypes:
- uuid: b1ac2e56b30f4812bf33ce973ef16b10
name: 'I/O Evictions by {#BACKEND_TYPE}'
@@ -1490,8 +2141,15 @@ zabbix_export:
type: HTTP_AGENT
key: pgmon_discover_rep
delay: 10m
filter:
conditions:
- macro: '{#APPLICATION_NAME}'
value: '^pg_[0-9]+_sync_[0-9]+_[0-9]+$'
operator: NOT_MATCHES_REGEX
formulaid: A
lifetime: 30d
enabled_lifetime_type: DISABLE_NEVER
enabled_lifetime_type: DISABLE_AFTER
enabled_lifetime: 7d
item_prototypes:
- uuid: 3a5a60620e6a4db694e47251148d82f5
name: 'Flush lag for {#REPID}'
@@ -1500,6 +2158,7 @@ zabbix_export:
delay: '0'
history: 90d
value_type: FLOAT
units: s
description: 'Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written and flushed it (but not yet applied it). This can be used to gauge the delay that synchronous_commit level on incurred while committing if this server was configured as a synchronous standby.'
preprocessing:
- type: JSONPATH
@@ -1515,13 +2174,12 @@ zabbix_export:
- tag: Database
value: '{#DBNAME}'
- uuid: 624f8f085a3642c9a10a03361c17763d
name: 'Last flush LSN for {#REPID}'
name: 'Last flush LSN lag for {#REPID}'
type: DEPENDENT
key: 'pgmon_rep[flush_lsn,repid={#REPID}]'
delay: '0'
history: 90d
value_type: TEXT
trends: '0'
units: B
description: 'Last write-ahead log location flushed to disk by this standby server'
preprocessing:
- type: JSONPATH
@@ -1543,6 +2201,7 @@ zabbix_export:
delay: '0'
history: 90d
value_type: FLOAT
units: s
description: 'Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written, flushed and applied it. This can be used to gauge the delay that synchronous_commit level remote_apply incurred while committing if this server was configured as a synchronous standby.'
preprocessing:
- type: JSONPATH
@@ -1558,13 +2217,12 @@ zabbix_export:
- tag: Database
value: '{#DBNAME}'
- uuid: fe1bed51845d4694bae8f53deed4846d
name: 'Last replay LSN for {#REPID}'
name: 'Last replay LSN lag for {#REPID}'
type: DEPENDENT
key: 'pgmon_rep[replay_lsn,repid={#REPID}]'
delay: '0'
history: 90d
value_type: TEXT
trends: '0'
units: B
description: 'Last write-ahead log location replayed into the database on this standby server'
preprocessing:
- type: JSONPATH
@@ -1580,13 +2238,12 @@ zabbix_export:
- tag: Database
value: '{#DBNAME}'
- uuid: 68c179d0e33f45f9bf82d2d4125763f0
name: 'Last sent LSN for {#REPID}'
name: 'Last sent LSN lag for {#REPID}'
type: DEPENDENT
key: 'pgmon_rep[sent_lsn,repid={#REPID}]'
delay: '0'
history: 90d
value_type: TEXT
trends: '0'
units: B
description: 'Last write-ahead log location sent on this connection'
preprocessing:
- type: JSONPATH
@@ -1636,6 +2293,7 @@ zabbix_export:
delay: '0'
history: 90d
value_type: FLOAT
units: s
description: 'Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written it (but not yet flushed it or applied it). This can be used to gauge the delay that synchronous_commit level remote_write incurred while committing if this server was configured as a synchronous standby.'
preprocessing:
- type: JSONPATH
@@ -1651,13 +2309,12 @@ zabbix_export:
- tag: Database
value: '{#DBNAME}'
- uuid: 57fb03cf63af4b0a91d8e36d6ff64d30
name: 'Last write LSN for {#REPID}'
name: 'Last write LSN lag for {#REPID}'
type: DEPENDENT
key: 'pgmon_rep[write_lsn,repid={#REPID}]'
delay: '0'
history: 90d
value_type: TEXT
trends: '0'
units: B
description: 'Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written it (but not yet flushed it or applied it). This can be used to gauge the delay that synchronous_commit level remote_write incurred while committing if this server was configured as a synchronous standby.'
preprocessing:
- type: JSONPATH
@@ -1694,6 +2351,8 @@ zabbix_export:
value: Raw
url: 'http://localhost:{$AGENT_PORT}/discover_rep'
lld_macro_paths:
- lld_macro: '{#APPLICATION_NAME}'
path: $.application_name
- lld_macro: '{#CLIENT_ADDR}'
path: $.client_addr
- lld_macro: '{#REPID}'
@@ -1705,6 +2364,15 @@ zabbix_export:
type: HTTP_AGENT
key: pgmon_discover_slots
delay: 10m
filter:
conditions:
- macro: '{#SLOT_NAME}'
value: '^pg_[0-9]+_sync_[0-9]+_[0-9]+$'
operator: NOT_MATCHES_REGEX
formulaid: A
lifetime: 30d
enabled_lifetime_type: DISABLE_AFTER
enabled_lifetime: 7d
item_prototypes:
- uuid: 536c5f82e3074ddfbfd842b3a2e8d46c
name: 'Slot {#SLOT_NAME} - Confirmed Flushed Bytes Lag'