OpenTelemetry tracing for pgx v5. Attach
QueryTracer to any pgx.ConnConfig or pgxpool.Config and every database
operation — queries, batch sends, prepared statements, COPY, and connections —
is automatically recorded as an OpenTelemetry span.
- Instruments all five pgx tracer interfaces:
QueryTracer,BatchTracer,ConnectTracer,PrepareTracer, andCopyFromTracer - Low-cardinality span names: extracts the first SQL keyword (
SELECT,INSERT, …) or uses an explicit-- name: Foocomment - Follows stable OpenTelemetry semantic conventions (
semconv/v1.40.0):db.namespace,db.operation.name,db.query.text,db.collection.name,server.address,server.port db.query.textis opt-in (IncludeStatement: true) to avoid recording sensitive SQL structure by default- Accepts an optional
TracerProviderfor scoped, test-friendly setup; falls back to the global provider when unset
go get github.com/pgx-contrib/pgxotelconfig, err := pgxpool.ParseConfig(os.Getenv("PGX_DATABASE_URL"))
if err != nil {
panic(err)
}
config.ConnConfig.Tracer = &pgxotel.QueryTracer{
Name: "my-service",
}
pool, err := pgxpool.NewWithConfig(context.Background(), config)
if err != nil {
panic(err)
}
defer pool.Close()
rows, err := pool.Query(context.Background(), "SELECT * FROM customer")
if err != nil {
panic(err)
}
defer rows.Close()Prefix any SQL string with -- name: <Identifier> to control the span name.
The comment is stripped from db.query.text automatically:
rows, err := pool.Query(ctx,
"-- name: ListActiveCustomers\nSELECT * FROM customer WHERE active = true",
)This produces a span named ListActiveCustomers instead of SELECT.
SQL is not recorded by default. Enable it per-tracer when the query text is not considered sensitive:
config.ConnConfig.Tracer = &pgxotel.QueryTracer{
Name: "my-service",
IncludeStatement: true,
}config.ConnConfig.Tracer = &pgxotel.QueryTracer{
Name: "my-service",
Provider: myTracerProvider,
}Every span carries the following attributes:
| Attribute | Value |
|---|---|
db.system.name |
postgresql |
db.namespace |
database name |
server.address |
host |
server.port |
port |
db.operation.name |
SELECT / INSERT / UPDATE / DELETE / UNKNOWN |
db.collection.name |
table name (CopyFrom only) |
db.query.text |
sanitized SQL (opt-in via IncludeStatement) |
Open in VS Code with the Dev Containers extension. The environment provides Go, PostgreSQL 18, and Nix automatically.
PGX_DATABASE_URL=postgres://vscode@postgres:5432/pgxotel?sslmode=disable
nix develop # enter shell with Go
go tool ginkgo run -r# Unit tests only (no database required)
go tool ginkgo run -r
# With integration tests
export PGX_DATABASE_URL="postgres://localhost/pgxotel?sslmode=disable"
go tool ginkgo run -r