diff --git a/GENTOO/pgmon-1.1.0-rc1.ebuild b/GENTOO/pgmon-1.1.0-rc1.ebuild new file mode 100644 index 0000000..9d0e6a9 --- /dev/null +++ b/GENTOO/pgmon-1.1.0-rc1.ebuild @@ -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 +} diff --git a/Makefile b/Makefile index 14e8ad9..489da13 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ FULL_VERSION := $(shell grep -m 1 '^VERSION = ' "$(SCRIPT)" | sed -ne 's/.*"\(.* 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) @@ -33,55 +34,29 @@ 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 lint format test query-tests install-common install-openrc install-systemd +.PHONY: all clean tgz lint format test query-tests template-coverage all: package-all +# Dump information related to the current version version: @echo "full version=$(FULL_VERSION) version=$(VERSION) rel=$(RELEASE) rpm=$(RPM_VERSION) deb=$(DEB_VERSION)" -# Build all packages -.PHONY: package-all -package-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)-$(FULL_VERSION)/," -acjf $(BUILD_DIR)/gentoo/$(PACKAGE_NAME)-$(FULL_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)-$(FULL_VERSION).tgz -C $(BUILD_DIR)/tgz/root . - # Clean up the build directory clean: rm -rf $(BUILD_DIR) @@ -98,7 +73,7 @@ format: $(BLACK) src/pgmon.py $(BLACK) src/test_pgmon.py -# Run unit tests for the script +# Run unit tests for the script (with coverage if it's available) test: ifeq ($(HAVE_COVERAGE),yes) cd src ; $(PYTHON) -m coverage run -m unittest && python3 -m coverage report -m @@ -114,8 +89,22 @@ query-tests: 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) @@ -138,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 @@ -149,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 @@ -165,10 +156,46 @@ 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: @@ -181,7 +208,7 @@ debian-%-install-test: rockylinux-%-install-test: docker run --rm \ -v ./$(BUILD_DIR):/output \ - rockylinux:$* \ + rockylinux/rockylinux:$* \ bash -c 'dnf makecache && dnf install -y /output/$(PACKAGE_NAME)-$(RPM_VERSION).el$*.noarch.rpm' # Run an Ubuntu install test @@ -192,19 +219,30 @@ ubuntu-%-install-test: 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)-$(RPM_VERSION).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 ## @@ -213,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 @@ -228,11 +271,10 @@ 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-%: @@ -256,10 +298,36 @@ actually-package-ubuntu-%: 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" -e "s/@@RELEASE@@/$(RPM_RELEASE)/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 $(RPM_VERSION)' \ -bb /output/oraclelinux-$*/SPECS/$(PACKAGE_NAME).spec 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/ + diff --git a/docker/Dockerfile-amazonlinux b/docker/Dockerfile-amazonlinux new file mode 100644 index 0000000..8766641 --- /dev/null +++ b/docker/Dockerfile-amazonlinux @@ -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"] diff --git a/docker/Dockerfile-oraclelinux b/docker/Dockerfile-oraclelinux index dd7e9f8..a8d405d 100644 --- a/docker/Dockerfile-oraclelinux +++ b/docker/Dockerfile-oraclelinux @@ -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 diff --git a/docker/Dockerfile-rockylinux b/docker/Dockerfile-rockylinux index eb5ba83..32fed6b 100644 --- a/docker/Dockerfile-rockylinux +++ b/docker/Dockerfile-rockylinux @@ -3,7 +3,7 @@ ARG DISTRO=rockylinux ARG RELEASE=9 -FROM ${DISTRO}:${RELEASE} +FROM rockylinux/${DISTRO}:${RELEASE} ARG DISTRO ARG RELEASE diff --git a/sample-config/pgmon-metrics.yml b/sample-config/pgmon-metrics.yml index 92b83a2..8c1045d 100644 --- a/sample-config/pgmon-metrics.yml +++ b/sample-config/pgmon-metrics.yml @@ -196,12 +196,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 @@ -235,7 +251,7 @@ metrics: locks: type: row query: - 0: + 0: > SELECT COUNT(*) AS total, SUM(CASE WHEN granted THEN 1 ELSE 0 END) AS granted FROM pg_locks diff --git a/src/pgmon.py b/src/pgmon.py index a506e9f..e13f435 100755 --- a/src/pgmon.py +++ b/src/pgmon.py @@ -37,7 +37,7 @@ from psycopg2.pool import ThreadedConnectionPool import requests -VERSION = "1.0.4" +VERSION = "1.1.0-rc1" class Context: diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml index fe2a9c8..23d722c 100644 --- a/tests/docker-compose.yml +++ b/tests/docker-compose.yml @@ -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 diff --git a/tests/run-tests.sh b/tests/run-tests.sh index 0f1e1a2..0bcc188 100755 --- a/tests/run-tests.sh +++ b/tests/run-tests.sh @@ -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=() diff --git a/zabbix_templates/pgmon_templates.yaml b/zabbix_templates/pgmon_templates.yaml index 260dec3..17dd276 100644 --- a/zabbix_templates/pgmon_templates.yaml +++ b/zabbix_templates/pgmon_templates.yaml @@ -411,7 +411,7 @@ zabbix_export: preprocessing: - type: JSONPATH parameters: - - '$[?(@.state == "active")].max_state_time' + - '$[?(@.state == "active")].max_state_time.first()' master_item: key: 'pgmon_connection_states[{#DBNAME}]' tags: @@ -429,7 +429,7 @@ zabbix_export: preprocessing: - type: JSONPATH parameters: - - '$[?(@.state == "active")].backend_count' + - '$[?(@.state == "active")].backend_count.first()' master_item: key: 'pgmon_connection_states[{#DBNAME}]' tags: @@ -448,7 +448,7 @@ zabbix_export: preprocessing: - type: JSONPATH parameters: - - '$[?(@.state == "disabled")].max_state_time' + - '$[?(@.state == "disabled")].max_state_time.first()' master_item: key: 'pgmon_connection_states[{#DBNAME}]' tags: @@ -466,7 +466,7 @@ zabbix_export: preprocessing: - type: JSONPATH parameters: - - '$[?(@.state == "disabled")].backend_count' + - '$[?(@.state == "disabled")].backend_count.first()' master_item: key: 'pgmon_connection_states[{#DBNAME}]' tags: @@ -485,7 +485,7 @@ zabbix_export: preprocessing: - type: JSONPATH parameters: - - '$[?(@.state == "fastpath function call")].max_state_time' + - '$[?(@.state == "fastpath function call")].max_state_time.first()' master_item: key: 'pgmon_connection_states[{#DBNAME}]' tags: @@ -503,7 +503,7 @@ zabbix_export: preprocessing: - type: JSONPATH parameters: - - '$[?(@.state == "fastpath function call")].backend_count' + - '$[?(@.state == "fastpath function call")].backend_count.first()' master_item: key: 'pgmon_connection_states[{#DBNAME}]' tags: @@ -522,7 +522,7 @@ zabbix_export: preprocessing: - type: JSONPATH parameters: - - '$[?(@.state == "idle")].max_state_time' + - '$[?(@.state == "idle")].max_state_time.first()' master_item: key: 'pgmon_connection_states[{#DBNAME}]' tags: @@ -540,7 +540,7 @@ zabbix_export: preprocessing: - type: JSONPATH parameters: - - '$[?(@.state == "idle")].backend_count' + - '$[?(@.state == "idle")].backend_count.first()' master_item: key: 'pgmon_connection_states[{#DBNAME}]' tags: @@ -559,7 +559,7 @@ zabbix_export: preprocessing: - type: JSONPATH parameters: - - '$[?(@.state == "idle in transaction (aborted)")].max_state_time' + - '$[?(@.state == "idle in transaction (aborted)")].max_state_time.first()' master_item: key: 'pgmon_connection_states[{#DBNAME}]' tags: @@ -577,7 +577,7 @@ zabbix_export: preprocessing: - type: JSONPATH parameters: - - '$[?(@.state == "idle in transaction (aborted)")].backend_count' + - '$[?(@.state == "idle in transaction (aborted)")].backend_count.first()' master_item: key: 'pgmon_connection_states[{#DBNAME}]' tags: @@ -596,7 +596,7 @@ zabbix_export: preprocessing: - type: JSONPATH parameters: - - '$[?(@.state == "idle in transaction")].max_state_time' + - '$[?(@.state == "idle in transaction")].max_state_time.first()' master_item: key: 'pgmon_connection_states[{#DBNAME}]' tags: @@ -614,7 +614,7 @@ zabbix_export: preprocessing: - type: JSONPATH parameters: - - '$[?(@.state == "idle in transaction")].backend_count' + - '$[?(@.state == "idle in transaction")].backend_count.first()' master_item: key: 'pgmon_connection_states[{#DBNAME}]' tags: @@ -633,7 +633,7 @@ zabbix_export: preprocessing: - type: JSONPATH parameters: - - '$[?(@.state == "starting")].max_state_time' + - '$[?(@.state == "starting")].max_state_time.first()' master_item: key: 'pgmon_connection_states[{#DBNAME}]' tags: @@ -651,7 +651,7 @@ zabbix_export: preprocessing: - type: JSONPATH parameters: - - '$[?(@.state == "starting")].backend_count' + - '$[?(@.state == "starting")].backend_count.first()' master_item: key: 'pgmon_connection_states[{#DBNAME}]' tags: