A lightweight, configurable Prometheus exporter for PostgreSQL written in Node.js.
- Collects core PostgreSQL metrics (connections, database size)
- Collects metrics about itself (scrape duration, error count)
- Supports dynamic custom metrics via
queries.json - Supports multiple database connections via
databases.json - Secured with API key using Bearer auth
- Fully Docker-compatible and cloud-ready
- Fast to set up, easy to extend
Quickstart
1. Clone and configure
git clone git@github.com/ducks/node-postgres-exporter.git
cd node-postgres-exporter
cp .env.example .env
cp databases.json.example databases.jsonEdit .env to match your environment:
EXPORTER_PORT=9187
EXPORTER_API_KEY=Defacing-Tingle-Caucus8-Refueling
QUERIES_FILE=/app/queries.json
DBS_CONFIG_FILE=/app/databases.json
Edit databases.json to match your environment:
{
"databases": [
{
"name": "db1",
"host": "postgres1",
"port": 5432,
"user": "postgres",
"pass": "postgres",
"database": "db1"
},
{
"name": "db2",
"host": "postgres2",
"port": 5432,
"user": "postgres",
"pass": "postgres",
"database": "db2"
}
]
}
2. Define your metrics
Edit or mount a custom queries.json file:
[
{
"name": "active_users",
"help": "Number of active users in the system",
"type": "gauge",
"labels": ["status"],
"query": "SELECT status, COUNT(*)::int FROM users GROUP BY status"
}
]
Both databases.json and queries.json are validated against JSON Schemas
at startup (see schemas/). Invalid configs (wrong type names, missing
required fields, typos in property names, etc.) cause the exporter to fail
fast with the offending JSON pointer rather than starting with broken state.
3. Run it
docker build -t pg-exporter .
docker run -p 9187:9187 \
--env-file .env \
-v $(pwd)/queries.json:/app/queries.json \
-v $(pwd)/databases.json:/app/databases.json \
pg-exporter
Or with Docker Compose:
docker compose up
4. Configure Prometheus
scrape_configs:
- job_name: 'postgres_exporter'
static_configs:
- targets: ['your-exporter-host:9187']
authorization:
type: Bearer
credentials: your_secret_key
Metrics Exposed
| Metric | Type | Description |
|---|---|---|
pg_active_connections{db="..."} |
Gauge | Number of active PostgreSQL connections per DB |
pg_database_size_bytes{db="...",database="..."} |
Gauge | Size of each database in bytes per DB |
pg_scrape_success{db="..."} |
Gauge | 1 if last scrape succeeded for DB, 0 if failed |
pg_scrape_duration_seconds{db="..."} |
Gauge | Duration of scrape per DB in seconds |
exporter_up |
Gauge | Always 1 if exporter process is running |
exporter_errors_total |
Counter | Total number of scrape errors encountered |
exporter_scrape_duration_seconds |
Gauge | Total scrape duration for entire exporter |
exporter_scrape_lockouts_total |
Counter | Total number of scrape requests rejected due to concurrent scrape lock |
| Custom metrics | Gauge/Counter | Defined via queries.json, dynamically loaded |
Endpoints
| Path | Method | Auth Required | Description |
|---|---|---|---|
/metrics |
GET | ✅ Bearer Token | Prometheus scrape endpoint |
/healthz |
GET | ❌ None | Liveness probe for health checks |
/livez |
GET | ❌ None | Liveness probe; returns 200 OK if process is alive |
/readyz |
GET | ❌ None | Readiness probe. Returns 200 OK if the database connection is successful. |
/configz |
GET | ✅ Bearer Token | Returns current loaded database and metrics config |
Authorization
The /metrics endpoint requires a Bearer token.
You must include the following HTTP header:
Authorization: Bearer your_secret_key
Configuration
| Variable | Description |
|---|---|
EXPORTER_PORT |
HTTP server port (default 9187) |
EXPORTER_API_KEY |
Bearer token for /metrics access |
QUERIES_FILE |
Path to queries.json file |
DBS_CONFIG_FILE |
Path to databases.json file |
Testing
Unit tests are written using Vitest.
Unit tests run on main branch push/PR. Integration tests requiring live
databases are automatically skipped in CI environments.
To run full tests locally:
npm test
TODOs / Improvement Ideas
- Rate-limit
/metricsto protect against abuse or scraping loops - Add exporter self-health metrics (up, scrape duration, error count)
- Add unit tests for query loading and metric registration
- Gracefully shut down DB pools on SIGINT/SIGTERM
- Support multiple database connections
- Add basic GitHub Actions CI integration
- Add
/configzendpoint to expose active config for debugging
Future enhancements:
- Hot-reload
queries.jsonwithout restart - Support token auth via query param (e.g.,
?token=...) - Publish prebuilt Docker image to GitHub Container Registry
- Support large
.sqlfile queries - Expand metric type support beyond Gauge/Counter
License
MIT