observability

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Oct 10, 2026 License: Apache-2.0 Imports: 26 Imported by: 0

Documentation

Overview

Package observability builds the funcd platform's root logger (ADR-0009).

It constructs a root *slog.Logger from configuration, hands out named child loggers, allows runtime log-level switching, and lifts trace_id/span_id from the OpenTelemetry span context into every record (the trace API only — the SDK pipeline, OTLP export, and audit channel belong to the follow-up P-F2). There is no package-level logger: the root is constructed here and injected from the composition root, so tests can assert on output with an in-memory writer.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ReplaceAttr added in v0.8.0

func ReplaceAttr(groups []string, a slog.Attr) slog.Attr

ReplaceAttr is the slog hook every funcd handler sets: it writes a record's own top-level time in the v1alpha1.Timestamp form (ADR-0196); a time-valued attribute, or a time inside a group, is left as it is. A duration at any group depth becomes a <key>_ms number of milliseconds (ADR-0197).

Types

type AuditDecision

type AuditDecision string

AuditDecision is the outcome recorded for a security-relevant action.

const (
	// AuditAllow records that the action was permitted.
	AuditAllow AuditDecision = "allow"
	// AuditDeny records that the action was denied.
	AuditDeny AuditDecision = "deny"
)

func (AuditDecision) Validate

func (d AuditDecision) Validate() error

Validate reports whether d is a known decision; unknown maps to fault.Invalid.

type AuditEvent

type AuditEvent struct {
	Actor    string        // authenticated principal / API key id
	Action   string        // e.g. "function.apply", "egress.connect"
	Resource string        // namespaced resource ref
	Decision AuditDecision // allow | deny
	Reason   string        // optional human reason (e.g. PDP rule)
}

AuditEvent is one security-relevant event — who did what to which resource and the decision. Typed (no any); it travels the dedicated audit stream, never the operational log stream.

type AuditRecorder

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

AuditRecorder writes audit events to a dedicated sink labeled source=audit, kept separate from operational logs (blueprint: audit is not ops logging). The V1 sink is a structured JSON writer; durable retention is a V2 audit ADR.

func NewAuditRecorder

func NewAuditRecorder(w io.Writer) *AuditRecorder

NewAuditRecorder builds an AuditRecorder writing to w (the composition root passes the audit stream; tests pass a buffer).

func (*AuditRecorder) Record

func (r *AuditRecorder) Record(ctx context.Context, e AuditEvent) error

Record writes one audit event. It returns fault.Invalid if Decision is unknown.

type Config

type Config struct {
	// Level is the initial log level; it is switchable at runtime via SetLevel.
	Level slog.Level
	// Format selects text or json rendering; the empty value defaults to json.
	Format Format
}

Config configures the root logger. It is value config (ADR-0002 §1): the composition root supplies a populated Config. Level is a slog.Level, which implements encoding.TextUnmarshaler, so "info"/"debug"/"warn+2"/… bind directly from TOML or the environment without a custom parser here.

type Fanout

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

Fanout is a slog.Handler that dispatches every record to all inner handlers — the seam the composition root (P-I) uses to send a record to stdout and OTLP. Concrete return type (ADR-0002 §1: constructors return concrete structs).

func NewFanout

func NewFanout(handlers ...slog.Handler) *Fanout

NewFanout returns a Fanout over the given handlers.

func (*Fanout) Enabled

func (f *Fanout) Enabled(ctx context.Context, level slog.Level) bool

Enabled reports whether any inner handler is enabled at the level.

func (*Fanout) Handle

func (f *Fanout) Handle(ctx context.Context, record slog.Record) error

Handle dispatches a clone of the record to every inner handler that is enabled.

func (*Fanout) WithAttrs

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

WithAttrs returns a Fanout whose inner handlers all carry the attrs.

func (*Fanout) WithGroup

func (f *Fanout) WithGroup(name string) slog.Handler

WithGroup returns a Fanout whose inner handlers all open the group.

type Format

type Format string

Format selects the slog handler rendering. The empty value is valid and defaults to FormatJSON in NewLogger (blueprint: stdout JSON by default).

const (
	// FormatText renders human-readable lines — the dev default.
	FormatText Format = "text"
	// FormatJSON renders structured JSON — the production default.
	FormatJSON Format = "json"
)

func (Format) Validate

func (f Format) Validate() error

Validate reports whether f is a known format. The empty value is accepted (NewLogger applies the JSON default); any other unknown value maps to fault.Invalid so it surfaces as HTTP 400 at an edge.

type Logger

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

Logger is the platform's root logging facade: a root *slog.Logger whose level is switchable at runtime, plus named child loggers. It holds no package-level state — two NewLogger calls are fully independent.

func NewLogger

func NewLogger(cfg Config, w io.Writer) (*Logger, error)

NewLogger builds the root Logger from cfg, writing to w (the composition root passes os.Stdout; tests pass a buffer). It returns a fault.Invalid error if cfg.Format is an unknown value. The name matches the blueprint "Platform logging" spec; the package will also expose the OTel provider and audit constructors in P-F2, so it is NewLogger, not a bare New. slog.LevelVar and the stdlib handlers are goroutine-safe, so SetLevel is race-free during live logging.

func (*Logger) Component

func (l *Logger) Component(name string) *slog.Logger

Component returns a child logger tagged with component=name. Children are independent and do not mutate the root or each other.

func (*Logger) Level

func (l *Logger) Level() slog.Level

Level reports the current log level.

func (*Logger) Root

func (l *Logger) Root() *slog.Logger

Root returns the root logger. Prefer Component for per-component children.

func (*Logger) SetLevel

func (l *Logger) SetLevel(level slog.Level)

SetLevel switches the level for the root and every already-constructed child (they share one LevelVar), with no logger rebuild. It is the seam the admin log-level endpoint (P-L) drives.

type NormalizeHandler added in v0.8.0

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

NormalizeHandler wraps an embedder's handler (funcd.WithNormalizedLogFields, ADR-0197): Handle builds a new record with the time in UTC truncated to the millisecond and each attribute resolved and passed through durationField (a group is rebuilt from its members); WithAttrs does the same to its attributes. Enabled and WithGroup forward unchanged.

func NewNormalizeHandler added in v0.8.0

func NewNormalizeHandler(inner slog.Handler) *NormalizeHandler

NewNormalizeHandler wraps inner.

func (*NormalizeHandler) Enabled added in v0.8.0

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

Enabled reports whether inner handles level.

func (*NormalizeHandler) Handle added in v0.8.0

func (h *NormalizeHandler) Handle(ctx context.Context, r slog.Record) error

Handle passes inner a copy of r with its time and attributes normalized.

func (*NormalizeHandler) WithAttrs added in v0.8.0

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

WithAttrs wraps inner with attrs normalized.

func (*NormalizeHandler) WithGroup added in v0.8.0

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

WithGroup wraps inner's group handler.

type Telemetry

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

Telemetry holds the platform's OTel providers and the OTLP log handler. It is injected (no globals); Shutdown flushes and closes every provider.

func NewFromProviders

func NewFromProviders(mp metric.MeterProvider, tp trace.TracerProvider) *Telemetry

NewFromProviders builds a Telemetry from explicit OTel providers (a nil provider falls back to the no-op). It is the seam for injecting SDK providers directly — e.g. an in-memory reader/recorder in tests, or a custom-wired pipeline — without going through the OTLP-exporter constructor.

func NewTelemetry

func NewTelemetry(ctx context.Context, cfg TelemetryConfig) (*Telemetry, error)

NewTelemetry builds the pipeline from cfg. With cfg.Endpoint set it constructs OTLP gRPC exporters and SDK providers; otherwise it returns no-op providers and a no-op log handler. Construction never dials the network (export is lazy).

func (*Telemetry) LogHandler

func (t *Telemetry) LogHandler() slog.Handler

LogHandler returns the otelslog bridge handler (records ship over OTLP), or a no-op handler whose Enabled is false when telemetry is disabled.

func (*Telemetry) LoggerProvider

func (t *Telemetry) LoggerProvider() otellog.LoggerProvider

LoggerProvider returns the OTel logger provider (SDK-backed or no-op).

func (*Telemetry) MeterProvider

func (t *Telemetry) MeterProvider() metric.MeterProvider

MeterProvider returns the meter provider (SDK-backed or no-op).

func (*Telemetry) Shutdown

func (t *Telemetry) Shutdown(ctx context.Context) error

Shutdown flushes and closes every provider. It is deadline-bounded (honors ctx) and idempotent — a second call is a no-op.

func (*Telemetry) TracerProvider

func (t *Telemetry) TracerProvider() trace.TracerProvider

TracerProvider returns the tracer provider (SDK-backed or no-op).

type TelemetryConfig

type TelemetryConfig struct {
	// Endpoint is the OTLP gRPC target, e.g. "localhost:4317"; "" disables export.
	Endpoint string
	// ServiceName sets the resource service.name; "" defaults to "funcd".
	ServiceName string
	// Insecure runs gRPC without TLS (dev/local collector).
	Insecure bool
}

TelemetryConfig configures the OTel pipeline. An empty Endpoint disables export (no-op providers) — dev/tests need no collector. ServiceName defaults to "funcd".

Jump to

Keyboard shortcuts

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