Skip to main content

Prerequisites

Before starting, make sure you have:
  • Query Exporter installed (see Installation)
  • A database to connect to (we’ll use SQLite for this guide)
  • Basic familiarity with YAML and SQL

Your first Query Exporter setup

1

Create a configuration file

Create a file named config.yaml in your working directory:
config.yaml
databases:
  demo_db:
    dsn: sqlite://

metrics:
  random_value:
    type: gauge
    description: A random value between 0 and 1

queries:
  generate_random:
    interval: 5
    databases: [demo_db]
    metrics: [random_value]
    sql: SELECT random() / 9223372036854775808.0 + 0.5 AS random_value
This configuration:
  • Connects to an in-memory SQLite database
  • Defines a gauge metric to store a random value
  • Runs a query every 5 seconds to generate a random number
Using sqlite:// creates an in-memory database - perfect for testing. For a real database, use a DSN like sqlite:///path/to/database.db.
2

Start Query Exporter

Run the exporter:
query-exporter
You should see output like:
INFO     query-exporter starting on port 9560
INFO     database connected: demo_db
INFO     scheduling query: generate_random (interval: 5s)
3

View your metrics

Open your browser or use curl to access the metrics endpoint:
curl http://localhost:9560/metrics
You should see output including:
# HELP random_value A random value between 0 and 1
# TYPE random_value gauge
random_value 0.7234567891234567

# HELP queries_total Number of executed queries
# TYPE queries_total counter
queries_total{database="demo_db",query="generate_random",status="success"} 3.0

# HELP query_latency Query execution latency (seconds)
# TYPE query_latency histogram
query_latency_bucket{database="demo_db",query="generate_random",le="0.005"} 3.0
Query Exporter automatically provides built-in metrics like queries_total and query_latency to monitor query execution health.
4

Validate configuration

Before running in production, validate your configuration:
query-exporter --check-only --config config.yaml
If valid, you’ll see:
INFO     configuration valid

Real-world example

Let’s create a more practical example that monitors a real database:
databases:
  production_db:
    dsn: postgresql://user:password@localhost:5432/myapp
    labels:
      environment: production
      region: us-east-1

metrics:
  active_users:
    type: gauge
    description: Number of active users in the last 24 hours
  
  order_total:
    type: counter
    description: Total revenue from orders
    labels: [status]
  
  query_duration:
    type: histogram
    description: Query execution time
    buckets: [0.1, 0.5, 1.0, 5.0, 10.0]

queries:
  count_active_users:
    interval: 60
    databases: [production_db]
    metrics: [active_users]
    sql: |
      SELECT COUNT(DISTINCT user_id) AS active_users
      FROM user_activity
      WHERE last_seen > NOW() - INTERVAL '24 hours'
  
  sum_order_revenue:
    interval: 300
    databases: [production_db]
    metrics: [order_total]
    sql: |
      SELECT
        SUM(total_amount) AS order_total,
        status
      FROM orders
      GROUP BY status

Configuration options

Command-line options

--host
string
default:"localhost"
Host address to bind. Use 0.0.0.0 to listen on all interfaces.
--port
integer
default:"9560"
Port to run the webserver on.
--metrics-path
string
default:"/metrics"
Path under which metrics are exposed.
--log-level
string
default:"info"
Minimum log level: critical, error, warning, info, or debug.
--config
string
default:"config.yaml"
Configuration file path. Can be specified multiple times for partial configs.
--check-only
boolean
default:"false"
Validate configuration without starting the exporter.
--process-stats
boolean
default:"false"
Include process resource usage metrics.

Environment variables

All command-line options can be set via environment variables with the QE_ prefix:
export QE_HOST=0.0.0.0
export QE_PORT=9560
export QE_LOG_LEVEL=debug
export QE_CONFIG=config.yaml
query-exporter
You can also use a .env file in your working directory:
.env
QE_HOST=0.0.0.0
QE_PORT=9560
QE_LOG_LEVEL=info

Built-in metrics

Query Exporter automatically exports these metrics:
database_errors
counter
Number of database connection errors per databaseLabels: database
queries_total
counter
Number of executed queries per database, query, and statusLabels: database, query, status (success/error/timeout)
query_interval
gauge
Configured query execution interval in secondsLabels: query
query_latency
histogram
Query execution latency in secondsLabels: database, query
query_timestamp
gauge
Last query execution timestamp (Unix time)Labels: database, query

Testing your setup

1

Check metrics are updating

Watch metrics change over time:
watch -n 2 'curl -s http://localhost:9560/metrics | grep random_value'
2

Verify query execution

Check query success counters:
curl -s http://localhost:9560/metrics | grep queries_total
3

Monitor query latency

Check query performance:
curl -s http://localhost:9560/metrics | grep query_latency
4

Check for errors

Look for database or query errors:
curl -s http://localhost:9560/metrics | grep -E 'database_errors|status="error"'

Common patterns

Using query timeouts

queries:
  slow_query:
    interval: 60
    timeout: 5.0  # Seconds
    databases: [mydb]
    metrics: [my_metric]
    sql: SELECT COUNT(*) AS my_metric FROM large_table

Using cron schedules

queries:
  daily_report:
    schedule: "0 0 * * *"  # Every day at midnight
    databases: [mydb]
    metrics: [daily_count]
    sql: SELECT COUNT(*) AS daily_count FROM events WHERE DATE(created) = CURRENT_DATE

Using environment variables in DSN

databases:
  prod_db:
    dsn: !env DB_DSN
Then set the environment variable:
export DB_DSN="postgresql://user:password@host:5432/database"

Multiple metrics from one query

metrics:
  total_users:
    type: gauge
    description: Total number of users
  
  active_users:
    type: gauge
    description: Number of active users

queries:
  user_stats:
    interval: 60
    databases: [mydb]
    metrics: [total_users, active_users]
    sql: |
      SELECT
        COUNT(*) AS total_users,
        COUNT(*) FILTER (WHERE last_login > NOW() - INTERVAL '7 days') AS active_users
      FROM users

Troubleshooting

Validate your configuration:
query-exporter --check-only --config config.yaml
Enable debug logging:
query-exporter --log-level debug --config config.yaml
  • Verify your DSN format is correct for your database engine
  • Check that required database drivers are installed
  • Test database connectivity outside of Query Exporter
  • Check firewall rules and network connectivity
  • Check query interval or schedule is configured correctly
  • Look for errors in logs: query-exporter --log-level debug
  • Verify query syntax is correct for your database
  • Check queries_total metric with status="error" label
  • Ensure config directory is mounted: -v "$PWD:/config"
  • Check config.yaml exists in mounted directory
  • Verify port mapping: -p 9560:9560
  • Check container logs: docker logs query-exporter

Next steps

Configuration reference

Learn about all configuration options in detail

Database setup

Database-specific connection and query examples

Metric types

Understanding gauge, counter, histogram, summary, and enum metrics

Production deployment

Best practices for running in production

Build docs developers (and LLMs) love