Telemetry events emitted by the driver.
Attach to these to get request rates, latency and error breakdowns without instrumenting call sites.
There are three levels, and which one you want depends on the question:
| event | one span per | answers |
|---|---|---|
[:typedb, :transaction, …] | bracketed transaction | how long a unit of work held a transaction |
[:typedb, :operation, …] | API call | how long a query took, retries included |
[:typedb, :request, …] | HTTP attempt | how the network behaved |
Nest them: :request spans sit inside an :operation span, and :operation
spans sit inside a :transaction span. Measuring rates and latency from
:request alone overcounts, because a retried call emits several.
[:typedb, :operation, :start | :stop | :exception]
One span per call into the public API — TypeDB.query/4,
TypeDB.Database.list/1, TypeDB.Transaction.commit/2 and so on — covering
every retry and every token renewal it needed. This is the event to build
request rates and latency on.
Metadata:
:connection— the connection name:method—:get,:post,:putor:delete:route— a low-cardinality template such as"/transactions/:id/query", safe to use as a metric tag:path— the concrete path, which contains database, user and transaction names and is therefore high-cardinality:database— present whenever the call names one, whether in the path or in the request body:transaction_type—:read,:writeor:schema, on transaction and query calls:transaction_id— on calls against an open transaction:attempts— how many HTTP requests it took, on:stoponly.1on the happy path; more means the driver retried or renewed a token:error— theTypeDB.Error, on:stoponly, when the call failed
[:typedb, :transaction, :start | :stop | :exception]
One span per TypeDB.transaction/5, from opening the transaction to the
commit, rollback or close that ends it. The only span that covers more than
one request.
Metadata: :connection, :database, :type (:read, :write or
:schema), and on :stop an :outcome of :commit, :rollback, :close
or :commit_failed, plus :error when there was one. A block that raises
produces :exception rather than :stop.
[:typedb, :request, :start | :stop | :exception]
One span per HTTP request, including each retry and each renew-and-retry
attempt — so a single TypeDB.query/4 can produce several spans.
Measurements follow :telemetry.span/3: :system_time on start,
:duration (native units) on stop and exception.
Metadata:
:connection— the connection name:method—:get,:post,:putor:delete:path— the API path, e.g."/transactions/open". Database and user names are not stripped, so treat it as potentially high-cardinality:attempt— 1-based attempt number within this request:route,:database,:transaction_type,:transaction_id— as above:status— HTTP status, on:stoponly:error— theTypeDB.Errorwhen one was produced, on:stoponly
[:typedb, :retry, :exhausted]
Not a span: a single event, emitted when a call stops retrying and returns
the failure — because :max_retries ran out or because :deadline left no
room for another attempt. Measurements: :attempts. Metadata: the operation
span's, plus :error.
This is the one to alert on. A retry that succeeds is the driver doing its job; a retry that runs out is something upstream being broken for longer than the configuration was willing to wait.
[:typedb, :sign_in, :start | :stop | :exception]
One span per sign-in. A healthy connection produces one on start-up and one per token lifetime; a spike means tokens are being rejected.
Metadata: :connection, and :error on failure.
Just show me what it is doing
attach_default_logger/1 writes a line per operation, transaction, sign-in
and give-up, and is one call from your application's start/2:
TypeDB.Telemetry.attach_default_logger(:info)Prometheus / telemetry_metrics
Tag on :route, never on :path — the latter contains database, user and
transaction names, and a metric tagged by it grows without bound.
Telemetry.Metrics.distribution("typedb.operation.stop.duration",
unit: {:native, :millisecond},
tags: [:method, :route]
)
Telemetry.Metrics.counter("typedb.retry.exhausted.attempts", tags: [:route])
Summary
Functions
Logs one line per operation, transaction, sign-in and give-up.
Removes the handler attach_default_logger/1 installed.
The event prefix for operation spans.
The event prefix for request spans.
The event emitted when a call stops retrying.
The event prefix for sign-in spans.
The event prefix for bracketed-transaction spans.
Functions
@spec attach_default_logger(Logger.level() | keyword()) :: :ok | {:error, :already_exists}
Logs one line per operation, transaction, sign-in and give-up.
The gap between "the driver emits telemetry" and "I can see what my
application is doing" is otherwise an afternoon of handler plumbing per
project. Call this once, from your application's start/2:
TypeDB.Telemetry.attach_default_logger(:info)Give-ups are always logged at :warning, whatever level you pass, because
they mean something upstream is broken.
This is independent of the driver's own logging, which :log_level on the
connection controls; silencing one does not silence the other. Nothing is
attached unless you ask, so a library that depends on this driver does not
make your logs noisier.
Options
:level— the level for ordinary lines. Defaults to:info.
Returns {:error, :already_exists} if it is already attached.
@spec detach_default_logger() :: :ok | {:error, :not_found}
Removes the handler attach_default_logger/1 installed.
@spec operation_event() :: [atom()]
The event prefix for operation spans.
@spec request_event() :: [atom()]
The event prefix for request spans.
@spec retry_exhausted_event() :: [atom()]
The event emitted when a call stops retrying.
@spec sign_in_event() :: [atom()]
The event prefix for sign-in spans.
@spec transaction_event() :: [atom()]
The event prefix for bracketed-transaction spans.