Development

Build and test pg_exporter, author collectors, regenerate configs, and understand the release pipeline

The project intentionally keeps most monitoring logic in YAML and a smaller execution engine in Go. Changes therefore fall into two paths: collector work and exporter-runtime work. Both paths should keep the merged configs, tests, documentation, and release metadata aligned.

Repository Layout

Path Purpose
exporter/ CLI parsing, URL/config loading, planning, execution, metrics, health state, HTTP handlers, tests
config/ 58 ordered collector definition files for PostgreSQL 10-19+ and pgBouncer
pg_exporter.yml Generated monolithic default config (make conf)
legacy/config/ Collector definitions for PostgreSQL 9.1-9.6
legacy/pg_exporter.yml Generated legacy monolithic config (make conf9)
docs/design/ Authoritative design notes such as snapshot histogram semantics
monitor/ Grafana dashboards and database initialization helper
package/ systemd environment/unit files and package scripts
.goreleaser.yml Cross-platform archives, RPM/DEB packages, checksums, Docker images, and GitHub Release

Toolchain

The current go.mod declares Go 1.26.5. For a normal development build:

git clone https://github.com/pgsty/pg_exporter.git
cd pg_exporter
go mod download
make build
./pg_exporter --version

The binary is built with CGO disabled for release artifacts. make build is suitable for local development; GoReleaser supplies version, branch, revision, and build-date metadata for official artifacts.

Test Before and After a Change

go test ./...
go test -race ./...

# Confirm all supported PostgreSQL and pgBouncer branches remain coverable,
# and that config structure, metric names, labels, and histograms are valid.
go test ./exporter/...

The test suite includes config coverage through PostgreSQL 19, PostgreSQL 9 legacy coverage, concurrency/reload behavior, HTTP route validation, label and metric-name validation, predicate caching, and snapshot histogram acceptance.

For a runtime change, also cross-build the supported release targets or use:

make goreleaser-build

Change or Add a Collector

  1. Choose the numeric group and a unique top-level branch name.
  2. Set name to the stable metric namespace when multiple version/role branches should emit one metric family.
  3. Write SQL with an explicit result-column list.
  4. Add min_version / max_version, role tags, fact tags, and predicates as narrowly as required.
  5. Declare every returned column exactly once under metrics.
  6. Pick ttl, timeout, fatal, and skip based on operational cost and failure impact.
  7. Run config tests, regenerate the merged file, and inspect the diff.
  8. Test the query as the monitoring role against every relevant server version and role.
  9. Update Bundled Collectors and release notes when the public metric surface changes.

Use config/0000-doc.yml as the executable schema reference.

Column rules

  • LABEL becomes a Prometheus label; avoid unbounded or sensitive values.
  • GAUGE is for values that can move in either direction.
  • COUNTER is for monotonically increasing source values (resets still occur on server restart/stat reset).
  • HISTOGRAM builds a snapshot distribution from SQL rows. Its _bucket, _count, and _sum series are gauges that may decrease; do not apply rate() or increase().
  • DISCARD validates/ignores a result column without exporting it.
  • rename, default, and scale change the emitted name/value semantics and need compatibility review.

le is reserved when a collector contains a histogram. Metric and label names are validated while loading the configuration so invalid names fail before scraping.

Regenerate Configs

make conf     # config/*.yml -> pg_exporter.yml
make conf9    # legacy/config/*.yml -> legacy/pg_exporter.yml

git diff -- pg_exporter.yml legacy/pg_exporter.yml

Generated files are committed artifacts. CI checks that they exactly match the ordered source files; never edit only the monolithic output.

Exercise a Collector Locally

# Syntax/schema only; no target required
./pg_exporter --config=./config --dry-run

# Build a target-specific plan and exit
PG_EXPORTER_URL='postgres://monitor@localhost/postgres' \
  ./pg_exporter --config=./config --explain

# Run, inspect the plan and observe timing/errors
PG_EXPORTER_URL='postgres://monitor@localhost/postgres' \
  ./pg_exporter --config=./config --log.level=debug
curl localhost:9630/explain
curl localhost:9630/stat

Test zero-row results as well as populated results. Since v1.4.1, a missing configured LABEL column rejects the collector result atomically, including when the query happens to return no rows.

Release Pipeline

GoReleaser produces:

  • Linux, macOS, and Windows archives;
  • RPM and DEB packages;
  • SHA256 checksums.txt;
  • amd64/arm64 Docker images and multi-architecture manifests;
  • a GitHub Release for the tag.

The release version is injected into exporter.Version. Keep the fallback version, Makefile version, README badge, package metadata, and documentation parameter aligned before tagging. Validate the tag, Release object, checksums, package contents, container manifests, and install behavior as separate layers.

Documentation Workflow

The standalone documentation repository can import the authoritative Pigsty module pages and split the consolidated history with:

python3 bin/sync_pg_exporter_content.py \
  --pigsty-io /path/to/pigsty.io \
  --pigsty-cc /path/to/pigsty.cc \
  --output ./content

The generated core pages are then supplemented by standalone-only guides such as this page, compatibility, security, collectors, and troubleshooting. Run the site warning-strict build and link checker before publishing.

Contributions are licensed under Apache 2.0. Open changes and issues at pgsty/pg_exporter.