Xqlite.Telemetry.OpenTelemetry (Xqlite v0.10.0)

View Source

A pure translation table from xqlite's telemetry events to OpenTelemetry's stable database semantic-convention attributes.

xqlite has NO OpenTelemetry dependency — you own the handler and the SDK. Feed any [:xqlite, ...] event through attributes/3 inside your own :telemetry handler and attach the returned map to the span you create; backends with database-aware tooling (latency by statement, DB overview pages) key off exactly these names.

def handle_event([:xqlite | _] = event, measurements, metadata, _cfg) do
  attrs = Xqlite.Telemetry.OpenTelemetry.attributes(event, measurements, metadata)
  # create/end your OTel span here, with `attrs` as span attributes
end

Targets the STABLE database conventions: db.system.name, db.query.text, db.operation.name, db.namespace, error.type. Keys are strings, values strings — ready for OTel attribute APIs.

If first-class instrumentation lands later (an optional opentelemetry_api dependency, or a companion instrumentation package), it builds on this module as its attribute vocabulary — the mapping here is the contract either way.

Sources

Every mapped name traces to the OpenTelemetry specification:

Verified against the stable revision of the database conventions on 2026-07-17; the pre-stabilization names (db.system, db.statement) are deliberately NOT emitted.

Summary

Functions

Maps one xqlite telemetry event to semantic-convention attributes.

Suggested span name per the conventions' priority chain: "{operation} {namespace}" when both are known, the operation alone otherwise, "sqlite" as the last resort.

Functions

attributes(event, measurements, metadata)

@spec attributes([atom()], map(), map()) :: %{required(String.t()) => String.t()}

Maps one xqlite telemetry event to semantic-convention attributes.

Always includes db.system.name => "sqlite". Adds db.operation.name derived from the event, db.query.text when the event's metadata carries :sql, db.namespace when it carries :path (connection open/close; nil paths — temporary databases — are skipped), and error.type for error results and exceptions (the structured reason's leading atom, or the exception module).

Everything else in the metadata (result classes, counters, xqlite's own identifiers) remains available to your handler directly — this function maps only the semantic-convention vocabulary.

span_name(event, metadata \\ %{})

@spec span_name([atom()], map()) :: String.t()

Suggested span name per the conventions' priority chain: "{operation} {namespace}" when both are known, the operation alone otherwise, "sqlite" as the last resort.