Audit store keeps a clear story of every change that happens in your product. Instead of guessing who updated a record or when something broke, you get a searchable timeline showing the actor, the item they touched, and what changed. Plug it into your existing SQL database, drop audit entries wherever you mutate data, and use the built-in queries to review activity or restore confidence when issues appear.
- Overview
- Features
- Installation
- Quick Start
- Key Concepts
- API Reference
- Querying Records
- Schema Details
- Debugging & Logging
- Testing
- Development Notes
- Dependencies
Auditstore helps your application answer the question "what changed and when?" by recording a trail of edits in any SQL database. You connect it to an existing *sql.DB, pick a table name such as audit_log, and the package takes care of creating the table (if you want) and storing audit entries. Each entry captures the object that changed, who made the change, and the before/after values, so you can later review activity history or troubleshoot issues.
- One-line setup: Call
NewStore(...)to bootstrap the audit table and get a ready-to-use store. - Human-readable audit entries:
NewRecord()gives you chainable setters for object type, object ID, author, and JSON snapshots of old/new values. - Flexible queries:
NewRecordQuery()lets you filter by user, object, or time range and supports pagination and sorting. - Driver-aware SQL: Under the hood, Auditstore generates SQL that works with popular drivers like SQLite, PostgreSQL, MySQL, and SQL Server.
- Optional verbose logging: Flip on
EnableDebugMode(true)to see the SQL statements being executed.
go get github.com/dracory/auditstoreEnsure your project uses Go 1.24.5 or newer (specified in go.mod).
package main
import (
"database/sql"
"log"
auditstore "github.com/dracory/auditstore"
_ "modernc.org/sqlite"
)
func main() {
db, err := sql.Open("sqlite", "file:audit.db?cache=shared&mode=rwc&parseTime=true")
if err != nil {
log.Fatal(err)
}
store, err := auditstore.NewStore(auditstore.NewStoreOptions{
DB: db,
AuditTableName: "audit_log",
AutomigrateEnabled: true,
DebugEnabled: false,
})
if err != nil {
log.Fatal(err)
}
record := auditstore.NewRecord().
SetObjectType("user").
SetObjectID("user_123").
SetAuthorID("admin_1").
SetValueOld(`{"name":"Old Name"}`).
SetValueNew(`{"name":"New Name"}`)
if err := store.AuditCreate(record); err != nil {
log.Fatal(err)
}
fetched, err := store.AuditGet(record.ID())
if err != nil {
log.Fatal(err)
}
log.Printf("Fetched audit %s created at %s", fetched.ID(), fetched.CreatedAt())
}- Store:
NewStore(NewStoreOptions)returns aStoreInterfacebacked bystoreImplementation. It requires an initialized*sql.DBand the target table name. - Record:
NewRecord()creates a mutable audit entry. IDs and timestamps default touid.MicroUid()and the current UTC time (viagithub.com/dromara/carbon/v2). - Query:
NewRecordQuery()produces a builder you can chain to filter, sort, and paginate audit results.
- EnableDebugMode(debug bool): Toggle structured logging;
DebugEnablealiases this for backward compatibility. - AuditCreate(record RecordInterface) error: Inserts a new audit row, auto-populating
idandcreated_atwhen missing. - AuditGet(id string) (RecordInterface, error): Retrieves a single record or
nilif not found. - AuditList(query RecordQueryInterface) ([]RecordInterface, error): Returns all records matching the query.
- AuditCount(query RecordQueryInterface) (int64, error): Counts rows for the given query.
- AuditDelete(id string) error: Removes the matching row.
- AutoMigrate() error: Creates the audit table using
sqlAuditTableCreate()when absent.
- DB: Required
*sql.DBconnection. Its driver name determines SQL dialect viadatabase.DatabaseType. - AuditTableName: Required table name (e.g.,
audit_log). - AutomigrateEnabled: Auto-run
AutoMigrate()during construction. - DebugEnabled: Enable structured debug logging immediately.
- SetObjectType(string) /
ObjectType() - SetObjectID(string) /
ObjectID() - SetValueOld(string) /
ValueOld() - SetValueNew(string) /
ValueNew() - SetAuthorID(string) /
AuthorID() - SetCreatedAt(string) /
CreatedAt() - CreatedAtCarbon(): Returns
*carbon.Carbonfor time arithmetic.
RecordQueryInterface (record_query_interface.go) exposes fluent setters. The concrete implementation in record_query.go validates inputs and converts them into a goqu.SelectDataset using ToSelectDataset(driver, table).
query := auditstore.NewRecordQuery().
SetObjectType("user").
SetAuthorID("admin_1").
SetCreatedAfter(time.Now().Add(-24 * time.Hour)).
SetOrderBy(auditstore.COLUMN_CREATED_AT, false).
SetLimit(50).
SetOffset(0)
records, err := store.AuditList(query)
if err != nil {
// handle error
}
count, err := store.AuditCount(query)Validation occurs via RecordQuery.Validate(), ensuring limits are non-negative and date ranges are consistent before SQL is generated.
Column names are defined in constants.go:
COLUMN_ID(id)COLUMN_OBJECT_TYPE(object_type)COLUMN_OBJECT_ID(object_id)COLUMN_VALUE_OLD(value_old)COLUMN_VALUE_NEW(value_new)COLUMN_AUTHOR_ID(author_id)COLUMN_CREATED_AT(created_at)
sqls.go uses github.com/dracory/sb to declare the table with appropriate column lengths and types. Indexes can be added by extending the builder section that currently contains commented placeholders.
- Enable debug mode:
store.EnableDebugMode(true)switches the logger to debug level usingslog.NewTextHandlerwithLevelDebug. - SQL output: When debug is on, SQL statements and parameters are printed before execution across CRUD methods.
store_test.go contains integration-style tests using modernc.org/sqlite in-memory databases:
TestStoreAuditCreate: Ensures IDs are assigned and records persist.TestStoreAuditGet,TestStoreAuditList,TestStoreAuditCount,TestStoreAuditDeletecover the primary Store operations. Run the suite with:
go test ./...- Ensure the target database driver is registered with
database/sql(e.g., import_ "modernc.org/sqlite"). AuditCreateusesdatabase.Executefromgithub.com/dracory/database, which expects context-aware execution; the package wrapscontext.Background()for convenience.- Timestamps default to UTC via
carbon.Now(carbon.UTC)insideAuditCreate, guaranteeing consistent storage across drivers.
Auditstore relies on:
github.com/doug-martin/goqu/v9for SQL construction.github.com/dracory/databasefor database helpers (SelectToMapString,Execute).github.com/dracory/dataobjectfor the record data container.github.com/dracory/uidfor unique ID generation.github.com/dracory/sbfor schema building.github.com/dromara/carbon/v2for time handling.modernc.org/sqlitein tests as an embedded driver; replace or supplement with your chosen driver in production.