go-auditGo Audit
Getting Started

Quickstart

Get go-audit running in under 5 minutes. This guide walks through installation, configuration and recording your first audit log entry.

This example wires Go Audit into a GORM + PostgreSQL app and shows audit logs appearing automatically after CRUD operations.

The Full Program

Go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/gopackx/go-audit"
    auditgorm "github.com/gopackx/go-audit/adapters/gorm"
    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

type User struct {
    ID    uint   `gorm:"primaryKey"`
    Name  string
    Email string
}

type ctxKey string

const userIDKey ctxKey = "user_id"

func main() {
    dsn := "host=localhost user=postgres password=postgres dbname=demo port=5432 sslmode=disable"
    gormDB, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
    if err != nil {
        log.Fatal(err)
    }
    sqlDB, err := gormDB.DB()
    if err != nil {
        log.Fatal(err)
    }

    // 1. Configure the auditor. Note: takes *sql.DB, not *gorm.DB.
    auditor, err := audit.New(sqlDB, audit.Config{
        Dialect: audit.PostgreSQL,
        UserFunc: func(ctx context.Context) (string, string) {
            if uid, ok := ctx.Value(userIDKey).(string); ok {
                return uid, "user"
            }
            return "system", "system"
        },
        DataAudit: audit.DataAuditConfig{
            Enabled:       true,
            ExcludeFields: []string{"password", "token"},
        },
    })
    if err != nil {
        log.Fatal(err)
    }

    // 2. Register the GORM plugin.
    if err := gormDB.Use(auditgorm.Plugin(auditor)); err != nil {
        log.Fatal(err)
    }

    // 3. Create audit tables (idempotent).
    ctx := context.Background()
    if err := auditor.AutoMigrate(ctx); err != nil {
        log.Fatal(err)
    }
    if err := gormDB.AutoMigrate(&User{}); err != nil {
        log.Fatal(err)
    }

    // 4. Attach a user to the context so UserFunc can resolve it.
    ctx = context.WithValue(ctx, userIDKey, "admin-1")
    tx := gormDB.WithContext(ctx)

    // 5. Perform CRUD — audit logs appear automatically.
    user := User{Name: "Ada Lovelace", Email: "ada@example.com"}
    tx.Create(&user)
    tx.Model(&user).Update("Email", "ada.l@example.com")
    tx.Delete(&user)

    // 6. Query the audit trail.
    logs, _ := auditor.Query(ctx, audit.DataFilter{EntityType: "users"})
    for _, l := range logs {
        fmt.Printf("%s %s by %s\n", l.Action, l.EntityID, l.UserID)
    }
}
Go snippet

Step-by-Step Walkthrough

  1. Extract the *sql.DB. Go Audit writes through database/sql, so call gormDB.DB() and pass the underlying *sql.DB to audit.New.
  2. Configure the auditor. Set the dialect explicitly, provide a UserFunc that reads user identity from the context, and turn on DataAudit.Enabled.
  3. Register the GORM plugin. gormDB.Use(auditgorm.Plugin(auditor)) installs all lifecycle callbacks on the GORM connection.
  4. Run auto-migration. auditor.AutoMigrate(ctx) creates the audit_logs (and optionally audit_api_logs) tables. Safe to call repeatedly — all DDL uses IF NOT EXISTS.
  5. Perform CRUD normally. Every Create, Save, Updates, and Delete is captured automatically. Use gormDB.WithContext(ctx) so the UserFunc receives the caller's context.

Expected Output

create 1 by admin-1
update 1 by admin-1
soft_delete 1 by admin-1

The third line appears as soft_delete instead of delete only if User has a gorm.DeletedAt field. Without soft delete, you'll see delete instead.

Next Steps

On this page