---
title: "database_observability.postgres | Grafana Alloy documentation"
description: "Learn about database_observability.postgres"
---

> For a curated documentation index, see [llms.txt](/llms.txt). For the complete documentation index, see [llms-full.txt](/llms-full.txt).

# `database_observability.postgres`

`database_observability.postgres` connects to a PostgreSQL database and collects observability data from system catalogs and the `pg_stat_statements` extension. The component collects query details, schema information, explain plans, query samples, and processes PostgreSQL logs. It forwards this data as log entries to Loki receivers and exports targets for Prometheus scraping.

## Usage

Alloy ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```alloy
database_observability.postgres "<LABEL>" {
  data_source_name = <DATA_SOURCE_NAME>
  forward_to       = [<LOKI_RECEIVERS>]
}
```

## Arguments

You can use the following arguments with `database_observability.postgres`:

Expand table

| Name                   | Type                 | Description                                                                                                                                                                                   | Default                                                                                              | Required |
|------------------------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|----------|
| `data_source_name`     | `secret`             | [Data Source Name](https://pkg.go.dev/github.com/lib/pq#hdr-URL_connection_strings-NewConfig) for the Postgres server to connect to. Required when no `database_instance` blocks are defined. |                                                                                                      | no       |
| `forward_to`           | `list(LogsReceiver)` | Where to forward log entries after processing.                                                                                                                                                |                                                                                                      | yes      |
| `targets`              | `list(map(string))`  | List of external targets to scrape for Prometheus metrics.                                                                                                                                    |                                                                                                      | no       |
| `disable_collectors`   | `list(string)`       | A list of collectors to disable from the default set.                                                                                                                                         |                                                                                                      | no       |
| `enable_collectors`    | `list(string)`       | A list of collectors to enable on top of the default set.                                                                                                                                     |                                                                                                      | no       |
| `exclude_databases`    | `list(string)`       | A list of databases to exclude from monitoring.                                                                                                                                               | `["alloydbadmin", "alloydbmetadata", "azure_maintenance", "azure_sys", "cloudsqladmin", "rdsadmin"]` | no       |
| `exclude_users`        | `list(string)`       | A list of users to exclude from monitoring.                                                                                                                                                   | `["azuresu", "cloudsqladmin", "db-o11y", "rdsadmin"]`                                                | no       |
| `exclude_current_user` | `bool`               | Exclude from activity monitoring the user that Alloy uses to connect to the database. The resolved username is automatically added to `exclude_users`, if not already present.                | `true`                                                                                               | no       |

Refer to the [PostgreSQL documentation](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING) for more information about the format of the connection strings in `data_source_name`.

## Exports

The following fields are exported and can be referenced by other components:

Expand table

| Name             | Type                | Description                                                                                                                  |
|------------------|---------------------|------------------------------------------------------------------------------------------------------------------------------|
| `logs_receiver`  | `LogsReceiver`      | Receiver for PostgreSQL logs that processes and exports error metrics. Exported in the single-DSN form only.                 |
| `logs_receivers` | `map(LogsReceiver)` | One logs receiver per \[`database_instance`]\[database\_instance] block, keyed by block label. Empty in the single-DSN form. |
| `targets`        | `list(map(string))` | Targets that can be used to collect metrics from the component.                                                              |

The following collectors are configurable:

Expand table

| Name             | Description                                                           | Enabled by default |
|------------------|-----------------------------------------------------------------------|--------------------|
| `explain_plans`  | Collect query explain plans.                                          | yes                |
| `table_stats`    | Collect table-level scan statistics.                                  | no                 |
| `index_stats`    | Collect per-index usage statistics.                                   | no                 |
| `query_details`  | Collect queries information.                                          | yes                |
| `query_samples`  | Collect query samples and wait events information.                    | yes                |
| `schema_details` | Collect schemas, tables, and columns from PostgreSQL system catalogs. | yes                |

## Blocks

You can use the following blocks with `database_observability.postgres`:

No valid configuration blocks found.

### `cloud_provider`

The `cloud_provider` block has no attributes. It contains zero or one of the [`aws`](#aws), [`azure`](#azure), or [`gcp`](#gcp) blocks. You use the `cloud_provider` block to provide information related to the cloud provider that hosts the database under observation. This information is appended as labels to the collected metrics. The labels make it easier for you to filter and group your metrics.

### `aws`

The `aws` block supplies the [ARN](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html) identifier for the database being monitored.

Expand table

| Name  | Type     | Description                                             | Default | Required |
|-------|----------|---------------------------------------------------------|---------|----------|
| `arn` | `string` | The ARN associated with the database under observation. |         | yes      |

### `azure`

The `azure` block supplies the identifying information for the database being monitored.

Expand table

| Name              | Type     | Description                                                                                             | Default | Required |
|-------------------|----------|---------------------------------------------------------------------------------------------------------|---------|----------|
| `subscription_id` | `string` | The Subscription ID for your Azure account.                                                             |         | yes      |
| `resource_group`  | `string` | The Resource Group that holds the database resource.                                                    |         | yes      |
| `server_name`     | `string` | The database server name, for example `orders-db` for the host `orders-db.postgres.database.azure.com`. |         | no       |

### `gcp`

The `gcp` block supplies the identifying information for the GCP Cloud SQL database being monitored.

Expand table

| Name              | Type     | Description                                                                                                                 | Default | Required |
|-------------------|----------|-----------------------------------------------------------------------------------------------------------------------------|---------|----------|
| `connection_name` | `string` | The Cloud SQL instance connection name in the format `project:region:instance`, for example `my-project:us-central1:my-db`. |         | yes      |

### `database_instance`

The `database_instance` block defines one database server to monitor. Repeat the block to monitor several databases with a single component. The block label must be unique across `database_instance` blocks and identifies the database in the component’s metrics endpoint path and in the `logs_receivers` export. Each `database_instance` block must also point to a distinct server: two blocks that resolve to the same host, port, and database name are rejected.

Expand table

| Name               | Type     | Description                                                                                                                          | Default | Required |
|--------------------|----------|--------------------------------------------------------------------------------------------------------------------------------------|---------|----------|
| `data_source_name` | `secret` | [Data Source Name](https://pkg.go.dev/github.com/lib/pq#hdr-URL_connection_strings-NewConfig) for the Postgres server to connect to. |         | yes      |

Each `database_instance` block can also contain a \[`cloud_provider`]\[cloud\_provider] block that applies to that database only.

The component always embeds a `postgres_exporter` for each `database_instance` block and serves its metrics on the block’s metrics path. Use the \[`prometheus_exporter`]\[prometheus\_exporter] block to configure it. External exporter targets are only supported in the top-level single-DSN form.

When you define `database_instance` blocks, don’t set the top-level `data_source_name`, `targets`, and `cloud_provider` arguments. They’re mutually exclusive with `database_instance` blocks. All other arguments and blocks, such as collector settings and `prometheus_exporter`, apply to every configured database.

The metrics for each database are served on a separate `/db/<LABEL>/metrics` path under the component’s HTTP endpoint, and the exported targets point to the corresponding path. When you don’t define `database_instance` blocks, the component serves metrics on its historical `/metrics` path. The metrics endpoints are served exactly at those paths: requests to any other path under the component’s HTTP endpoint return HTTP 404.

Each database also gets its own logs receiver in the `logs_receivers` export, keyed by the block label. Forward each database’s PostgreSQL logs to its own receiver so log-derived error metrics are attributed to the right database.

For example:

Alloy ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```alloy
database_observability.postgres "pool" {
  forward_to = [loki.write.logs_service.receiver]

  database_instance "orders" {
    data_source_name = sys.env("ORDERS_DSN")

    cloud_provider {
      aws {
        arn = "orders-rds-db-arn"
      }
    }
  }

  database_instance "billing" {
    data_source_name = sys.env("BILLING_DSN")
  }
}

loki.source.file "orders_db_logs" {
  targets    = local.file_match.orders_db_logs.targets
  forward_to = [database_observability.postgres.pool.logs_receivers["orders"]]
}
```

### `clustering`

Expand table

| Name      | Type   | Description                                              | Default | Required |
|-----------|--------|----------------------------------------------------------|---------|----------|
| `enabled` | `bool` | Enables distributing databases with other cluster nodes. | `false` | yes      |

When Alloy is [using clustering](../../../../get-started/clustering/), and `enabled` is set to true, then this `database_observability.postgres` component instance opts-in to distributing its configured databases between all cluster nodes.

Clustering assumes that all cluster nodes are running with the same configuration file. All component instances opting in to clustering use the instance key of each configured database, `postgresql://<host>:<port>/<dbname>`, and a consistent hashing algorithm to determine ownership of each database between the cluster peers. Each peer then only collects from the subset of databases it’s responsible for, and only exports the targets of those databases, so `prometheus.scrape` components on the same node scrape exactly the databases the node owns. When a node joins or leaves the cluster, every peer recalculates ownership: expect a short gap or a brief duplicate collection for a database while its ownership moves. While the cluster isn’t yet ready to admit traffic, for example while it’s still forming and waiting for the minimum cluster size, the component doesn’t collect from any database.

Every node exports the logs receivers of all configured databases, whether it owns them or not: a node that doesn’t own a database accepts and discards entries sent to that database’s receiver. Log pipelines that forward PostgreSQL logs to the exported receivers therefore work unchanged on every node, but only the owning node processes the logs into error metrics.

Clustering is also useful with a single database: when several cluster nodes run an identical configuration, exactly one node collects from the database at a time, which gives you a highly available setup without duplicate collection.

If Alloy is *not* running in clustered mode, then the block is a no-op and `database_observability.postgres` collects from every configured database.

### `query_details`

Expand table

| Name               | Type       | Description                                          | Default | Required |
|--------------------|------------|------------------------------------------------------|---------|----------|
| `collect_interval` | `duration` | How frequently to collect information from database. | `"1m"`  | no       |
| `statements_limit` | `integer`  | Max number of recent queries to collect details for. | `100`   | no       |

### `query_samples`

Expand table

| Name                                | Type       | Description                                                                                                                      | Default | Required |
|-------------------------------------|------------|----------------------------------------------------------------------------------------------------------------------------------|---------|----------|
| `collect_interval`                  | `duration` | How frequently to collect information from database.                                                                             | `"10s"` | no       |
| `disable_query_redaction`           | `bool`     | Collect unredacted SQL query text (might include parameters).                                                                    | `false` | no       |
| `exclude_current_user`              | `bool`     | Deprecated. Use the top-level `exclude_current_user` argument instead. This setting takes precedence over the top-level setting. | (unset) | no       |
| `enable_pre_classified_wait_events` | `boolean`  | When `true`, emits telemetry data with pre-classified wait event information.                                                    | `false` | no       |

### `schema_details`

Expand table

| Name               | Type       | Description                                                 | Default | Required |
|--------------------|------------|-------------------------------------------------------------|---------|----------|
| `collect_interval` | `duration` | How frequently to collect information from database.        | `"1m"`  | no       |
| `cache_enabled`    | `boolean`  | Deprecated. Whether to enable caching of table definitions. | `true`  | no       |
| `cache_size`       | `integer`  | Deprecated. Cache size.                                     | `256`   | no       |
| `cache_ttl`        | `duration` | Deprecated. Cache TTL.                                      | `"10m"` | no       |

The `cache_enabled`, `cache_size`, and `cache_ttl` settings are deprecated: they are accepted for backward compatibility, but ignored.

### `explain_plans`

Expand table

| Name                | Type       | Description                                          | Default | Required |
|---------------------|------------|------------------------------------------------------|---------|----------|
| `collect_interval`  | `duration` | How frequently to collect information from database. | `"1m"`  | no       |
| `per_collect_ratio` | `float64`  | The ratio of queries to collect explain plans for.   | `1.0`   | no       |

### `logs`

Expand table

| Name                           | Type   | Description                                                              | Default | Required |
|--------------------------------|--------|--------------------------------------------------------------------------|---------|----------|
| `enable_error_logs_processing` | `bool` | Emit per-query error telemetry by pairing error and statement log lines. | `false` | no       |

The `logs` collector is always enabled and counts server errors from the PostgreSQL logs forwarded to `logs_receiver`. When `enable_error_logs_processing` is `true`, the collector additionally emits per-query error telemetry that associates each error with the query that caused it.

### `health_check`

Expand table

| Name               | Type       | Description                                          | Default | Required |
|--------------------|------------|------------------------------------------------------|---------|----------|
| `collect_interval` | `duration` | How frequently to collect information from database. | `"1h"`  | no       |

### `prometheus_exporter`

The `prometheus_exporter` block configures the embedded postgres\_exporter scrapers. The `data_source_name` is inherited from the parent block.

Refer to [`prometheus.exporter.postgres`](../../prometheus/prometheus.exporter.postgres/) docs for the full list of supported arguments and sub-blocks.

## `logs` collector

The `logs` collector processes PostgreSQL logs received through the `logs_receiver` entry point. It counts server errors and exposes them as a Prometheus metric on the component’s metrics endpoint. When [`enable_error_logs_processing`](#logs) is `true`, it also emits per-query error telemetry as Loki log entries, so each error can be associated with the query that caused it. When you define \[`database_instance`]\[database\_instance] blocks, each database has its own entry point in the `logs_receivers` export instead, keyed by block label.

The `logs_receiver` entry point must be fed by `loki` log source components, for example:

- `loki.source.file`: to read and process PostgreSQL log files from a self-managed database instance
- `otelcol.receiver.awscloudwatch` and `otelcol.exporter.loki`: to read and process CloudWatch Logs for an AWS RDS instance

PostgreSQL must be configured with a specific `log_line_prefix` so the collector can parse the logs.

> Note
> 
> Refer to the [PostgreSQL setup documentation](/docs/grafana-cloud/monitor-applications/database-observability/set-up/postgres/) for the required `log_line_prefix` and detailed log configuration options.

## Example

Alloy ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```alloy
database_observability.postgres "orders_db" {
  data_source_name = "postgres://user:pass@localhost:5432/dbname"
  forward_to       = [loki.relabel.orders_db.receiver]
  targets          = prometheus.exporter.postgres.orders_db.targets

  // Enable per-query error telemetry from the processed PostgreSQL logs.
  logs {
    enable_error_logs_processing = true
  }
}

prometheus.exporter.postgres "orders_db" {
  data_source_name   = "postgres://user:pass@localhost:5432/dbname"
  enabled_collectors = ["stat_statements"]
}

// OPTIONAL: read PostgreSQL log files and forward to logs collector
loki.source.file "postgres_logs" {
  targets = [{
    __path__ = "/var/log/postgresql/postgresql-*.log",
    job      = "postgres-logs",
  }]

  forward_to = [database_observability.postgres.orders_db.logs_receiver]
}

loki.relabel "orders_db" {
  forward_to = [loki.write.logs_service.receiver]
  rule {
    target_label = "job"
    replacement  = "integrations/db-o11y"
  }
  rule {
    target_label = "instance"
    replacement  = "orders_db"
  }
}

discovery.relabel "orders_db" {
  targets = database_observability.postgres.orders_db.targets

  rule {
    target_label = "job"
    replacement  = "integrations/db-o11y"
  }
  rule {
    target_label = "instance"
    replacement  = "orders_db"
  }
}

prometheus.scrape "orders_db" {
  targets    = discovery.relabel.orders_db.targets
  job_name   = "integrations/db-o11y"
  forward_to = [prometheus.remote_write.metrics_service.receiver]
}

prometheus.remote_write "metrics_service" {
  endpoint {
    url = sys.env("<GRAFANA_CLOUD_HOSTED_METRICS_URL>")
    basic_auth {
      username = sys.env("<GRAFANA_CLOUD_HOSTED_METRICS_ID>")
      password = sys.env("<GRAFANA_CLOUD_RW_API_KEY>")
    }
  }
}

loki.write "logs_service" {
  endpoint {
    url = sys.env("<GRAFANA_CLOUD_HOSTED_LOGS_URL>")
    basic_auth {
      username = sys.env("<GRAFANA_CLOUD_HOSTED_LOGS_ID>")
      password = sys.env("<GRAFANA_CLOUD_RW_API_KEY>")
    }
  }
}
```

Replace the following:

- *`<GRAFANA_CLOUD_HOSTED_METRICS_URL>`* : The URL for your Grafana Cloud hosted metrics.
- *`<GRAFANA_CLOUD_HOSTED_METRICS_ID>`* : The user ID for your Grafana Cloud hosted metrics.
- *`<GRAFANA_CLOUD_RW_API_KEY>`* : Your Grafana Cloud API key.
- *`<GRAFANA_CLOUD_HOSTED_LOGS_URL>`* : The URL for your Grafana Cloud hosted logs.
- *`<GRAFANA_CLOUD_HOSTED_LOGS_ID>`* : The user ID for your Grafana Cloud hosted logs.

## Compatible components

`database_observability.postgres` can accept arguments from the following components:

- Components that export [Targets](../../../compatibility/#targets-exporters)
- Components that export [Loki `LogsReceiver`](../../../compatibility/#loki-logsreceiver-exporters)

`database_observability.postgres` has exports that can be consumed by the following components:

- Components that consume [Targets](../../../compatibility/#targets-consumers)
- Components that consume [Loki `LogsReceiver`](../../../compatibility/#loki-logsreceiver-consumers)

> Note
> 
> Connecting some components may not be sensible or components may require further configuration to make the connection work correctly. Refer to the linked documentation for more details.
