57 lines
1.1 KiB
Go
57 lines
1.1 KiB
Go
package audit
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"log"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type Event struct {
|
|
ID string
|
|
Timestamp time.Time
|
|
UserID string
|
|
Action string
|
|
ResourceType string
|
|
ResourceID string
|
|
Success bool
|
|
Details map[string]any
|
|
}
|
|
|
|
type AuditLogger interface {
|
|
Record(ctx context.Context, e Event) error
|
|
}
|
|
|
|
type SQLAuditLogger struct {
|
|
DB *sql.DB
|
|
}
|
|
|
|
func NewSQLAuditLogger(db *sql.DB) *SQLAuditLogger {
|
|
return &SQLAuditLogger{DB: db}
|
|
}
|
|
|
|
func (l *SQLAuditLogger) Record(ctx context.Context, e Event) error {
|
|
if e.ID == "" {
|
|
e.ID = uuid.New().String()
|
|
}
|
|
if e.Timestamp.IsZero() {
|
|
e.Timestamp = time.Now()
|
|
}
|
|
detailsJSON, _ := json.Marshal(e.Details)
|
|
_, err := l.DB.ExecContext(ctx, `INSERT INTO audit_events (id, ts, user_id, action, resource_type, resource_id, success, details) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, e.ID, e.Timestamp, e.UserID, e.Action, e.ResourceType, e.ResourceID, boolToInt(e.Success), string(detailsJSON))
|
|
if err != nil {
|
|
log.Printf("audit record failed: %v", err)
|
|
}
|
|
return err
|
|
}
|
|
|
|
func boolToInt(b bool) int {
|
|
if b {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|