Collector Configuration
A YAML collector defines a SQL query, its metrics, and when to run it. This page describes the configuration used by stable v1.6.0. For process flags and environment variables, see Command Reference.
Load one YAML file or a directory of YAML files. The default pg_exporter.yml combines 57 collector files and one schema reference from 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
- Invalid files are skipped with a warning when other files provide valid collectors. A directory with YAML files but no valid collector definitions returns an error
- The selected file or directory is the complete configuration. It is not merged with another standard path. An explicit path that fails to load does not fall back to the defaults
Simple Gauge Collector
Set PG_EXPORTER_URL with your target and credentials as shown in Quick Start. Save the following definition as connections.yml. It exports the total connection count and the counts by state.
Validate the configuration, then run a foreground process:
Check the output in another terminal:
This file contains only the example collector. To add metrics to the default configuration, see Custom Collectors.
Collector Structure
Each top-level key identifies one collector branch. This example shows the available fields; replace the SQL and column names with those for your query:
Validation rules:
queryand eachpredicate_querymust contain SQL. Main and predicate TTL values must be zero or positive- Each entry in
metricsmust define exactly one column mapping, with a unique source column name - Each collector must expose at least one
GAUGE,COUNTER, orHISTOGRAMcolumn usageacceptsGAUGE,COUNTER,HISTOGRAM,LABEL, orDISCARD, without case sensitivityHISTOGRAMcolumns 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
- At startup and reload, constant labels are checked against query labels. With built-in metrics enabled,
datnameandqueryare also reserved. If any configured collector usesHISTOGRAM, a constant label namedleis rejected - SQL results must include every
LABELandHISTOGRAMcolumn, even for zero-row results. Missing either rejects the whole collector result. A missingGAUGEorCOUNTERcolumn is logged and omitted - If you use one-line inline
metricsdefinitions, keepdescriptionvalues double-quoted to avoid YAML ambiguity
Core Configuration Elements
Collector Branch Name
The top-level key identifies the branch; name sets its metric prefix:
Branches for different server versions can share name. Their version ranges and tags must select at most one branch for the same metric series. The planner selects every eligible branch; it does not choose one winner for each name.
priority sets execution order, with lower values first. Fatal collectors run before non-fatal collectors. In directory mode, omitted priorities become 100 + the successfully loaded file’s position. In a single file, an omitted priority stays zero. Set distinct priorities when order matters.
Query Definition
The SQL query that retrieves metrics:
Metric Types
Declare each result column as a value, label, or discarded column. A scalar metric is named <collector name>_<column name>. Column rename replaces the metric suffix or label name; column name overrides the SQL column name used for lookup.
| Usage | Description | Example |
|---|---|---|
GAUGE |
Instantaneous value that can go up or down | Current connections |
COUNTER |
Cumulative value; resets when source statistics reset | 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)
HISTOGRAM, available since v1.4.0, groups observations by their label values.
Each non-NULL value contributes one observation. The output consists of three
Gauge families: <collector>_<column>_bucket, _count, and _sum. Buckets are
cumulative within the current snapshot and include le="+Inf":
Usage notes:
- The distribution is rebuilt when the collector refreshes its cache. All three
families have type
gaugeand may decrease. Usehistogram_quantile()directly on buckets; use the current_sum / _countfor the mean. Do not applyrate()orincrease()to these snapshot series - SQL
NULLobservations are omitted unlessdefaultis set. A label group with no observations emits no histogram series. Invalid or non-finite observations reject the collector result 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
For the example above, the 95th percentile is:
Cache Control (TTL)
The ttl parameter controls result caching:
ttl defaults to 0, which refreshes on each scrape. Use a TTL longer than the
scrape interval to reduce SQL load. Choose it from the maximum acceptable age of
the metric. --disable-cache forces main-query refreshes.
A failed refresh clears the old result. The error or predicate-skip result remains cached until the main TTL expires. Predicate results can have a separate TTL.
Timeout Control
Prevent queries from running too long:
The deadline covers predicate queries and the main query together. Set it above
normal execution time and below the scrape time budget. Connection prechecks use
the separate --connect-timeout flag, measured in milliseconds.
Cache TTLs and timeouts reject NaN, infinity, and positive values that overflow Go’s time.Duration. Cache TTLs remain nonnegative; finite negative timeouts still disable the deadline.
Request Lifetime
Since v1.6.0, at most two metrics requests are admitted across collection, waiting, and response writing. Collection is serial; the second request waits within its remaining budget, and further requests receive HTTP 503. The budget is 30 seconds, shortened by a valid positive finite X-Prometheus-Scrape-Timeout-Seconds header. A canceled waiter executes no SQL.
Cancellation stops work before the next collector or database. A started collector with a positive timeout finishes its predicate chain and main SQL within their shared deadline and caches the result normally. A negative timeout removes that deadline: the query then follows request cancellation. An interrupted collection returns 503 if the connection still permits a response. Driver/network delays mean these deadlines are not hard wall-clock limits; configure the DSN connect_timeout for connection handshakes.
An interrupted pass does not increment pg_exporter_scrape_error_count or pg_exporter_server_scrape_error_count; its summary log is INFO interrupted. Query errors and fatal-query ERROR logs remain observable. A real failure coinciding with request cancellation can therefore be omitted from these two pass counters. Without request cancellation, connection/precheck failures and fatal query failures, including their own timeouts, retain their error accounting. Non-fatal failures remain query-level errors.
Failed refreshes retain the existing failure TTL. In particular, canceling a negative-timeout fatal collector caches a fatal failure: a later live scrape can count that failure and report pg_up 0 until a successful refresh. Keep a positive timeout on fatal collectors. See scrape lifetime for the rationale.
Version Compatibility
Control which PostgreSQL versions can run this collector:
min_version is inclusive; max_version is exclusive. An omitted or zero bound
leaves that end unrestricted. skip and fatal default to false.
Version numbers follow PostgreSQL server_version_num rules:
100000= 10.0130002= 13.2160001= 16.1190000= 19.090600= 9.6, relevant when using the legacy config bundle
Execution Model
A collector passes through three steps:
- Plan: on the first scrape or after plan invalidation, check target type, version, tags, and
skip. Select every eligible branch./explainshows selected collectors on the main target; debug logs show rejection reasons. - Collect: return a cached result while its TTL is valid. Otherwise, evaluate predicates and run the main SQL within the shared timeout. Convert the complete result to metrics before publishing it.
- Handle failure: a normal collector error omits its result and increments its query error count. A fatal collector error stops further collection on that database and marks that database scrape as failed. A failure on the main target also sets
pg_upto 0. Other discovered databases can still be collected.
Successful metadata prechecks also replan when the connected username, schema set, or extension set changes. New eligible collectors appear on the next scrape; removed dependencies stop selecting their collectors. Unchanged sets retain the plan and caches. Replanning resets query statistics and caches, as a reload does.
Tag System
Tags control when and where collectors execute:
Built-in Tags
| Tag | Description |
|---|---|
cluster |
Run on the main connection only, not on auto-discovered database connections |
primary / master / leader |
Only on primary servers |
standby / replica / slave |
Only on replica servers |
pgbouncer |
Only for PgBouncer connections |
cluster does not coordinate separate exporter processes or PostgreSQL instances.
All tags on a collector must match.
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:
Each predicate must return one Boolean column. One row containing true passes;
false, NULL, or zero rows skips the main query. Multiple rows, a non-Boolean
column, or an SQL error fails the collector. All predicates must pass.
Add ttl: 60 to a predicate to cache its pass/skip result for 60 seconds. The
default, 0, checks it whenever the main query refreshes. Errors are not stored in
the predicate cache. --disable-cache does not bypass predicate caches.
Metric Definition
Basic Definition
Advanced Options
For GAUGE and COUNTER, SQL NULL becomes NaN unless default is set.
Numeric values and defaults are multiplied by scale (default 1). Timestamps
become Unix seconds and Booleans become 0 or 1; neither is scaled. A NULL label
becomes an empty string.
Collector Organization
PG Exporter ships with pre-organized collectors:
| Range | Category | Description |
|---|---|---|
| 0000 | Documentation | Examples and documentation |
| 0100 | Basic | Server info, settings, metadata |
| 0200 | Replication | Replication, slots, receivers |
| 0300 | Persistence | I/O, checkpoints, recovery |
| 0400 | Activity | WAL, connections, locks, queries |
| 0500 | Progress | Vacuum, index creation progress |
| 0600 | Database | Per-database statistics |
| 0700 | Objects | Tables, indexes, functions |
| 0800 | Optional | Expensive/optional metrics |
| 0900 | PgBouncer | Connection pooler metrics |
| 1000+ | Extensions | Extension-specific metrics |
Real-World Examples
Counter with Labels
Version-Specific Collector
This example uses columns available on PostgreSQL 14–17. PostgreSQL 18 moves WAL
timing statistics to pg_stat_io; the bundled pg_wal collector has separate branches.
Extension-Dependent Collector
This example requires the PostgreSQL 13+ pg_stat_statements schema and a search
path that contains the extension.
Custom Collectors
Creating Your Own Metrics
- To add metrics to the default configuration, first copy the complete configuration into a new directory:
If you already use a configuration directory, add the new file there. Save the application collector below as /etc/pg_exporter/9990-app.yml. It assumes the application tables exist and processing_time is a numeric value in seconds:
- Set
PG_EXPORTER_URLfor theappdatabase with the same credentials. Validate the definitions and select its collectors:
- Run the exporter with the same URL and configuration, then request
/metricsand inspect/statfrom another terminal.--explainselects collectors but does not execute their SQL.
To switch a packaged service to this directory, set PG_EXPORTER_CONFIG=/etc/pg_exporter in /etc/default/pg_exporter and restart the service. For later YAML edits in that directory, use POST /reload.
Conditional Metrics
Use predicate queries for conditional metrics:
Performance Optimization
Measure SQL duration with the monitoring role. Give expensive collectors a longer
TTL and enough timeout to complete under normal load. Set skip: true on
collectors you do not use. Add tags: [cluster] to instance-wide SQL so automatic
database discovery does not repeat it.
Keep labels bounded and include enough columns to identify each result row. For example, table names need a database and schema when collecting several databases. Prefer aggregated SQL when object-level series are not needed.
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 | Aggregate results or filter a defined set of objects |
| Permission errors | Verify query permissions for monitoring user |
Debug Logging
Enable debug logging to troubleshoot: