Changelog

Copy Markdown

All notable changes to this project are documented in this file.

[0.1.2]

Added

  • Transaction correlation id. Every event dispatched while a Repo.transaction/Ecto.Multi is open (schema-tracked Repo calls, and any manual emit/monitor made inside the transaction function) is now stamped with a shared transaction_id, generated once when the outermost transaction opens. A transaction touching several tables previously shipped as N fully uncorrelated log lines with no way to reconstruct that they were one unit; AuditTrail.get_logs(%{transaction_id: "..."}) now pulls the whole set back together. Added as a filter across the Loki reader, the Postgres/TimescaleDB adapter, and the Test adapter.
  • :telemetry events for the health of the logging pipeline itself (not your audit events — those go through your storage adapter): [:audit_trail, :buffer, :dropped], [:audit_trail, :buffer, :flushed], [:audit_trail, :shipper, :succeeded], [:audit_trail, :shipper, :failed], [:audit_trail, :dead_letter, :dropped], [:audit_trail, :dead_letter, :redrive, :succeeded], [:audit_trail, :dead_letter, :redrive, :failed], and [:audit_trail, :crash, :reported]. See the new "Telemetry" section in the README. :telemetry is now an explicit dependency (previously only pulled in transitively via Ecto).
  • Persistent dead-letter queue (opt-in). New dead_letter_persistent: true config backs AuditTrail.DeadLetter with :dets instead of plain ETS, so entries queued while Loki is down survive a node restart/deploy instead of being lost. Off by default — existing behavior is unchanged unless you opt in. Pairs with the new dead_letter_path: config.
  • AuditTrail.clear_actor/0 and AuditTrail.clear_tenant/0 — reset the process-dictionary actor/tenant back to their defaults. Previously only reachable via the internal AuditTrail.ActorStore.clear/0/AuditTrail.TenantStore.clear/0, with no public, documented way to do this. Useful for pooled/long-lived processes (a GenServer working through a job queue, shared test processes) that shouldn't leak one actor's/tenant's context into the next unit of work.
  • AuditTrail.DeadLetter gained proper documentation for its existing operational functions (push/1, dump/0, count/0, clear/0, redrive/0) — previously undocumented entirely, with redrive/0's explanation only ever existing as a source comment that never reached hexdocs.

Fixed

  • AuditTrail.LiveViewAudit now truncates oversized param values the same way AuditTrail.ControllerAudit already did. A LiveView event pushing a large list or a base64 blob through handle_event params (e.g. from a JS hook) previously got dumped into the audit payload in full; it's now truncated the same as a controller file upload.
  • AuditTrail.DeadLetter no longer reports a failed redrive as a success. AuditTrail.Shipper.push/1 returned whatever AuditTrail.DeadLetter.push/1 returned on retry exhaustion — a GenServer.cast, which always returns :ok regardless of whether the entries are ever redelivered. redrive_batch/0 treated that :ok as a real success and deleted the original queued entries while a failed redrive silently re-queued a duplicate copy behind the scenes. Shipper.push/2 now returns a real :ok | {:error, reason}, and redrive calls it with dead_letter?: false so a failed redrive correctly leaves entries in place instead of duplicating them.

  • Closed a redaction gap in AuditTrail.Sanitizer and AuditTrail.Diff. Any struct not covered by a specific clause (an app-defined struct without an :id field, ending up in original_record:/params:/a tracked embed) was collapsed via inspect/1, which prints every field verbatim — including ones matching sensitive_fields/0 — bypassing redaction entirely. Such structs are now expanded to a plain map and redacted the same way any other map is.
  • LogQL injection in AuditTrail.Reader. Filter values (type, status, actor_id, tenant, resource, resource_id, operation, search) were interpolated directly into the LogQL query string with no escaping — a value containing " could break out of a label/line matcher and alter the query. All filter values are now escaped before interpolation.

Documentation

  • Full pass over every public function's @doc in lib/audit_trail.ex (monitor/4, emit/2, log_repo/5, log_external_api/3, set_actor/1, set_actor/2, get_actor/0, get_tenant/0, get_logs/1) — most previously rendered as a bare See AuditTrail.Logger.emit/2. stub on hexdocs, or nothing at all (get_logs/1, get_tenant/0). log_repo/5 in particular had no documentation or README mention anywhere despite being a real, distinct public API.
  • AuditTrail.Taskawait/2 had no documentation at all; async/1/start/1/start_link/1 were only covered collectively by the moduledoc (and start_link/1 wasn't mentioned anywhere). Each now has its own @doc.
  • child_spec/1 marked @doc false — it was showing up as a callable public function on hexdocs despite the README explicitly warning it should never be called directly.
  • AuditTrail.CrashReporter's four :logger handler callbacks and AuditTrail.Buffer's child_spec/1/start_link/1 were leaking onto their hexdocs pages as undocumented public functions (neither module used @impl/@doc false the way the rest of the codebase does). Marked @doc false with an explanation of why.
  • README: added the previously entirely-undocumented AuditTrail.Adapters.SMTP mailer option (only the Swoosh path was documented before), a full AuditTrail.Task usage example, and the full crash_routing match-type table ({:exception, ...} and {:source, ...} existed in code but were never documented — only {:module, ...} and :default were shown). Corrected the crash-dedup description, which undersold the actual behavior (a periodic digest email for recurring crashes, not just "emailed once").
  • README: new "Telemetry" section, "Correlating multi-table changes with transaction_id" subsection, updated "Buffer tuning" config block, and updated Limitations table entry for dead-letter durability now being fixable via config rather than a hard limitation.

[0.1.1]

  • Bump to v0.1.1, loosen decimal constraint to ~> 2.4 or ~> 3.0.
  • Sanitizer module updates; removed a missing flush function reference; mix file updates.

[0.1.0]

  • Initial release.