Stores: logstore

Persist structured logs with github.com/dracory/logstore.

github.com/dracory/logstore

logstore captures structured log events in SQL. It provides a simple API for writing log messages, attaching context, and even wiring into Go's slog handler so logs are persisted automatically.


Highlights

  • Schema via migrations – schema creation handled by migration files, not automigration.
  • Log levels – trace, debug, info, warn, error, fatal, panic helpers.
  • Context support – InfoWithContext (and others) accept key/value maps.
  • slog integration – NewSlogHandler lets you plug logstore into Go's standard structured logger.
  • Query helpers – list logs by level, time range, message search, or context filters via query options.
  • Soft deletion – keep historical logs while hiding them from default queries.

Creating a Store

func NewLogStore(db *sql.DB, debug bool) (logstore.StoreInterface, error) {
    st, err := logstore.NewStore(logstore.NewStoreOptions{
        DB:           db,
        LogTableName: "snv_logs_log",
    })
    if err != nil {
        return nil, err
    }
    st.EnableDebug(debug)
    return st, nil
}
  • Schema creation is handled by migration files in database/migrations/ (invoked via migrations.MigrateAll(app)), not by automigration. The log table includes columns for level, message, context, and timestamps.
  • Debug is controlled via st.EnableDebug(debug) to trace SQL statements.

Writing Logs

store.Info("service started")

store.WarnWithContext("cache miss", map[string]string{
    "key": "user:123",
})

store.Error("failed to process request")
  • Log levels map to methods (Trace, Debug, Info, Warn, Error, Fatal, Panic).
  • Context maps are stored as JSON.

slog handler

logger := slog.New(logstore.NewSlogHandler(store))
logger.Info("request", "path", "/health", "status", 200)

Querying Logs

query := logstore.NewLogQuery().
    SetLevel(logstore.LevelError).
    SetCreatedAtGte("2025-01-01 00:00:00").
    SetCreatedAtLte("2025-01-31 23:59:59")

entries, err := store.LogList(ctx, query)
count, err := store.LogCount(ctx, query)
  • Filter by level, text search, context values, or soft-deleted inclusion.
  • Use pagination (SetLimit, SetOffset) and ordering options.

  • Design Principles – revisit Dracory's store architecture.
  • Entities & Interfaces – learn how logstore implements dataobject patterns.
  • Testing – repository uses SQLite-based tests to validate logging flows.
  • Create Your Own Store – adapt logstore for environment-specific logging needs.