Changelog
Copy MarkdownAll 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.Multiis open (schema-tracked Repo calls, and any manualemit/monitormade inside the transaction function) is now stamped with a sharedtransaction_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. :telemetryevents 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.:telemetryis now an explicit dependency (previously only pulled in transitively via Ecto).- Persistent dead-letter queue (opt-in). New
dead_letter_persistent: trueconfig backsAuditTrail.DeadLetterwith:detsinstead 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 newdead_letter_path:config. AuditTrail.clear_actor/0andAuditTrail.clear_tenant/0— reset the process-dictionary actor/tenant back to their defaults. Previously only reachable via the internalAuditTrail.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.DeadLettergained proper documentation for its existing operational functions (push/1,dump/0,count/0,clear/0,redrive/0) — previously undocumented entirely, withredrive/0's explanation only ever existing as a source comment that never reached hexdocs.
Fixed
AuditTrail.LiveViewAuditnow truncates oversized param values the same wayAuditTrail.ControllerAuditalready did. A LiveView event pushing a large list or a base64 blob throughhandle_eventparams (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.DeadLetterno longer reports a failed redrive as a success.AuditTrail.Shipper.push/1returned whateverAuditTrail.DeadLetter.push/1returned on retry exhaustion — aGenServer.cast, which always returns:okregardless of whether the entries are ever redelivered.redrive_batch/0treated that:okas a real success and deleted the original queued entries while a failed redrive silently re-queued a duplicate copy behind the scenes.Shipper.push/2now returns a real:ok | {:error, reason}, and redrive calls it withdead_letter?: falseso a failed redrive correctly leaves entries in place instead of duplicating them.- Closed a redaction gap in
AuditTrail.SanitizerandAuditTrail.Diff. Any struct not covered by a specific clause (an app-defined struct without an:idfield, ending up inoriginal_record:/params:/a tracked embed) was collapsed viainspect/1, which prints every field verbatim — including ones matchingsensitive_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
@docinlib/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 bareSee AuditTrail.Logger.emit/2.stub on hexdocs, or nothing at all (get_logs/1,get_tenant/0).log_repo/5in particular had no documentation or README mention anywhere despite being a real, distinct public API. AuditTrail.Task—await/2had no documentation at all;async/1/start/1/start_link/1were only covered collectively by the moduledoc (andstart_link/1wasn't mentioned anywhere). Each now has its own@doc.child_spec/1marked@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:loggerhandler callbacks andAuditTrail.Buffer'schild_spec/1/start_link/1were leaking onto their hexdocs pages as undocumented public functions (neither module used@impl/@doc falsethe way the rest of the codebase does). Marked@doc falsewith an explanation of why.- README: added the previously entirely-undocumented
AuditTrail.Adapters.SMTPmailer option (only the Swoosh path was documented before), a fullAuditTrail.Taskusage example, and the fullcrash_routingmatch-type table ({:exception, ...}and{:source, ...}existed in code but were never documented — only{:module, ...}and:defaultwere 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
decimalconstraint to~> 2.4 or ~> 3.0. - Sanitizer module updates; removed a missing
flushfunction reference; mix file updates.
[0.1.0]
- Initial release.