GitHub

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.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"
  }
]

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 /metrics to 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 /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

Read the original on github.com ↗