go-auditGo Audit
API Reference

Query & Filters

Cross-table queries, retention, snapshot, and restore.

Auditor.QueryByTransaction(ctx, txID) → (*TransactionLog, error)

Fetches all data audit rows and API call rows sharing a transaction_id.

trail, err := auditor.QueryByTransaction(ctx, txID)
// trail.DataLogs  []AuditLog
// trail.APILogs   []AuditAPILog

API logs are only included if APIAudit.Enabled == true.

audit.TransactionLog

type TransactionLog struct {
    TransactionID string
    DataLogs      []AuditLog
    APILogs       []AuditAPILog
}

Use this in UIs that show a transaction timeline or in support tooling that reconstructs what happened during a single user action.

Pagination

Every filter type exposes Limit and Offset:

page1, _ := auditor.Query(ctx, audit.DataFilter{Limit: 25, Offset: 0})
page2, _ := auditor.Query(ctx, audit.DataFilter{Limit: 25, Offset: 25})

For very large tables, prefer keyset pagination against created_at (set the next page's DateTo to the previous page's last row's CreatedAt) over deep offset pagination.

Sorting

All queries return results ordered by created_at DESC by default.

Transaction ID Helpers

func audit.NewTransactionID() string
func audit.WithTransactionID(ctx context.Context, txID string) context.Context
func audit.TransactionIDFromContext(ctx context.Context) string

NewTransactionID returns a YYYYMMDDTHHmmss-<32-char hex> string (lexicographically sortable by time). TransactionIDFromContext returns the empty string when no ID is set.

Auditor.Purge(ctx, before) → (PurgeResult, error)

Deletes rows older than before from audit_logs and audit_api_logs (only the tables that are enabled).

cutoff := time.Now().AddDate(-1, 0, 0) // 1 year ago
result, err := auditor.Purge(ctx, cutoff)
// result.DataLogs: int64 rows deleted
// result.APILogs:  int64 rows deleted

Returns a PurgeResult:

type PurgeResult struct {
    DataLogs int64
    APILogs  int64
}

Run Purge from a daily cron to enforce retention policies.

Auditor.Snapshot(ctx, entityType, entityID, at) → (map[string]any, error)

Reconstructs the state of an entity at a given point in time by replaying its audit history up to at.

state, err := auditor.Snapshot(ctx,
    "orders", "42",
    time.Date(2026, 3, 1, 12, 0, 0, 0, time.UTC),
)
// state is the map of column → value at that moment

Returns nil (without error) if the entity did not exist or had been deleted at that time. Requires non-empty entityType, entityID, and a non-zero at time.

Useful for "what did this record look like when X happened?" questions during incident response.

Auditor.Restore(ctx, entityType, entityID, at) → (*RestoreResult, error)

Reconstructs the target state via Snapshot, then writes a restore audit entry (old values = current state, new values = target state), and returns the target values for the caller to apply via their ORM.

result, err := auditor.Restore(ctx, "orders", "42", oldTime)
if err != nil { return err }

// Apply the returned values via GORM
gormDB.Model(&Order{ID: 42}).Updates(result.Values)
type RestoreResult struct {
    EntityType string         `json:"entity_type"`
    EntityID   string         `json:"entity_id"`
    Values     map[string]any `json:"values,omitempty"`
    WasDeleted bool           `json:"was_deleted"`
}

The ORM adapter will not record the application-level write as a separate update — the restore audit entry already captures it. Your caller is responsible for actually persisting the restored values.

On this page