Documentation
¶
Overview ¶
Package observability owns bounded operation observations and pluggable error reporting shared by framework kernels. It starts no independent HTTP server.
Index ¶
- Constants
- func DurationBuckets() []time.Duration
- func Observe(ctx context.Context, operation Operation, run func(context.Context) error) (err error)
- func WithContext(ctx context.Context, recorder *Recorder) context.Context
- type Collector
- type Config
- type Entry
- type ErrorReport
- type Kind
- type Label
- type LogReporterConfig
- type Metric
- type MetricSample
- type MetricWriter
- type Name
- type OTLPConfig
- type OTLPHeader
- type Operation
- type Outcome
- type QuantileEstimate
- type Recorder
- func (r *Recorder) Claim() error
- func (r *Recorder) Close(ctx context.Context) error
- func (r *Recorder) CollectSamples() []MetricSample
- func (r *Recorder) Done() <-chan struct{}
- func (r *Recorder) Gate() *maintenance.Gate
- func (r *Recorder) Ready(ctx context.Context) error
- func (r *Recorder) RegisterCollector(name Name, collector Collector) error
- func (r *Recorder) Run(ctx context.Context) error
- func (r *Recorder) Snapshot() Snapshot
- func (r *Recorder) Start(ctx context.Context, operation Operation) (context.Context, *Span, error)
- func (r *Recorder) WritePrometheus(writer io.Writer) error
- type Reporter
- type Result
- type Snapshot
- type Span
- type TraceBatchExporter
- type TraceExporter
Constants ¶
const ( MaxCollectors = 32 MaxCollectorSamples = 1024 MaxMetricLabels = 16 MaxMetricNameBytes = 128 MaxMetricHelpBytes = 256 MaxMetricLabelBytes = 256 )
Collector bounds. A collector exceeding them has its remaining samples dropped and counted in foundry_collector_failures_total.
const DefaultTraceBatchSize = 64
DefaultTraceBatchSize bounds one TraceBatchExporter call when unset.
const PrometheusContentType = "text/plain; version=0.0.4; charset=utf-8"
Variables ¶
This section is empty.
Functions ¶
func DurationBuckets ¶
DurationBuckets returns a copy of duration histogram bounds.
func Observe ¶
Observe runs work synchronously with the recorder attached to ctx. A missing, closed or exhausted recorder does not prevent domain work; drop counters remain available on the recorder. Existing callback isolation still belongs to the caller. The deferred end also releases ownership on panic or Goexit. The returned error alone decides the outcome: work that returned nil stays Succeeded even if its context is cancelled or expires afterwards.
func WithContext ¶
WithContext carries only the explicit application recorder. Kernels that intentionally discard parent context values may capture this specific runtime capability before creating their fresh execution contexts. A nil recorder clears an inherited recorder without altering other context values.
Types ¶
type Collector ¶
type Collector func(*MetricWriter)
Collector contributes point-in-time samples to each Prometheus exposition. It runs synchronously during the scrape inside callback isolation: read in-memory statistics only, never perform I/O or wait. Retaining the writer after returning has no effect.
type Config ¶
type Config struct {
MaxSeries int
MaxRecent int
MaxActive int
ErrorQueue int
ReporterConcurrency int
ReporterTimeout time.Duration
// SampleTraces enables local trace sampling. TraceSampleRatio then selects
// the sampled fraction of traces, deterministically by trace ID; zero
// selects 1 (every trace). Disable sampling with SampleTraces=false.
SampleTraces bool
TraceSampleRatio float64
TraceExporters []TraceExporter
TraceBatchExporters []TraceBatchExporter
// TraceBatchSize bounds one batch exporter call; zero selects 64.
TraceBatchSize int
TraceQueue int
TraceConcurrency int
TraceTimeout time.Duration
Maintenance *maintenance.Gate
}
Config configures recorder budgets, sampling, exporters, and the maintenance gate.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns default metric, error reporting, and trace collection budgets.
type Entry ¶
type Entry struct {
Operation Operation `json:"operation"`
Result Result `json:"result"`
Started time.Time `json:"started"`
Duration time.Duration `json:"duration_ns"`
TraceID tracing.TraceID `json:"trace_id"`
SpanID tracing.SpanID `json:"span_id"`
ParentID tracing.SpanID `json:"parent_id"`
RequestID attribution.RequestID `json:"request_id,omitempty"`
Route attribution.Route `json:"route,omitzero"`
}
Entry is a bounded, payload-free operation record. Correlation IDs belong in recent observations and reports, never metric labels. Vendor tracestate is deliberately absent; raw request paths, IPs, identities and error chains are not retained by the recorder.
type ErrorReport ¶
type ErrorReport struct {
Entry Entry `json:"entry"`
Diagnostic fault.Diagnostic `json:"diagnostic,omitzero"`
}
ErrorReport describes one failed operation. Diagnostic is a redacted summary (type names, framework fault notes and attributes, contained-panic frames); it never contains error text, payloads or credentials.
type Label ¶
Label is one Prometheus label on a collector sample. Keep values bounded operational identities (connection names, roles), never user or request data.
type LogReporterConfig ¶
type LogReporterConfig struct {
Level slog.Level
Window time.Duration
MaxFingerprints int
DontReportFaults []fault.Code
DontReportStatuses []int
DontReportOutcomes []Outcome
// Clock measures suppression windows; nil uses the system clock.
Clock clock.Clock
}
LogReporterConfig controls the built-in structured-log error reporter. Window suppresses repeated reports sharing one fingerprint (operation, outcome, status and redacted diagnostic); zero logs every report. The first report after a window closes carries the suppressed count. DontReport* filters skip reports whose diagnostic contains one of the fault codes, whose HTTP status or whose outcome is listed.
func DefaultLogReporterConfig ¶
func DefaultLogReporterConfig() LogReporterConfig
DefaultLogReporterConfig returns default error severity and deduplication settings.
func (LogReporterConfig) Validate ¶
func (c LogReporterConfig) Validate() error
Validate checks error log severity, deduplication bounds, and suppression filters.
type Metric ¶
type Metric struct {
Operation Operation `json:"operation"`
Result Result `json:"result"`
Count uint64 `json:"count"`
Seconds float64 `json:"seconds"`
Buckets [len(durationBounds)]uint64 `json:"buckets"`
}
Metric contains an operation's count, total duration, and cumulative duration buckets for a result.
type MetricSample ¶
MetricSample is a structured gauge/counter sample from the existing runtime, process and registered collectors. Labels is the bounded, escaped Prometheus label representation; consumers must not interpret it as markup.
type MetricWriter ¶
type MetricWriter struct {
// contains filtered or unexported fields
}
MetricWriter validates and escapes collector samples. Invalid samples are dropped and counted as collector failures instead of corrupting the output.
type OTLPConfig ¶
type OTLPConfig struct {
Endpoint string
ServiceName string
Headers []OTLPHeader
Timeout time.Duration
Client *http.Client
}
OTLPConfig configures the standard-library OTLP/HTTP JSON trace exporter. Endpoint is the complete traces URL, for example https://collector.example:4318/v1/traces. Timeout caps one request (zero selects 10 seconds); the recorder's TraceTimeout also bounds each call. A nil Client uses an owned client that never follows redirects, so configured headers are sent only to Endpoint.
func (OTLPConfig) Validate ¶
func (c OTLPConfig) Validate() error
Validate checks the OTLP endpoint, service name, timeout, and bounded transport-safe headers.
type OTLPHeader ¶
OTLPHeader is one explicitly configured export header, typically collector authentication. Values stay redacted in formatting and logs.
type Outcome ¶
type Outcome string
Outcome identifies an observed operation result category.
func OutcomeFor ¶
OutcomeFor inspects errors inside owned isolation because custom Is/Unwrap methods can panic or call Goexit. Traversal is bounded: cyclic or excessively large/deep graphs report Failed. Methods must return and Is must perform a shallow comparison, as required by errors.Is. No error text is formatted.
type QuantileEstimate ¶
QuantileEstimate interpolates within the framework's cumulative histogram. Overflow means the estimate exceeds the largest finite bound. No samples means Available=false, never a fabricated zero duration.
func EstimateQuantile ¶
func EstimateQuantile(buckets []uint64, count uint64, q float64) (QuantileEstimate, error)
EstimateQuantile interpolates a quantile from cumulative duration buckets. Empty observations are unavailable; values beyond the final bound report overflow.
type Recorder ¶
type Recorder struct {
// contains filtered or unexported fields
}
Recorder is application-owned. New performs no I/O and starts no goroutines. Run owns reporter workers; Close rejects new spans and drains accepted spans and reporter callbacks. No global logger/provider is modified. Do not copy it. Span admission and completion use atomics and per-series shards; they never wait for snapshot formatting, collectors or exporter callbacks.
func FromContext ¶
FromContext returns the context's recorder, or nil if absent or the context is nil.
func (*Recorder) Claim ¶
Claim reserves a fresh recorder for one application builder without starting resources. Failed/abandoned builders still consume this reservation; create a fresh recorder for another builder. This prevents accidental cross-app shutdown of the same recorder. Direct standalone Run needs no reservation.
func (*Recorder) Close ¶
Close rejects new spans immediately. A deadline bounds the caller's wait; Done remains open while any span or accepted reporter callback still runs.
func (*Recorder) CollectSamples ¶
func (r *Recorder) CollectSamples() []MetricSample
CollectSamples reuses the existing collectors without parsing text exposition or retaining operation/correlation history. Every result is owned by the caller.
func (*Recorder) Done ¶
func (r *Recorder) Done() <-chan struct{}
Done returns the recorder's completion channel.
func (*Recorder) Gate ¶
func (r *Recorder) Gate() *maintenance.Gate
Gate returns the recorder's maintenance gate, or nil for a nil recorder.
func (*Recorder) Ready ¶
Ready waits until reporter admission has started or the recorder has closed. It reports runtime startup, not application or dependency readiness.
func (*Recorder) RegisterCollector ¶
RegisterCollector adds a named collector to later expositions. Names are declared semantic identifiers and unique per recorder; at most MaxCollectors may be registered and registration closes when the recorder closes.
func (*Recorder) Run ¶
Run owns reporter workers once. Parent cancellation seals admission and drains accepted spans/reports; deadlines remain cooperative and cannot abandon live callbacks. Run returns only after reporter work actually exits.
func (*Recorder) Snapshot ¶
Snapshot collects synchronized metric and recent-entry snapshots, sorting recent entries oldest first.
func (*Recorder) Start ¶
Start captures one operation and derives a trace child. A nil optional recorder preserves the input context and returns a nil span. Resource limits return an error and increment dropped-span accounting; instrumentation callers may continue their business operation without a span. An already-cancelled context is still observed: cancellation is the operation's outcome to report.
func (*Recorder) WritePrometheus ¶
WritePrometheus writes one owned snapshot in Prometheus 0.0.4 text format: operation metrics, recorder totals, Go runtime and process metrics, then samples from registered collectors. Metric labels are declared operation metadata; trace/request IDs, vendor state and payloads never become labels. Counts and cumulative histogram buckets come from the same snapshot. Registry and collector bounds cap the output size.
type Reporter ¶
type Reporter func(context.Context, ErrorReport) error
Reporter receives owned metadata in a bounded worker. It must honor context cancellation and return only after its work ends. Recorder shutdown retains ownership of callbacks that ignore the deadline. Panics/Goexit are isolated.
func LogReporter ¶
func LogReporter(logger *slog.Logger, config LogReporterConfig) (Reporter, error)
LogReporter logs each accepted error report once as a structured record with the redacted diagnostic and correlation IDs. It never logs error text or payloads. Duplicate suppression retains at most MaxFingerprints entries; the least recently reported fingerprint is forgotten first.
type Result ¶
Result contains operational metadata only. Status is an optional HTTP status; zero Outcome derives success/rejection/failure from it. Never put error text, URLs, payloads or user identifiers into an operation's declared metric name.
type Snapshot ¶
type Snapshot struct {
Closing bool `json:"closing"`
Mode maintenance.Mode `json:"mode"`
Active int `json:"active"`
Completed uint64 `json:"completed"`
Failures uint64 `json:"failures"`
DroppedSeries uint64 `json:"dropped_series"`
DroppedSpans uint64 `json:"dropped_spans"`
DroppedReports uint64 `json:"dropped_reports"`
ReporterFailures uint64 `json:"reporter_failures"`
PendingReports int `json:"pending_reports"`
DroppedTraces uint64 `json:"dropped_traces"`
TraceExportFailures uint64 `json:"trace_export_failures"`
PendingTraces int `json:"pending_traces"`
CollectorFailures uint64 `json:"collector_failures"`
Metrics []Metric `json:"metrics"`
Recent []Entry `json:"recent"`
}
Snapshot contains recorder lifecycle, queue, failure, metric, and recent operation data.
type Span ¶
type Span struct {
// contains filtered or unexported fields
}
Span retains one recorder admission until End. End is concurrency-safe and idempotent; forgetting it retains shutdown ownership. Nil spans are harmless. Do not copy a Span.
func (*Span) EndWithDiagnostic ¶
func (s *Span) EndWithDiagnostic(result Result, diagnostic fault.Diagnostic)
EndWithDiagnostic completes the span and attaches a redacted failure summary to the error report produced for a failed, panicked or timed-out result.
func (*Span) EndWithRoute ¶
func (s *Span) EndWithRoute(result Result, diagnostic fault.Diagnostic, route attribution.Route)
EndWithRoute adds a validated declared route at completion, when HTTP matching has finished. Invalid metadata is omitted; it never changes the operation.
type TraceBatchExporter ¶
TraceBatchExporter receives up to Config.TraceBatchSize sampled spans that were already queued together, in queue order. A trace worker never waits to fill a batch, so light traffic exports promptly in small batches. The slice is owned by the callback. One failed call counts one export failure.
func NewOTLPExporter ¶
func NewOTLPExporter(config OTLPConfig) (TraceBatchExporter, error)
NewOTLPExporter returns a batch exporter posting sampled spans as OTLP/HTTP JSON. Spans carry operation metadata, typed trace/span/request IDs and the outcome only; no payloads, error text or vendor tracestate. Each call makes one attempt without retry; a non-2xx response is an export failure.