https://github.com/ducks/node-postgres-exporter
A lightweight, configurable Prometheus exporter for PostgreSQL written in Node.js.
https://github.com/ducks/node-postgres-exporter
nodejs postgres prometheus
Last synced: 2 months ago
JSON representation
A lightweight, configurable Prometheus exporter for PostgreSQL written in Node.js.
- Host: GitHub
- URL: https://github.com/ducks/node-postgres-exporter
- Owner: ducks
- Created: 2025-06-09T16:43:24.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2025-06-18T15:17:52.000Z (about 1 year ago)
- Last Synced: 2025-06-18T15:44:12.463Z (about 1 year ago)
- Topics: nodejs, postgres, prometheus
- Language: JavaScript
- Homepage:
- Size: 7.81 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# node-postgres-exporter
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
```bash
git clone git@github.com/ducks/node-postgres-exporter.git
cd node-postgres-exporter
cp .env.example .env
cp databases.json.example databases.json
```
Edit `.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"
}
]
```
### 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
- [x] Rate-limit `/metrics` to protect against abuse or scraping loops
- [x] Add exporter self-health metrics (up, scrape duration, error count)
- [x] Add unit tests for query loading and metric registration
- [x] Gracefully shut down DB pools on SIGINT/SIGTERM
- [x] Support multiple database connections
- [x] Add basic GitHub Actions CI integration
- [x] Add `/configz` endpoint to expose active config for debugging
Future enhancements:
- [ ] Hot-reload `queries.json` without restart
- [ ] Support token auth via query param (e.g., `?token=...`)
- [ ] Publish prebuilt Docker image to GitHub Container Registry
- [ ] Support large `.sql` file queries
- [ ] Expand metric type support beyond Gauge/Counter
## License
MIT