diagnostics

package
v0.1.71 Latest Latest
Warning

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

Go to latest
Published: Oct 1, 2026 License: AGPL-3.0 Imports: 18 Imported by: 0

Documentation

Overview

Package diagnostics provides bounded, redacted operational log storage.

Index

Constants

View Source
const (
	DefaultMaxBytes = 10 << 20
	DefaultMaxAge   = 14 * 24 * time.Hour
	DefaultLimit    = 100
	HardMaxLimit    = 1000
)
View Source
const ExportSchemaVersion = 1

ExportSchemaVersion identifies the stable JSON contract written by WriteExport.

Variables

View Source
var ErrShipperQueueFull = errors.New("diagnostics shipper queue is full")
View Source
var ErrStoreClosed = errors.New("diagnostics store is closed")

ErrStoreClosed is returned by FileStore.Append after Close.

Functions

func DescribeError added in v0.1.63

func DescribeError(err error) (code, summary string)

DescribeError returns a stable, non-sensitive category and operator-facing summary for an error. Callers should log these fields instead of the raw error when the record may be persisted in the diagnostics store.

func RedactText

func RedactText(value string) string

RedactText removes common credential-bearing forms before text is allowed into durable diagnostics. This is intentionally conservative: structured attributes are allowlisted separately by Handler, while messages receive masking and a hard size bound at the store boundary.

func WriteExport added in v0.1.63

func WriteExport(w io.Writer, archive Export) error

WriteExport writes the stable, human-readable JSON form of an Export.

Types

type AuditSink

type AuditSink interface {
	RecordDiagnosticsQuery(context.Context, QueryAudit) error
}

type BatchSink added in v0.1.63

type BatchSink interface {
	Ship(context.Context, []Event) error
}

BatchSink receives one bounded batch from a Shipper.

type BatchSinkFunc added in v0.1.63

type BatchSinkFunc func(context.Context, []Event) error

BatchSinkFunc adapts a function to BatchSink.

func (BatchSinkFunc) Ship added in v0.1.63

func (f BatchSinkFunc) Ship(ctx context.Context, events []Event) error

type ComponentSpec added in v0.1.63

type ComponentSpec struct {
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
}

ComponentSpec describes one producer whose diagnostics are included in an export. Components are declared by the implementation that owns them, so a consumer can explain where an event came from without knowing Boxy's internal package layout.

type Event

type Event struct {
	ID           string    `json:"id"`
	Timestamp    time.Time `json:"timestamp"`
	Level        string    `json:"level"`
	Component    string    `json:"component,omitempty"`
	Message      string    `json:"message,omitempty"`
	Operation    string    `json:"operation,omitempty"`
	Job          string    `json:"job,omitempty"`
	Step         string    `json:"step,omitempty"`
	Status       string    `json:"status,omitempty"`
	Attempt      int       `json:"attempt,omitempty"`
	ErrorCode    string    `json:"error_code,omitempty"`
	ErrorSummary string    `json:"error_summary,omitempty"`
	// DurationMS is the elapsed time of the operation/step this event
	// describes, in milliseconds. Zero means "not reported" — most events
	// have no associated duration. See #355.
	DurationMS int64  `json:"duration_ms,omitempty"`
	Pool       string `json:"pool,omitempty"`
	Agent      string `json:"agent,omitempty"`
	Resource   string `json:"resource,omitempty"`
	Provider   string `json:"provider,omitempty"`
	Request    string `json:"request,omitempty"`
}

Event is the safe, structured representation exposed by diagnostics. Fields not represented here must never cross the diagnostics boundary.

type Export added in v0.1.63

type Export struct {
	SchemaVersion int             `json:"schema_version"`
	GeneratedAt   time.Time       `json:"generated_at"`
	Sanitized     bool            `json:"sanitized"`
	Components    []ComponentSpec `json:"components"`
	Events        []Event         `json:"events"`
}

Export is the portable, sanitized diagnostics archive.

func BuildExport added in v0.1.63

func BuildExport(events []Event, options ExportOptions) (Export, error)

BuildExport makes a bounded export and sanitizes every event. Sanitization uses stable placeholders for repeated values within this export, preserving correlation without exposing machine or user identity.

type ExportOptions added in v0.1.63

type ExportOptions struct {
	GeneratedAt time.Time
	Components  []ComponentSpec
}

ExportOptions controls metadata for BuildExport. Event limits are enforced by the public package and cannot be disabled by a caller.

type FileAuditStore

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

func NewFileAuditStore

func NewFileAuditStore(path string) (*FileAuditStore, error)

func (*FileAuditStore) RecordDiagnosticsQuery

func (s *FileAuditStore) RecordDiagnosticsQuery(ctx context.Context, audit QueryAudit) error

func (*FileAuditStore) RecordResourceCleanup added in v0.1.59

func (s *FileAuditStore) RecordResourceCleanup(ctx context.Context, audit ResourceCleanupAudit) error

type FileStore

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

FileStore is a bounded JSONL store. File metadata invalidates cached snapshots when another store or process changes the durable history.

func NewFileStore

func NewFileStore(path string, maxBytes int64, maxAge time.Duration) (*FileStore, error)

func (*FileStore) Append

func (s *FileStore) Append(_ context.Context, event Event) error

func (*FileStore) Close added in v0.1.69

func (s *FileStore) Close() error

Close stops the store accepting new events. It waits for an Append already in progress, and every later Append returns ErrStoreClosed without touching the filesystem. Query keeps working.

Appends otherwise recreate the store's directory (MkdirAll), so a log record that arrives after the owner has finished -- from any goroutine still using a slog handler wrapping this store -- could write the file back while the owner is removing its data directory (#376).

func (*FileStore) Query

func (s *FileStore) Query(_ context.Context, query Query) (Page, error)

type Handler

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

Handler forwards records to the normal slog handler and independently stores a safe diagnostics projection. Storage failures are deliberately ignored so an observability disk problem cannot break the application.

func NewHandler

func NewHandler(base slog.Handler, store Store) *Handler

func (*Handler) Enabled

func (h *Handler) Enabled(ctx context.Context, level slog.Level) bool

func (*Handler) Handle

func (h *Handler) Handle(ctx context.Context, record slog.Record) error

func (*Handler) WithAttrs

func (h *Handler) WithAttrs(attrs []slog.Attr) slog.Handler

func (*Handler) WithGroup

func (h *Handler) WithGroup(name string) slog.Handler

type MemoryStore

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

MemoryStore provides the same bounded query semantics for tests and embedders that do not need restart persistence.

func NewMemoryStore

func NewMemoryStore() *MemoryStore

func (*MemoryStore) Append

func (s *MemoryStore) Append(_ context.Context, event Event) error

func (*MemoryStore) Query

func (s *MemoryStore) Query(_ context.Context, query Query) (Page, error)

type Page

type Page struct {
	Events     []Event `json:"events"`
	NextCursor string  `json:"next_cursor,omitempty"`
}

type Query

type Query struct {
	Since     time.Time
	Level     string
	Component string
	Pool      string
	Agent     string
	Resource  string
	Provider  string
	Job       string
	Status    string
	Limit     int
	Cursor    string
}

Query selects a bounded page of diagnostic events. Cursor values are opaque to callers and are produced by Page.NextCursor.

type QueryAudit

type QueryAudit struct {
	Actor       string
	Since       string
	Level       string
	Component   string
	Job         string
	Status      string
	Pool        string
	Agent       string
	Resource    string
	Provider    string
	Limit       int
	ResultCount int
}

QueryAudit is deliberately limited to safe query metadata.

type ResourceCleanupAudit added in v0.1.59

type ResourceCleanupAudit struct {
	Actor          string `json:"actor"`
	Mode           string `json:"mode"`
	Force          bool   `json:"force"`
	State          string `json:"state"`
	Unreferenced   bool   `json:"unreferenced"`
	OlderThan      string `json:"older_than,omitempty"`
	CandidateCount int    `json:"candidate_count"`
	CleanedCount   int    `json:"cleaned_count"`
	SkippedCount   int    `json:"skipped_count"`
	ErrorCount     int    `json:"error_count"`
}

ResourceCleanupAudit describes safe metadata for an administrator cleanup mutation. It intentionally contains counts and IDs only; callers must not attach resource properties or provider credentials.

type ResourceCleanupAuditSink added in v0.1.59

type ResourceCleanupAuditSink interface {
	RecordResourceCleanup(context.Context, ResourceCleanupAudit) error
}

ResourceCleanupAuditSink is optional so existing embedders with an audit sink that predates cleanup remain source-compatible.

type Sanitizer added in v0.1.63

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

Sanitizer is the public sanitization contract used by both exports and log shippers. It is intentionally stateful so repeated values receive the same placeholder during one incident report.

func NewSanitizer added in v0.1.63

func NewSanitizer() *Sanitizer

NewSanitizer returns a sanitizer with an empty per-report identity map.

func (*Sanitizer) Event added in v0.1.63

func (s *Sanitizer) Event(event Event) Event

Event returns a sanitized copy of event.

func (*Sanitizer) Text added in v0.1.63

func (s *Sanitizer) Text(value string) string

Text removes credentials and anonymizes host, network, and user identity embedded in diagnostic text.

type Shipper added in v0.1.63

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

Shipper is a bounded, retryable batch buffer. Submit never sends network traffic; callers choose when and where Flush sends the batch.

func NewShipper added in v0.1.63

func NewShipper(options ShipperOptions) *Shipper

NewShipper creates a bounded log shipper.

func (*Shipper) Flush added in v0.1.63

func (s *Shipper) Flush(ctx context.Context, sink BatchSink) error

Flush sends at most MaxBatch events. A failed send leaves the batch queued at the front for a later retry.

func (*Shipper) Handler added in v0.1.63

func (s *Shipper) Handler(next slog.Handler) slog.Handler

Handler returns a slog handler that forwards safe events to next and queues a sanitized copy for the shipper. The next handler may be slog.Discard's equivalent when an agent has no local log destination.

func (*Shipper) Pending added in v0.1.63

func (s *Shipper) Pending() int

Pending returns the number of events waiting to be shipped.

func (*Shipper) Submit added in v0.1.63

func (s *Shipper) Submit(ctx context.Context, event Event) error

Submit sanitizes and queues one event. Queue-full is explicit so callers can count drops; the slog adapter intentionally treats it as best effort.

type ShipperOptions added in v0.1.63

type ShipperOptions struct {
	MaxBatch int
	MaxQueue int
}

ShipperOptions bounds memory and transport work for a log source.

type Store

type Store interface {
	Append(context.Context, Event) error
	Query(context.Context, Query) (Page, error)
}

Jump to

Keyboard shortcuts

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