audit

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 17, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package audit writes a structured, post-redaction record for every call through an asynchronous single-writer pipeline, so audit I/O never sits on the request hot path (design §5, §8, ADR-0010).

The hot path hands a record to a bounded buffer with a non-blocking handoff. A dedicated writer goroutine marshals each record to a line of JSON, batches them through a bufio.Writer, and group-commit fsyncs to the sink. Overflow is tiered: high-volume success records are shed once the buffer passes a high-water mark, while security records (denials, redactions) take a hard path that blocks briefly and, if the sink is wedged, fail the request closed so an un-auditable security decision never proceeds.

Record must not be called after Close; the composition root closes the writer only once request handlers have drained (graceful shutdown), so no producer races a Close.

Index

Constants

This section is empty.

Variables

View Source
var ErrClosed = errors.New("audit writer closed")

ErrClosed is returned by Record after the writer has been closed.

View Source
var ErrUnrecordable = errors.New("audit record unrecordable; sink wedged")

ErrUnrecordable is returned by Record when a security record cannot be buffered before the security block timeout; the caller must fail the request closed (design §5).

Functions

This section is empty.

Types

type Config

type Config struct {
	Buffer               int
	HighWaterMark        float64
	FlushMaxRecords      int
	FlushMaxInterval     time.Duration
	FsyncInterval        time.Duration
	Overflow             OverflowPolicy
	SecurityBlockTimeout time.Duration
}

Config tunes the audit pipeline. Zero fields fall back to package defaults.

type OverflowPolicy

type OverflowPolicy string

OverflowPolicy controls what happens to a success record when the buffer is past its high-water mark.

const (
	// OverflowShed drops success records past the high-water mark (default),
	// keeping the handoff non-blocking on the hot path.
	OverflowShed OverflowPolicy = "shed"
	// OverflowBlock makes success records wait for buffer room instead of being
	// shed. It deliberately trades the non-blocking hot-path guarantee for
	// zero success-record loss, so a wedged sink can back-pressure callers; use
	// it only when that trade is acceptable (security records are unaffected —
	// they always take the fail-closed hard path).
	OverflowBlock OverflowPolicy = "block"
)

type Stats

type Stats struct {
	Written      int64
	Shed         int64
	Unrecordable int64
	SinkErrors   int64
}

Stats is a snapshot of the writer's counters, for export to metrics.

type SyncWriter

type SyncWriter interface {
	io.Writer
	Sync() error
}

SyncWriter is the audit sink: a writer that can flush durably to its backing store. *os.File satisfies it; use NopSync to wrap stdout.

func NopSync

func NopSync(w io.Writer) SyncWriter

NopSync adapts a plain writer (e.g. os.Stdout, where fsync is not meaningful) to a SyncWriter with a no-op Sync.

type Writer

type Writer struct {
	// contains filtered or unexported fields
}

Writer is the asynchronous audit pipeline. It is safe for concurrent Record calls; a single goroutine owns all I/O.

func New

func New(sink SyncWriter, cfg Config) *Writer

New starts an audit writer feeding the given sink.

func (*Writer) Close

func (w *Writer) Close() error

Close drains buffered records, flushes and fsyncs, and stops the writer. It is idempotent. It must be called only after request handlers have stopped submitting records (graceful shutdown drains in-flight calls first).

func (*Writer) Get

func (w *Writer) Get() *domain.AuditRecord

Get returns a cleared record from the pool for the caller to fill. After passing it to Record the caller must not touch it again.

func (*Writer) Record

func (w *Writer) Record(rec *domain.AuditRecord) error

Record hands a filled record to the pipeline. The caller must not use rec afterward. It returns nil once handed off (or shed), ErrClosed after Close, and ErrUnrecordable when a security record cannot be buffered in time.

func (*Writer) Stats

func (w *Writer) Stats() Stats

Stats returns a snapshot of the writer's counters.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL