Plug that extracts AuditContext from a Plug.Conn and stores it in
conn.assigns[:audit_context].
Usage
# In a Phoenix router pipeline or endpoint:
plug Threadline.Plug
# With actor extraction (recommended):
plug Threadline.Plug, actor_fn: &MyApp.Auth.to_actor_ref/1Options
:actor_fn— a function(Plug.Conn.t() -> ActorRef.t() | nil)that extracts the current actor from the conn. Called duringcall/2. If omitted,audit_context.actor_refwill be nil.
What is extracted
actor_ref— result of:actor_fn(or nil)request_id— fromx-request-idheader, thenconn.assigns[:request_id], then nilcorrelation_id— fromx-correlation-idheader, or nilremote_ip— fromconn.remote_ip, formatted as a dotted-decimal string
PgBouncer note
This Plug does not call SET / SET LOCAL on the database connection. Request
metadata lives on conn.assigns only. This design is safe for PgBouncer
transaction-mode pooling.
PostgreSQL bridge (CTX-03)
To populate audit_transactions.actor_ref from capture triggers, the host
must set a transaction-local GUC inside the same Ecto.Repo.transaction/1
as audited writes, before the first row change in that transaction:
json = Threadline.Semantics.ActorRef.to_map(actor_ref) |> Jason.encode!()
Repo.transaction(fn ->
Repo.query!("SELECT set_config('threadline.actor_ref', $1::text, true)", [json])
# ... audited writes here ...
end)The trigger reads threadline.actor_ref via current_setting only; it never
calls set_config itself (see gate-01-01.md). See
test/threadline/capture/trigger_context_test.exs for the contract example.