audit

command
v1.1.15 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 19, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

README

Command Audit Logging Example

Record who did what, when, and with what outcome — an immutable audit trail for every command.

Regulated and security-sensitive systems need a tamper-evident record of every action taken and by whom, including the ones that failed. go-mink's AuditMiddleware writes one immutable entry per command dispatched through the bus, capturing the actor, command type, success/failure, error, and duration. Because it lives in the middleware pipeline, auditing is transparent to your handlers and applies uniformly to every command.

What this demonstrates

  • Audit middlewareAuditMiddleware(DefaultAuditConfig(store)) records one entry per command with no changes to handler code.
  • Success and failure captured — both a passing CreateAccount and a failing Withdraw are recorded, the latter with its error message.
  • Nested recoveryRecoveryMiddleware sits inside the audit middleware, so even a panicking handler is still recorded as a failed entry.
  • Actor attributionWithActor(ctx, "user-42") stamps every audit entry with who initiated the command.
  • Selective skippingcfg.SkipCommands = []string{"HealthCheck"} keeps noisy commands out of the trail.
  • Querying the trailAuditQuery{} (zero value) returns all entries, most recent first.

Running

go run ./examples/audit

No infrastructure required — the audit store is in-memory (memory.NewAuditStore). For production, swap in postgres.NewAuditStore(db, ...) and call its Initialize (the audit table is created by the store, not by the adapter's migrations).

What happens

  1. An in-memory AuditStore and a HandlerRegistry with three handlers are created: CreateAccount (returns success), Withdraw (always fails with "insufficient funds"), and HealthCheck (success).
  2. A CommandBus is built with AuditMiddleware wrapping RecoveryMiddleware; the audit config skips HealthCheck and enables IncludeMetadata.
  3. WithActor(ctx, "user-42") identifies the caller, then three commands are dispatched: CreateAccount (succeeds), Withdraw (fails — the expected error is printed), and HealthCheck (skipped from the audit trail).
  4. auditStore.Find(ctx, AuditQuery{}) returns the trail. Only two entries appear — HealthCheck was skipped — printed with command type, actor, success flag, OK/FAILED status, error message, and duration in milliseconds.

Key APIs

  • mink.AuditMiddleware(config) — middleware that writes an audit entry per command.
  • mink.DefaultAuditConfig(store) — sensible defaults; here extended with SkipCommands and IncludeMetadata.
  • memory.NewAuditStore() — in-memory audit store for tests/examples (production: postgres.NewAuditStore).
  • mink.WithActor(ctx, actor) — attach the acting principal to the context so it lands on each entry.
  • mink.RecoveryMiddleware() — converts handler panics into errors; nested inside audit so panics are still recorded.
  • mink.AuditQuery{} — filter/paginate the audit trail; the zero value returns everything.
  • mink.NewHandlerRegistry() / mink.RegisterGenericHandler(...) — register the command handlers dispatched through the bus.

Documentation

Overview

Package main demonstrates the command Audit Logging middleware.

This example shows:

  • Wiring AuditMiddleware into a CommandBus (with RecoveryMiddleware nested inside, so even a panicking handler is recorded as a failed audit entry)
  • Auditing successful AND failing commands
  • Skipping selected command types from the audit trail
  • Identifying the actor via WithActor on the context
  • Querying the audit trail with AuditQuery

It uses the in-memory audit store, so it runs with NO database:

go run ./examples/audit

For production, swap the in-memory store for the PostgreSQL store. The audit table is created by store.Initialize (it is NOT part of the adapter's migrations):

db, _ := sql.Open("postgres", connStr)            // import _ "github.com/lib/pq"
auditStore := postgres.NewAuditStore(db,
	postgres.WithAuditSchema("public"),
	postgres.WithAuditTable("mink_audit"),
)
_ = auditStore.Initialize(ctx)
// then: mink.AuditMiddleware(mink.DefaultAuditConfig(auditStore))

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL