Skip to main content

Postgresql Receiver

Status Available in: contrib Maintainers: @antonblock, @ishleenk17, @Caleb-Hurshman, @ebrdarSplunk, @XSAM, @akshays-19, @sv-splunk, @splunk-shanu Source: opentelemetry-collector-contrib

Supported Telemetry

Logs Metrics

Overview

Prerequisites

See PostgreSQL documentation for supported versions. The monitoring user must be granted SELECT on pg_stat_database.
[!NOTE] The feature gate receiver.postgresql.separateSchemaAttr addresses an inconsistency in how schema names are reported across different metric types. When enabled, schema names are consistently reported in a dedicated postgresql.schema.name resource attribute. Status: Alpha (disabled by default) When disabled (default behavior):
  • Table metrics: postgresql.table.name = "schema_name.table_name" (schema included)
  • Index metrics: postgresql.table.name = "table_name" (schema missing)
  • Function metrics: Schema reported separately in some cases
When enabled (recommended for consistency):
  • All metrics consistently use:
    • postgresql.schema.name = "schema_name"
    • postgresql.table.name = "table_name"
This ensures reliable correlation of metrics when tables with identical names exist across different schemas. To enable:
Note: This gate is mutually exclusive with receiver.postgresql.useOTelSemconv. Both cannot be enabled at the same time. See https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/29559 for more details.

Configuration

The following setting is required to create a database connection:
  • username
Exactly one of the following credential settings is also required:
  • password: A static PostgreSQL password.
  • db_auth: The component ID of a database authentication provider extension. The provider supplies the password, and can optionally override username, whenever the receiver opens a connection. db_auth and password are mutually exclusive.
For example, a provider extension must be declared, referenced from the receiver, and enabled in service.extensions:
The selected provider extension must be included in the Collector distribution. Provider-wide settings, such as the region above, belong to the extension; endpoint and username are passed to it by the receiver for each credential request. The following settings are optional:
  • endpoint (default = localhost:5432): The endpoint of the PostgreSQL server. Whether using TCP or Unix sockets, this value should be host:port. If transport is set to unix, the endpoint will internally be translated from host:port to /host.s.PGSQL.port
  • transport (default = tcp): The transport protocol being used to connect to PostgreSQL. Available options are tcp and unix.
  • databases (default = []): The list of databases for which the receiver will attempt to collect statistics. If an empty list is provided, the receiver will attempt to collect statistics for all non-template databases. This list applies to metrics only; the query sample and top query collectors ignore it and are filtered solely by exclude_databases.
  • exclude_databases (default = []): List of databases excluded from statistics, query samples, and top queries. Excluded databases are filtered out of every collection query and the receiver opens no per-database connection to them. Exception: the receiver always connects to the configured connect_database (default postgres) for discovery and server-level queries, even if it is listed here.
  • connect_database (default = postgres): The database the receiver connects to for discovery and server-level queries, including pg_stat_statements. Independent of databases — pg_stat_statements is tracked cluster-wide, so any database with the extension installed works as the connection target, regardless of which databases are being monitored. Use this if pg_stat_statements lives outside postgres, or if you connect through a dedicated monitoring-only database:
[!NOTE] Managed PostgreSQL services create internal databases that no customer credential can connect to. The receiver discovers them like any other database and logs a connection error on every scrape. If you use one of these services, add its internal databases to exclude_databases: Example: exclude_databases: [rdsadmin]
The following settings are also optional and nested under tls to help configure client transport security
  • insecure (default = false): Whether to enable client transport security for the PostgreSQL connection.
  • insecure_skip_verify (default = true): Whether to validate server name and certificate if client transport security is enabled.
  • cert_file (default = $HOME/.postgresql/postgresql.crt): A certificate used for client authentication, if necessary.
  • key_file (default = $HOME/.postgresql/postgresql.key): An SSL key used for client authentication, if necessary.
  • ca_file (default = ""): A set of certificate authorities used to validate the database server’s SSL certificate.
  • collection_interval (default = 10s): This receiver collects metrics on an interval. This value must be a string readable by Golang’s time.ParseDuration. Valid time units are ns, us (or µs), ms, s, m, h.
  • initial_delay (default = 1s): defines how long this receiver waits before starting.

Query Sample Collection

We provide functionality to collect the query sample from PostgreSQL. It will get historical query from pg_stat_activity. To enable it, you will need the following configuration
By default, query sample collection is disabled, also note, to use it, you will need to grant the user you are using pg_monitor. Take the example from testdata/integration/init.sql
To correlate query samples with traces, set the PostgreSQL application_name for the client connection to a valid W3C traceparent value before running the query:
When query sample collection observes a valid traceparent in application_name, the receiver sets the trace ID and span ID on the emitted db.server.query_sample log record. This enables correlation between the query sample and the originating trace. The following options are available:
  • max_rows_per_query: (optional, default=1000) The max number of rows would return from the query against pg_stat_activity.

Top Query Collection

We provide functionality to collect the most executed queries from PostgreSQL. It will get data from pg_stat_statements and report incremental value of total_exec_time, total_plan_time, calls, rows, shared_blks_dirtied, shared_blks_hit, shared_blks_read, shared_blks_written, temp_blks_read, temp_blks_written. To enable it, you will need the following configuration
Along with those attributes, we will also report the query plan we gathered if it is possible. By default, top query collection is disabled, also note, to use it, you will need to create the extension in the database the receiver connects to (connect_database, default postgres) — pg_stat_statements is tracked cluster-wide, so it does not need to be created in every database. Take the example from testdata/integration/02-create-extension.sh
[!NOTE] This is different from vector metrics below, which query per-database clients — connect_database has no effect there, and pg_stat_statements must be installed in every scanned database for vector metrics to work.
The following options are available:
  • max_rows_per_query: (optional, default=1000) The max number of rows would return from the query against pg_stat_statements.
  • top_n_query: (optional, default=200) The maximum number of active queries to report (to the next consumer) in a single run.
  • max_explain_each_interval: (optional, default=1000). The maximum number of explain query to be sent in each scrape interval. The top query collection would not get the query plan directly. Instead, we need to mimic the query in the database and get the query plan from database separately. This could lead some resources usage and limit this will reduce the impact on your database.
  • query_plan_cache_size: (optional, default=1000). The query plan cache size. Once we got explain for one query, we will store it in the cache. This defines the cache’s size for query plan.
  • query_plan_cache_ttl: (optional, default=1h). How long before the query plan cache got expired. Example values: 1m, 1h.
  • collection_interval: (optional, default=60s). This receiver can collect top_query metrics on an interval. If not provided then the global collection_interval takes effect. This value must be a string readable by Golang’s time.ParseDuration. Valid time units are ns, us (or µs), ms, s, m, h.

db.server.query_plan

By default, db.server.top_query carries the query’s execution plan in its postgresql.query_plan attribute. Enabling db.server.query_plan isolates the plan on a record of its own, where it can be filtered, routed or dropped independently of the query statistics, and where an oversized plan does not take those statistics with it when a batcher splits by size. db.server.top_query is then emitted without its postgresql.query_plan attribute, and the plan itself is reported on db.server.query_plan, joined back to its query via postgresql.queryid, db.namespace and postgresql.rolname — queryid alone can repeat across databases and across roles in the same database. A query with no plan available yet (not yet explained, or the EXPLAIN failed) produces no db.server.query_plan record. Leaving db.server.query_plan disabled preserves the previous behavior exactly. Known limitations of the join key:
  • It doesn’t distinguish toplevel, so a top-level statement and a nested one it calls can still collide (only with pg_stat_statements.track = all, not the default).
  • postgresql.rolname is empty once the role that ran the statement is dropped, so two rows from different dropped roles can collide too (mainly with ephemeral roles or credential rotation).
db.server.query_plan is sourced from the same collection as db.server.top_query and only splits the plan out of it, so it needs no grants of its own, and enabling it without db.server.top_query is a configuration error.

Vector Metrics

The receiver can report pgvector similarity-search and insert activity through a set of opt-in metrics. Prerequisites:
  • PostgreSQL 13 or later.
  • The pgvector extension installed in each scanned database. The l1, hamming, and jaccard distance functions additionally require pgvector 0.7.0 or later.
  • The pg_stat_statements extension (version 1.8+) installed and enabled in each scanned database (see below).

Search metrics

Three metrics report similarity-search activity
  • postgresql.vector.search.calls: the cumulative number of vector search executions.
  • postgresql.vector.search.duration: the cumulative execution time (in seconds) of vector searches.
  • postgresql.vector.search.rows_returned: the cumulative number of rows returned by vector searches.
[!NOTE] The distance function is inferred from the query text alone, so the receiver cannot tell which operator implementation is actually invoked. If the pg_trgm extension is also installed, its text-similarity <-> operator is indistinguishable from pgvector’s L2 <-> operator, so queries such as ORDER BY text_col <-> 'abc' may be counted under the l2 distance function.

Insert metrics

These metrics report write activity against pgvector tables
  • postgresql.vector.insert.rows: the cumulative number of vectors inserted.
  • postgresql.vector.insert.duration: the cumulative execution time (in seconds) of those inserts.
All of these metrics are disabled by default. Enable the ones you need via:
The pg_stat_statements extension must be created in every database you want these metrics collected from:

Example Configuration

The full list of settings exposed for this receiver are documented in config.go with detailed sample configurations in testdata/config.yaml. TLS config is documented further under the opentelemetry collector’s configtls package.

Connection pool feature

The feature gate receiver.postgresql.connectionPool allows to enable the creation & reuse of a pool per database for the connections instead of creating & closing on each scrape. This is generally a useful optimization but also alleviates the volume of generated audit logs when the PostgreSQL instance is configured with log_connections=on and/or log_disconnections=on. When this feature gate is enabled, the following optional settings are available nested under connection_pool to help configure the connection pools:
  • max_idle_time: The maximum amount of time a connection may be idle before being closed.
  • max_lifetime: The maximum amount of time a connection may be reused.
  • max_idle: The maximum number of connections in the idle connection pool.
  • max_open: The maximum number of open connections to the database.
Those settings and their defaults are further documented in the sql/database package. The connection pool composes with a db_auth block (e.g. AWS IAM). The credential is re-resolved on every new connection the pool opens, so a short-lived token (an RDS IAM token lives ~15 minutes) is re-minted as the pool grows or replaces connections, and a connection is never opened with an expired token. Connections already established stay valid for their lifetime — IAM authenticates only at connection open, not per query — so tune max_lifetime to bound how long a connection lives before it must reconnect with a fresh token.

Example Configuration

OpenTelemetry semantic conventions feature gate

The feature gate receiver.postgresql.useOTelSemconv (alpha, disabled by default) controls the resource model used by this receiver:
  • Gate disabled (default): Legacy per-entity resource model. Each database, table, and index emits metrics under a separate resource with postgresql.database.name, postgresql.table.name, postgresql.index.name, and postgresql.schema.name as resource attributes. service.instance.id is in host:port format.
  • Gate enabled: Single resource per server. All metrics are emitted under one resource with service.instance.id (UUID v5) as a resource attribute, aligning with OpenTelemetry semantic conventions. Metric-level attributes db.namespace, db.collection.name, and postgresql.index.name are present on applicable metrics.
server.address and server.port are emitted in both models and are not affected by this gate. This gate is mutually exclusive with receiver.postgresql.separateSchemaAttr — both cannot be enabled simultaneously.

Server address resolution

server.address and server.port describe the monitored server. When endpoint is a loopback address (localhost, 127.0.0.1, or ::1), the server is only reachable because it is co-located with the collector, so server.address reports the name of the machine running the collector rather than the loopback address, which every monitored host would otherwise report identically. This is the same host already used to derive service.instance.id, and both are resolved when the receiver starts, so the two attributes always agree and a host name change is picked up on restart. Non-loopback endpoints are reported as configured, and with transport: unix the socket path is reported instead.

Metrics

Details about the metrics produced by this receiver can be found in metadata.yaml
[!NOTE] The optional postgresql.query.execution.time metric requires the pg_stat_statements extension to be installed and enabled.

Metrics

Attributes

Resource Attributes

Configuration

Example Configuration


Last generated: 2026-10-05