Documentation
¶
Overview ¶
Package observe is the one you almost always want: structured logging (slog with context-aware fields), request/trace IDs and the small set of helpers the rest of the framework logs through.
Not to be confused with the sibling package observability, which is the IN-PROCESS EVENT BUS (HTTP/SQL/session events) that admin panels such as orbit subscribe to. If you are wiring logs, metrics labels or trace IDs, use observe; reach for observability only when you need to consume the event stream itself.
Index ¶
- Constants
- func CtxWithModelObserved(ctx context.Context) context.Context
- func CtxWithRequestID(ctx context.Context, id string) context.Context
- func CtxWithTenantID(ctx context.Context, id string) context.Context
- func CtxWithTraceID(ctx context.Context, id string) context.Context
- func CtxWithUserID(ctx context.Context, id string) context.Context
- func DefaultRedactedKeys() []string
- func IsModelObserved(ctx context.Context) bool
- func NewLogger(level, format string) *slog.Logger
- func NewLoggerWithRedaction(level, format string, cfg RedactionConfig) *slog.Logger
- func RequestIDFromCtx(ctx context.Context) string
- func SetupOpenTelemetry(ctx context.Context, cfg TelemetryConfig, logger *slog.Logger) (shutdown func(context.Context) error, metricsHandler http.Handler, err error)
- func TenantIDFromCtx(ctx context.Context) string
- func TraceIDFromCtx(ctx context.Context) string
- func UserIDFromCtx(ctx context.Context) string
- func WithContext(ctx context.Context, logger *slog.Logger) *slog.Logger
- type RedactionConfig
- type TelemetryConfig
Constants ¶
const RedactionPlaceholder = "[REDACTED]"
RedactionPlaceholder is the value substituted for a redacted log attribute. It is deliberately bracketed and uppercase so a redacted field is unmistakable in log output and easy to grep for.
Variables ¶
This section is empty.
Functions ¶
func CtxWithModelObserved ¶
CtxWithModelObserved returns a context marked as already observed by the model/CRUD SQL layer, so driver-level instrumentation skips re-emitting the same statement. CRUD stamps this on the context it hands to database/sql.
func CtxWithRequestID ¶
CtxWithRequestID stores a request ID in the context.
func CtxWithTenantID ¶
CtxWithTenantID stores a tenant ID in the context. Used by request-scope resolution in pkg/app and read by downstream middleware (logging, rate-limit per-tenant keying) that cannot import pkg/app without a cycle.
func CtxWithTraceID ¶
CtxWithTraceID stores a trace ID in the context.
func CtxWithUserID ¶
CtxWithUserID stores a user ID in the context.
func DefaultRedactedKeys ¶
func DefaultRedactedKeys() []string
DefaultRedactedKeys returns a sorted copy of the built-in set of log attribute keys whose values NewLogger redacts. It is exposed so operators can audit exactly what is redacted by default and decide what app-specific keys to add via RedactionConfig.ExtraKeys.
func IsModelObserved ¶
IsModelObserved reports whether the context was marked by CtxWithModelObserved — i.e. the statement is CRUD-originated and already observed at the model layer. Driver-level instrumentation checks this to avoid double-recording.
func NewLogger ¶
NewLogger creates a *slog.Logger configured with the given level and format. Supported levels: "debug", "info", "warn" (alias "warning"), "error" (default: "info"). Supported formats: "json", "text" (default: "json").
Secret redaction is ON by default: attribute values whose key is in DefaultRedactedKeys (authorization, cookie, password, token, …) are replaced with RedactionPlaceholder before they reach the output. To extend the key set, change the placeholder, or disable redaction entirely, use NewLoggerWithRedaction. See ADR-007.
Redaction is key-based and applies only to structured key-value attributes. It does NOT scan the message string — a secret interpolated into the msg (e.g. fmt.Sprintf("token=%s", t)) is logged verbatim. It also does not recurse into a struct logged via slog.Any under a non-secret key; only slog.Group attrs are expanded and matched. Always pass secrets as their own named attrs, and do not log secret material in the first place — redaction is defence-in-depth, not a license.
func NewLoggerWithRedaction ¶
func NewLoggerWithRedaction(level, format string, cfg RedactionConfig) *slog.Logger
NewLoggerWithRedaction is NewLogger with explicit control over secret redaction. The zero-value RedactionConfig is identical to NewLogger: redaction on, built-in key set, standard placeholder.
func RequestIDFromCtx ¶
RequestIDFromCtx extracts the request ID from the context, or returns "".
func SetupOpenTelemetry ¶
func SetupOpenTelemetry(ctx context.Context, cfg TelemetryConfig, logger *slog.Logger) (shutdown func(context.Context) error, metricsHandler http.Handler, err error)
SetupOpenTelemetry initializes the global OpenTelemetry providers and, when PrometheusEnabled is set, returns an http.Handler that serves OpenMetrics-compatible Prometheus output for /metrics scraping.
Trace + metric exporters target OTLPEndpoint when configured; otherwise that side is a no-op. The Prometheus reader is independent — it is attached to the MeterProvider regardless of OTLP, so a deployment can scrape locally without an OTLP collector.
Return values:
- shutdown is always non-nil. It must be called on app teardown to flush remaining telemetry; the no-op case (no exporters configured) returns immediately.
- metricsHandler is non-nil only when PrometheusEnabled is true. Callers should mount it at the configured /metrics path.
func TenantIDFromCtx ¶
TenantIDFromCtx extracts the tenant ID from the context, or returns "".
func TraceIDFromCtx ¶
TraceIDFromCtx extracts the trace ID from the context, or returns "".
func UserIDFromCtx ¶
UserIDFromCtx extracts the user ID from the context, or returns "".
Types ¶
type RedactionConfig ¶
type RedactionConfig struct {
// Disabled turns redaction off entirely. Redaction is ON by default
// (the security-by-default principle, SPEC.md §2). There is no
// config-file switch to disable it — turning it off requires this
// explicit code-level opt-out so the decision surfaces in code
// review, the same discipline ADR-004 applies to WithOpenAuthz().
Disabled bool
// ExtraKeys are additional attribute keys to redact beyond
// DefaultRedactedKeys. Case-insensitive. Use this for app-specific
// sensitive fields (e.g. "ssn", "card_number"). slog's own built-in
// keys (time, level, msg, source) are always ignored here — listing
// one has no effect, so a stray entry cannot silence timestamps.
ExtraKeys []string
// Placeholder overrides the redacted-value string. Empty uses
// RedactionPlaceholder.
Placeholder string
}
RedactionConfig customises secret redaction for NewLoggerWithRedaction. The zero value is the secure default: redaction enabled, built-in key set, standard placeholder.
type TelemetryConfig ¶
type TelemetryConfig struct {
ServiceName string
OTLPEndpoint string
PrometheusEnabled bool
// PrometheusRequested distinguishes an operator who asked for metrics
// from the default that turns them on for everybody.
//
// It exists because the exporter now ships as its own module, and the
// two cases deserve opposite answers. An operator who wrote
// metrics_path into their configuration and did not link the exporter
// has a broken deployment, and startup says so. An application that
// never mentioned metrics and is simply carrying the default must not
// be stopped from booting by a module it never asked for — it logs an
// INFO line naming the import, and runs.
PrometheusRequested bool
}
TelemetryConfig configures OpenTelemetry initialization.