OpenTelemetry Collector processor that normalizes parameterized SQL in span attributes (e.g. db.statement) so traces group by query shape instead of by literal values.
Supports all PEP 249 paramstyles.
- PEP 249 paramstyle normalization — Converts every placeholder style to a canonical form so
SELECT * FROM t WHERE id = ?,WHERE id = %s,WHERE id = :1,WHERE id = :id, andWHERE id = %(id)sare treated as the same statement for grouping. - IN-clause normalization — Optionally reduces
IN (?, ?, ?)(and equivalents in other paramstyles) to a single placeholder so different list lengths map to one normalized shape. - Configurable attribute keys — Apply normalization only to the span attributes you care about (default:
db.statement). - Parse-safe — Invalid or unparseable SQL is left unchanged; only successfully parsed statements are rewritten.
| paramstyle | Example placeholders | Supported |
|---|---|---|
| qmark | ? |
Yes (pass-through) |
| numeric | :1, :2, :3 |
Yes -> ? |
| named | :id, :name |
Yes -> ? |
| format | %s |
Yes -> ? |
| pyformat | %(id)s, %(name)s |
Yes -> ? |
Output is normalized to a single canonical form (parser-dependent; e.g. Vitess-style :v1) so all of the above produce the same logical shape for grouping.
Spec: PEP 249 – Python Database API Specification v2.0 (paramstyle)
Add this module (github.com/nilox94/otel-sqlparamstyle-processor) to your collector distribution (for example via the OpenTelemetry Collector Builder) and enable the sqlparamstyle processor in your traces pipeline.
Basic processor config:
processors:
sqlparamstyle:
attribute_keys:
- db.statement
normalize_in_clause: true| Option | Description | Default |
|---|---|---|
attribute_keys |
Span attribute keys to normalize (e.g. SQL in db.statement) |
["db.statement"] |
normalize_in_clause |
Collapse IN (?, ?, ?) to a single placeholder for grouping |
true |
For complete, working examples, see the examples README.
To see normalization without running a full collector, build and run the demo:
go run ./cmd/demoIt prints normalized output for sample statements in all five PEP 249 paramstyles.
If you prefer to build a custom collector binary that bundles this processor during development, you can use the OpenTelemetry Collector Builder (builder) with the configs in examples/.
See the “Collector Builder config (builder-config.yaml )” section in examples/README.md for copy-pasteable install, build, and run commands.
Quick before/after example:
db.statement = "SELECT * FROM users WHERE id IN (%s, %s, %s)"
becomes (with normalize_in_clause: true):
db.statement = "select * from users where id in (:v1)"
See examples/README.md for:
- A ready-to-run collector config using the
sqlparamstyleprocessor. - A collector-builder config that shows how to bundle this processor into a custom distribution.
Licensed under the Apache License, Version 2.0. See LICENSE for the full text.