Ditliti.Db (ditliti v0.1.2)

Copy Markdown View Source

Database query auto-instrumentation.

trace_query/3 wraps a query call with a db.query span carrying OpenTelemetry-shaped database attributes. attach_ecto_telemetry/3 hooks Ecto's own [:my_app, :repo, :query] telemetry event - no Repo wrapping, works for the query builder, changesets, and raw Repo.query!/2 alike.

The backend (ingestion-api) parameterizes and sanitizes db.query.text server-side and derives db.query.summary / db.operation.name / db.collection.name / ditliti.query_hash from it - this only needs to supply the real SQL text, exactly like every other span already sent by this SDK travels over the same trust boundary to the user's own ingestion-api.

Neither ever changes the wrapped call's exception flow: span-recording failures are swallowed, and the original exception (if any) is always re-raised unchanged.

Summary

Functions

Attaches a :telemetry handler for event_name (e.g. [:my_app, :repo, :query] - see your Ecto repo's :telemetry_prefix, default [:my_app, :repo] with :query appended) that records every executed query as a db.query span with the correct, already-measured duration.

Wraps execute (a zero-arity function performing the query) with a db.query span. Returns {client, execute.() result} - client is returned for consistency with the rest of this immutable-struct SDK, though tracing a span never changes the client itself.

Functions

attach_ecto_telemetry(client, event_name, opts \\ [])

@spec attach_ecto_telemetry(Ditliti.t(), [atom()], keyword()) ::
  :ok | {:error, :already_exists}

Attaches a :telemetry handler for event_name (e.g. [:my_app, :repo, :query] - see your Ecto repo's :telemetry_prefix, default [:my_app, :repo] with :query appended) that records every executed query as a db.query span with the correct, already-measured duration.

Correlates to the trace of the process handling the current request via Ditliti.current_trace/0 (set automatically by Ditliti.start_trace/2 when called earlier in the same process, e.g. from a Phoenix Plug) - falls back to client's own trace, or starts a fresh one, if none is set.

trace_query(client, opts, execute)

@spec trace_query(Ditliti.t(), keyword(), (-> result)) :: {Ditliti.t(), result}
when result: var

Wraps execute (a zero-arity function performing the query) with a db.query span. Returns {client, execute.() result} - client is returned for consistency with the rest of this immutable-struct SDK, though tracing a span never changes the client itself.

Options:

  • :system (required) - e.g. "postgresql", "mysql", "sqlite"
  • :text (required) - the real SQL text
  • :collection / :operation - optional, server infers if omitted
  • :row_count - (result -> non_neg_integer() | nil), defaults to inferring from {:ok, %{rows: rows}} / %{num_rows: n} / list shapes