Threadline.Telemetry (Threadline v1.0.0)

Copy Markdown View Source

Threadline.Telemetry defines Threadline's emitted event contract and lets hosts record accurate transaction table counts.

Threadline emits the following :telemetry events. No event carries row values, actor identifiers, correlation ids, or free-text reasons — with one narrow exception: [:threadline, :retention, :purge, :exception]'s reason/stacktrace metadata, forwarded verbatim from a raised exception for incident diagnosis (see the Telemetry guide's "Keep row data out of your handlers" section before logging it anywhere durable). See the guide for an attach_many example per family, a telemetry_metrics example, handler-safety and cardinality warnings, and a recipe for observing Threadline's own repo queries through your host's [:my_app, :repo, :query] event.

EventMeasurementsMetadataWhen emitted
[:threadline, :transaction, :committed]table_count—an AuditTransaction is committed
[:threadline, :action, :recorded]status—Threadline.record_action/2 completes, whether it succeeds or fails
[:threadline, :health, :checked]covered, expected_uncovered, uncovered—Threadline.Health.trigger_coverage/1 returns
[:threadline, :health, :checked, :error]—exceptiona polled coverage check raises
[:threadline, :health, :findings_checked]errors, warnings—Threadline.Health.trigger_findings/1 returns
[:threadline, :operator_surface, :authorize]resultpath, scope_keysan operator-surface mount or request is authorized, denied, or errors
[:threadline, :operator_surface, :export_authorize]count, result—an export-specific authorization check raises
[:threadline, :operator_surface, :actor_ref_mismatch]count—the session actor and the scope-derived actor disagree
[:threadline, :export, :completed]duration, row_countformat, truncatedan export (eager CSV/JSON, the async orchestrator job, or the chunked operator-surface download) finishes successfully
[:threadline, :export, :failed]duration, row_countformat, error_kind, exceptionan eager facade filter/option or direct Export option validation raises; or an eager CSV/JSON read, async orchestrator job, or chunked operator-surface download fails
[:threadline, :retention, :purge, :start]monotonic_time, system_timedry_run, telemetry_span_contextafter purge/1's input checks pass, when the purge work begins
[:threadline, :retention, :purge, :stop]batches_run, deleted_changes, deleted_transactions, duration, monotonic_timedry_run, telemetry_span_contextwhen the run or preview returns
[:threadline, :retention, :purge, :exception]duration, monotonic_timedry_run, kind, reason, stacktrace, telemetry_span_contextwhen the database raises mid-run
[:threadline, :retention, :batch_purged]deleted_changes, deleted_transactions, duration—after a purge_loop step's change delete_all and full orphan drain both return, once per step including the terminating empty one
[:threadline, :row_history, :truncated]limitschemaThreadline.row_history/3's default 200-row cap dropped older changes

[:threadline, :transaction, :committed] is automatically emitted (with table_count: 0) when Threadline.record_action/2 succeeds. For accurate per-transaction counts, call Threadline.Telemetry.transaction_committed/2 explicitly after a known DB transaction commit.

Every emission in this library goes through a @doc false helper function in this module; :telemetry.execute/3 and :telemetry.span/3 are called only here. Every event this module can emit, along with its measurement and metadata keys, is held in an internal registry exposed through __events__/0 (@doc false) — not a public events/0 — for use by this library's own test suite.

Entry points

  • transaction_committed/2 — call after a host database transaction commits when its audited table count is known.
  • emit_action_recorded/1, emit_transaction_committed_proxy/0, emit_health_checked/3, emit_health_checked_error/1, emit_findings_checked/2, emit_operator_surface_authorize/3, emit_export_authorize_error/0, emit_actor_ref_mismatch/0, emit_export_completed/4, emit_export_failed/5, purge_span/2, emit_row_history_truncated/2, and emit_batch_purged/3 — internal @doc false hooks called by Threadline at the matching event sites; host applications should subscribe to the events instead of calling these.
  • __events__/0 — the internal registry used by the library's contract tests, not an adopter entry point.

Usage

Attach handlers in your application's start/2 callback:

:telemetry.attach(
  "my-app-audit",
  [:threadline, :action, :recorded],
  &MyApp.Instrumentation.handle_event/4,
  nil
)

Summary

Types

An opaque host transaction result passed to transaction_committed/2.

Functions

Emits [:threadline, :transaction, :committed] with the given table count.

Types

transaction_committed_opt()

@type transaction_committed_opt() :: {:table_count, integer()}

An option accepted by transaction_committed/2.

transaction_value()

@type transaction_value() ::
  atom()
  | number()
  | bitstring()
  | pid()
  | port()
  | reference()
  | function()
  | tuple()
  | maybe_improper_list(transaction_value(), transaction_value())
  | %{optional(transaction_value()) => transaction_value()}

An opaque host transaction result passed to transaction_committed/2.

Functions

transaction_committed(transaction, opts \\ [])

@spec transaction_committed(transaction_value(), [transaction_committed_opt()]) :: :ok

Emits [:threadline, :transaction, :committed] with the given table count.

Call this after a DB transaction that you know produced AuditTransaction records, when you need accurate table_count measurements.

Options

  • :table_count — integer. Defaults to 0; reports the number of audited tables in the transaction.

Other option keys are ignored.

Returns

  • :ok after the telemetry event is emitted.

Example

{:ok, txn} = MyApp.Repo.transaction(fn ->
  # ... your writes ...
end)
Threadline.Telemetry.transaction_committed(txn, table_count: 3)