Collector Configuration
Every business metric in pg_exporter is driven by a YAML collector definition: one SQL query plus its execution conditions (version, role, tags, predicates) and runtime controls (caching, timeout). This page is the complete reference for collector definitions.
A configuration can be a single YAML file (like the default pg_exporter.yml) or a directory of YAML files — the official default bundle is merged from the 58 definition files under config/.
Configuration Loading
PG Exporter searches for configuration in the following order:
- Command-line argument:
--config=/path/to/config - Environment variable:
PG_EXPORTER_CONFIG=/path/to/config - Current directory:
./pg_exporter.yml - System config file:
/etc/pg_exporter.yml - System config directory:
/etc/pg_exporter/
Directory mode details:
- Only
.yml/.yamlfiles in that directory are loaded, non-recursively - Files are merged in lexicographic order; later files override earlier collector definitions with the same top-level name
- If a config directory contains YAML files but every one of them fails to parse, the exporter returns an error instead of silently ignoring the directory
Collector Structure
Each collector is a top-level object in the YAML configuration with a unique name and various properties:
Validation rules:
- Each entry in
metricsmust define exactly one column mapping - Each collector must expose at least one
GAUGE,COUNTER, orHISTOGRAMcolumn usageonly acceptsGAUGE,COUNTER,HISTOGRAM,LABEL, orDISCARDHISTOGRAMcolumns must definebucket: a finite, strictly increasing list of bucket upper bounds; the+Infbucket is appended automatically- Metric names and label names are validated against Prometheus naming rules during load; invalid configs fail fast
- Constant labels are checked for conflicts during load; they cannot overlap with query labels or built-in dynamic labels such as
datnameandquery; when anyHISTOGRAMcollector is configured,leis reserved and cannot be used as a constant label - The SQL result must include every column declared as
LABEL; sincev1.4.1, a missing label column fails that collector’s entire scrape instead of emitting an empty label or retaining stale results, while other non-fatal collectors continue normally - If you use one-line inline
metricsdefinitions, keepdescriptionvalues double-quoted to avoid YAML ambiguity
Core Configuration Elements
Collector Branch Name
The top-level key uniquely identifies a collector across the entire configuration:
Query Definition
The SQL query that retrieves metrics:
Metric Types
Each column in the query result must be mapped to a metric type:
| Usage | Description | Example |
|---|---|---|
GAUGE |
Instantaneous value that can go up or down | Current connections |
COUNTER |
Cumulative value that only increases | Total transactions |
HISTOGRAM |
Snapshot histogram deriving _bucket / _count / _sum series |
Transaction age distribution |
LABEL |
Use as a Prometheus label | Database name |
DISCARD |
Ignore this column | Internal values |
Histogram Columns (HISTOGRAM)
v1.4.0 introduces the HISTOGRAM column type: every row returned by the query counts
as one observation, aggregated per label group into a classic Prometheus histogram
snapshot, deriving three series families: <name>_bucket (with the le label and the
+Inf bucket), <name>_count, and <name>_sum:
Usage notes:
- This is a snapshot histogram: the whole distribution is rebuilt on every scrape,
so bucket counts can go up or down — gauge-like semantics.
histogram_quantile()works directly, butrate()/increase()over_count/_sumis meaningless - SQL
NULLobservations are ignored by default; with an explicitdefault, they count as the default value scaleis applied to the observation before bucket assignment; as with scalar columns, timestamp and boolean values are exempt fromscale- The
pg_xact_agecollector in the default bundle serves as the reference implementation
Cache Control (TTL)
The ttl parameter controls result caching:
Best practices:
- Set TTL less than your scrape interval
- Use longer TTL for expensive queries
- TTL of 0 disables caching
Timeout Control
Prevent queries from running too long:
Version Compatibility
Control which PostgreSQL versions can run this collector:
Version numbers follow PostgreSQL server_version_num rules:
100000= 10.0130200= 13.2160100= 16.1190000= 19.090600= 9.6, relevant when using the legacy config bundle
Execution Model
Understanding the full path from a collector definition to emitted metrics helps answer “why is this metric missing”:
- Planning (on connection setup or hot reload): each collector branch is checked in turn — target type (PostgreSQL / PgBouncer),
min_version/max_versiongates,tagsmatching against server role and exporter tags, and theskipswitch. Branches that fail any check are not installed on that target.curl localhost:9630/explainshows exactly the verdict of this step. - Scraping (on every
/metricsrequest): for each installed collector — if the cache is still withinttl, the cached result is returned; otherwisepredicate_queriesrun first (any false verdict skips this round and bumpspg_exporter_query_scrape_predicate_skip_count), then the main query executes undertimeout, and results are converted to metrics and cached. - Failure semantics: a normal collector failure only affects itself (
pg_exporter_query_scrape_error_countgoes up, its metric group is absent this round); a failing collector markedfatal: truefails the whole server scrape.
Tag System
Tags control when and where collectors execute:
Built-in Tags
| Tag | Description |
|---|---|
cluster |
Execute once per PostgreSQL cluster |
primary / master |
Only on primary servers |
standby / replica |
Only on replica servers |
pgbouncer |
Only for PgBouncer connections |
Prefixed Tags
| Prefix | Example | Description |
|---|---|---|
dbname: |
dbname:postgres |
Only on specific database |
username: |
username:monitor |
Only with specific user |
extension: |
extension:pg_stat_statements |
Only if extension installed |
schema: |
schema:public |
Only if schema exists |
not: |
not:slow |
NOT when exporter has tag |
Custom Tags
Pass custom tags to the exporter:
Then use in configuration:
Predicate Queries
Execute conditional checks before main query:
The main query only executes if all predicates return true.
Metric Definition
Basic Definition
Advanced Options
Collector Organization
PG Exporter ships with pre-organized collectors:
| Range | Category | Description |
|---|---|---|
| 0xx | Documentation | Examples and documentation |
| 1xx | Basic | Server info, settings, metadata |
| 2xx | Replication | Replication, slots, receivers |
| 3xx | Persistence | I/O, checkpoints, WAL |
| 4xx | Activity | Connections, locks, queries |
| 5xx | Progress | Vacuum, index creation progress |
| 6xx | Database | Per-database statistics |
| 7xx | Objects | Tables, indexes, functions |
| 8xx | Optional | Expensive/optional metrics |
| 9xx | PgBouncer | Connection pooler metrics |
| 10xx+ | Extensions | Extension-specific metrics |
Real-World Examples
Simple Gauge Collector
Counter with Labels
Version-Specific Collector
Extension-Dependent Collector
Custom Collectors
Creating Your Own Metrics
- Create a new YAML file in your config directory:
- Test your collector:
Conditional Metrics
Use predicate queries for conditional metrics:
Performance Optimization
Query Optimization Tips
-
Use appropriate TTL values:
- Fast queries: 1-10 seconds
- Medium queries: 10-60 seconds
- Expensive queries: 300-3600 seconds
-
Set realistic timeouts:
- Default: 100ms
- Complex queries: 500ms-1s
- Never disable timeout in production
-
Use cluster-level tags:
YAML -
Disable expensive collectors:
YAML
Monitoring Collector Performance
Check collector execution statistics:
Troubleshooting Configuration
Validate Configuration
Common Issues
| Problem | Solution |
|---|---|
| Metrics missing | Check tags and version compatibility |
| Slow scrapes | Increase TTL, add timeout, disable expensive queries |
| High memory usage | Reduce result set size, use LIMIT |
| Permission errors | Verify query permissions for monitoring user |
Debug Logging
Enable debug logging to troubleshoot: