> ## Documentation Index
> Fetch the complete documentation index at: https://otel.fyi/llms.txt
> Use this file to discover all available pages before exploring further.

# Sqlquery

> OpenTelemetry receiver for Sqlquery

# Sqlquery Receiver

![Status](https://img.shields.io/badge/status-alpha-red)

**Available in:** `contrib`

**Maintainers:** [@dmitryax](https://github.com/dmitryax), [@crobert-1](https://github.com/crobert-1)

**Source:** [opentelemetry-collector-contrib](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/sqlqueryreceiver)

## Supported Telemetry

![Logs](https://img.shields.io/badge/logs-development-blue) ![Metrics](https://img.shields.io/badge/metrics-alpha-green)

## Overview

> :construction: This receiver is in **ALPHA**. Behavior, configuration fields, and log or metric data model are subject to
> change.

## Configuration

**Connection Configuration (choose one approach):**

**Option 1: Individual connection parameters** (cannot be used when `datasource` is set):

* `host` (required): The hostname or IP address of the database server.
  * For the `sqlserver` driver, an instance appended to the hostname (e.g. `hostname1/instance1`) will be parsed properly into this connection string: `sqlserver://username:password@host:port/instance`.
* `port` (required, except optional for `sqlserver`): The port number of the database server.
* `database` (required): The name of the database to connect to.
* `username` (optional): The username for database authentication.
  * The `username` will be properly escaped and securely handled when building the connection string. Special characters (such as #, @, %, etc.) are automatically URL-encoded to ensure proper connection string formatting.
  * For `mysql`: No URL encoding is applied
* `password` (optional): The password for database authentication. Supports environment variable substitution.
  * The `password` field supports sensitive value handling through environment variables or other secure value sources. Special characters (such as #, @, %, etc.) are automatically URL-encoded to ensure proper connection string formatting.
  * For `mysql`: No URL encoding is applied
* `additional_params` (optional): Additional driver-specific connection parameters.

**Option 2: Datasource string:**

* `datasource` (required): The datasource value passed to [sql.Open](https://pkg.go.dev/database/sql#Open). This value is used instead of the individual connection parameters listed above and does not perform any special character escaping. This is a driver-specific string usually consisting of at least a database name and connection information. This is sometimes referred to as the "connection string" in driver documentation. Examples:

  * [clickhouse](https://github.com/clickhouse/clickhouse-go) - `clickhouse://username:userpassword@localhost:9000/default?dial_timeout=200ms&read_timeout=30s&max_execution_time=60`
  * [hdb](https://github.com/SAP/go-hdb) - `hdb://<USER>:<PASSWORD>@something.hanacloud.ondemand.com:443?TLSServerName=something.hanacloud.ondemand.com`
  * [mysql](https://github.com/go-sql-driver/mysql) - `username:user_password@tcp(localhost:3306)/db_name`
  * [oracle](https://github.com/sijms/go-ora) - `oracle://username:user_password@localhost:1521/FREEPDB1`
  * [postgres](https://github.com/lib/pq) - `host=localhost port=5432 user=username password=user_password sslmode=disable`
  * [snowflake](https://github.com/snowflakedb/gosnowflake) - `username[:password]@<account_identifier>/dbname/schemaname[?param1=value&...&paramN=valueN]`
  * [sqlserver](https://github.com/microsoft/go-mssqldb) - `sqlserver://username:user_password@localhost:1433?database=db_name`
  * [tds](https://github.com/thda/tds) - `tds://username:user_password@localhost:5000/db_name`

**Other configuration fields:**

* `driver` (required): The name of the database driver: one of *postgres*, *mysql*, *snowflake*, *sqlserver*, *hdb* (SAP
  HANA), *oracle* (Oracle DB), *tds* (SapASE/Sybase), *clickhouse*.
* `queries` (required): A list of queries, where a query is a sql statement and one or more `logs` and/or `metrics` sections (details below).
* `collection_interval`(optional): The time interval between query executions. Defaults to *10s*.
* `initial_delay` (default = `1s`): defines how long this receiver waits before starting.
* `storage` (optional, default `""`): The ID of a [storage][storage_extension] extension to be used to [track processed results](#tracking-processed-results).
* `telemetry` (optional) Defines settings for the component's own telemetry - logs, metrics or traces.
  * `telemetry.logs` (optional) Defines settings for the component's own logs.
    * `telemetry.logs.query` (optional, default `false`) If set to `true`, every time a SQL query is run, the text of the query and the values of its parameters will be logged together with the debug log `"Running query"`.
* `max_open_conn` (optional, default `0`): The maximumn number of open connections to the sql server. \<= 0 means unlimited

[storage_extension]: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/extension/storage/filestorage

### Queries

A *query* consists of a sql statement and one or more `logs` and/or `metrics` section.
At least one `logs` or one `metrics` section is required.
Note that technically you can put both `logs` and `metrics` sections in a single query section,
but it's probably not a real world use case, as the requirements for logs and metrics queries
are quite different.

Additionally, each `query` section supports the following properties:

* `tracking_column` (optional, default `""`) Applies only to logs. In case of a parameterized query,
  defines the column to retrieve the value of the parameter on subsequent query runs.
  See the below section [Tracking processed results](#tracking-processed-results).
* `tracking_start_value` (optional, default `""`) Applies only to logs. In case of a parameterized query, defines the initial value for the parameter.
  See the below section [Tracking processed results](#tracking-processed-results).
* `ignore_null_values` (optional, default `false`) When set to `true`, suppresses warning logs about NULL values encountered in query result columns. This is useful when queries return NULL in columns that are not referenced in the metric or log configuration.
* `attribute_columns`(optional): a list of column names in the returned dataset used to set attributes on the signal.
  These attributes may be case-sensitive, depending on the driver (e.g. Oracle DB).

### Example using datasource:

```yaml theme={null}
receivers:
  sqlquery:
    driver: postgres
    datasource: "host=localhost port=5432 user=postgres password=s3cr3t sslmode=disable"
    queries:
      - sql: "select * from my_logs where log_id > $$1"
        tracking_start_value: "10000"
        tracking_column: log_id
        logs:
          - body_column: log_body
      - sql: "select count(*) as count, genre from movie group by genre"
        metrics:
          - metric_name: movie.genres
            value_column: "count"
```

### Example without using datasource:

```yaml theme={null}
receivers:
  sqlquery:
    driver: postgres
    host: localhost
    port: 5432
    user: postgres
    password: s3cr3t
    additional_params:
      sslmode: disable
    queries:
      - sql: "select * from my_logs where log_id > $$1"
        tracking_start_value: "10000"
        tracking_column: log_id
        logs:
          - body_column: log_body
      - sql: "select count(*) as count, genre from movie group by genre"
        metrics:
          - metric_name: movie.genres
            value_column: "count"
```

### SQL Server example without using datasource:

```yaml theme={null}
receivers:
  sqlquery:
    driver: sqlserver
    host: localhost/instance
    user: sql_server
    password: s3cr3t
    additional_params:
      sslmode: disable
    queries:
      - sql: "select * from my_logs where log_id > $$1"
        tracking_start_value: "10000"
        tracking_column: log_id
        logs:
          - body_column: log_body
      - sql: "select count(*) as count, genre from movie group by genre"
        metrics:
          - metric_name: movie.genres
            value_column: "count"
```

#### Logs Queries

The `logs` section is in development.

* `body_column` (required) defines the column to use as the log record's body.

##### Tracking processed results

With the default configuration and a non-parameterized logs query like `select * from my_logs`,
the receiver will run the same query every collection interval, which can cause reading the same rows
over and over again, unless there's an external actor removing the old rows from the `my_logs` table.

To prevent reading the same rows on every collection interval, use a parameterized query like `select * from my_logs where id_column > ?`,
together with the `tracking_start_value` and `tracking_column` configuration properties.
The receiver will use the configured `tracking_start_value` as the value for the query parameter when running the query for the first time.
After each query run, the receiver will store the value of the `tracking_column` from the last row of the result set and use it as the value for the query parameter on next collection interval. To prevent duplicate log downloads, make sure to sort the query results in ascending order by the tracking\_column value.

Note that the notation for the parameter depends on the database backend. For example in MySQL this is `?`, in PostgreSQL this is `$1`, in Oracle this is any string identifier starting with a colon `:`, for example `:my_parameter`.

Use the `storage` configuration property of the receiver to persist the tracking value across collector restarts.

#### Metrics queries

Each `metrics` section consists of a
`metric_name`, a `value_column`, and additional optional fields.
Each *metric* in the configuration will produce one OTel metric per row returned from its sql query.

* `metric_name`(required): the name assigned to the OTel metric.
* `value_column`(required): the column name in the returned dataset used to set the value of the metric's datapoint.
  This may be case-sensitive, depending on the driver (e.g. Oracle DB).
* `data_type` (optional): can be `gauge` or `sum`; defaults to `gauge`.
* `value_type` (optional): can be `int` or `double`; defaults to `int`.
* `monotonic` (optional): boolean; whether a cumulative sum's value is monotonically increasing (i.e. never rolls over
  or resets); defaults to false.
* `aggregation` (optional): only applicable for `data_type=sum`; can be `cumulative` or `delta`; defaults
  to `cumulative`.
* `description` (optional): the description applied to the metric.
* `unit` (optional): the units applied to the metric.
* `static_attributes` (optional): static attributes applied to the metrics.
* `start_ts_column` (optional): the name of the column containing the start timestamp, the value of which is applied to
  the metric's start timestamp (otherwise the current time is used). Only applies if the metric is of type cumulative
  sum.
* `ts_column` (optional): the name of the column containing the timestamp, the value of which is applied to the
  metric's timestamp. This can be current timestamp depending upon the time of last recorded metric's datapoint.
* `row_condition` (optional): when set, only rows where the specified column equals the specified value are used
  to produce this metric. Rows that do not match are silently skipped. This is useful for pivot-style result
  sets where each row encodes a different metric (e.g. `SHOW LISTS` in pgbouncer).
  * `column` (required): the column name to evaluate.
  * `value` (required): the expected string value the column must equal for the row to be included.

### Example

```yaml theme={null}
receivers:
  sqlquery:
    driver: postgres
    datasource: "host=localhost port=5432 user=postgres password=s3cr3t sslmode=disable"
    storage: file_storage
    queries:
      - sql: "select * from my_logs where log_id > $$1"
        tracking_start_value: "10000"
        tracking_column: log_id
        logs:
          - body_column: log_body
            attribute_columns: ["log_attribute_1", "log_attribute_2"]
      - sql: "select count(*) as count, genre from movie group by genre"
        metrics:
          - metric_name: movie.genres
            value_column: "count"
            attribute_columns: ["genre"]
            static_attributes:
              dbinstance: mydbinstance
```

Given a `movie` table with three rows:

| name      | genre  |
| --------- | ------ |
| E.T.      | sci-fi |
| Star Wars | sci-fi |
| Die Hard  | action |

If there are two rows returned from the query `select count(*) as count, genre from movie group by genre`:

| count | genre  |
| ----- | ------ |
| 2     | sci-fi |
| 1     | action |

then the above config will produce two metrics at each collection interval:

```
Metric #0
Descriptor:
     -> Name: movie.genres
     -> DataType: Gauge
NumberDataPoints #0
Data point attributes:
     -> genre: STRING(sci-fi)
     -> dbinstance: STRING(mydbinstance)
Value: 2

Metric #1
Descriptor:
     -> Name: movie.genres
     -> DataType: Gauge
NumberDataPoints #0
Data point attributes:
     -> genre: STRING(action)
     -> dbinstance: STRING(mydbinstance)
Value: 1
```

#### Row Condition Example

Some databases expose pivot-style views where each row represents a different metric, identified by a name column.
For example, pgbouncer's `SHOW LISTS` command returns:

```
     list      | items
---------------+-------
 databases     |     8
 pools         |     4
 users         |     2
 free_clients  |    25
 used_servers  |     5
```

Use `row_condition` to extract a single row as a dedicated metric:

```yaml theme={null}
receivers:
  sqlquery:
    driver: postgres
    datasource: "host=pgbouncer port=5432 user=pgbouncer dbname=pgbouncer sslmode=disable"
    queries:
      - sql: "SHOW LISTS"
        metrics:
          - metric_name: pgbouncer.lists.pools
            value_column: items
            value_type: int
            row_condition:
              column: list
              value: pools
          - metric_name: pgbouncer.lists.databases
            value_column: items
            value_type: int
            row_condition:
              column: list
              value: databases
          - metric_name: pgbouncer.lists.users
            value_column: items
            value_type: int
            row_condition:
              column: list
              value: users
```

This produces three separate metrics (`pgbouncer.lists.pools`, `pgbouncer.lists.databases`,
`pgbouncer.lists.users`), each sourced from the matching row only.

#### NULL values

If a query produces a NULL value, a warning will be logged unless `ignore_null_values` is set to true. Furthermore,
if a configuration references the column that produces a NULL value, an error will always be logged. However, in
either case, the receiver will continue to operate.

#### Oracle DB Driver Example

Refer to the config file [provided](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/sqlqueryreceiver/testdata/oracledb-receiver-config.yaml) for an example of using the
Oracle DB driver to connect and query the same table schema and contents as the example above.
The Oracle DB driver documentation can be found [here.](https://github.com/sijms/go-ora)

#### MySQL Datasource Format Example

The `datasource` format for MySQL works as follows:\
`user:password@tcp(host:port)/databasename`

## Configuration

### Example Configuration

```yaml theme={null}
sqlquery:
  collection_interval: 10s
  driver: postgres
  datasource: "host=localhost port=5432 user=me password=s3cr3t sslmode=disable"
  queries:
    - sql: "select count(*) as count, type from mytable group by type"
      metrics:
        - metric_name: val.count
          value_column: "count"
          attribute_columns: ["type"]
          data_type: sum
          value_type: int
          monotonic: false
          aggregation: cumulative
          static_attributes:
            foo: bar
```

***

*Last generated: 2026-07-06*
