obs

package
v0.40.1 Latest Latest
Warning

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

Go to latest
Published: Aug 22, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package obs bundles the library's injected observability — a zap logger, an OTel tracer, and the metric instruments — built once from the embedder's configuration and handed to each subsystem.

As a library, oteldb/storage never owns a global logger, tracer, or meter: the embedder supplies them through Config (via storage.Options). Every handle is **no-op by default** — an unset logger becomes zap.Nop, an unset provider becomes the OTel noop provider — so an unconfigured store spans, logs, and counts nothing and pays no overhead. The library imports only the OTel API (never an SDK or exporter); the embedder owns the SDK, sampling, and pipelines.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ExtractHTTP

func ExtractHTTP(ctx context.Context, h http.Header) context.Context

ExtractHTTP returns ctx augmented with the trace context read from the request headers, so a receiving handler's spans (and the engine spans below it) join the caller's trace. With the default no-op propagator it returns ctx unchanged.

func InjectHTTP

func InjectHTTP(ctx context.Context, h http.Header)

InjectHTTP writes the trace context from ctx into the request headers, so a node-to-node RPC carries the distributed trace. It uses the globally-configured OTel propagator (set by the embedder, e.g. propagation.TraceContext{}); the default is a no-op that writes nothing, so an unconfigured store propagates nothing at no cost.

Types

type Admission

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

Admission holds the ingest/admission meta-metrics (DESIGN §8a — observability is mandatory for overload control). They are recorded in **bulk** (one Add per write call per reason, never per-point), so they cost nothing on the hot inner loops. With the no-op meter every Add is a no-op.

func (*Admission) Accepted

func (a *Admission) Accepted(ctx context.Context, n int64, sig string)

Accepted records n points accepted for the given signal. A zero n is ignored.

func (*Admission) Overflowed added in v0.10.0

func (a *Admission) Overflowed(ctx context.Context, n int64, sig string)

Overflowed records n points routed to an overflow series past the soft cardinality budget for the given signal. A zero n is ignored.

func (*Admission) Rejected

func (a *Admission) Rejected(ctx context.Context, n int64, sig, reason string)

Rejected records n points shed for the given signal and reason (e.g. out_of_order, rate_limit, max_series, max_in_flight_bytes). A zero n is ignored.

func (*Admission) SampledDropped

func (a *Admission) SampledDropped(ctx context.Context, n int64, sig string)

SampledDropped records n points dropped by budgeted sampling for the given signal. A zero n is ignored.

type Backend

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

Backend instruments the L1 object-store operations.

func (*Backend) Record

func (b *Backend) Record(ctx context.Context, op, result string, dur time.Duration, bytes int64)

Record accounts one backend op (read/write/list/delete/cas) with its result (ok/not_found/error), wall time dur, and the bytes it moved (0 for none).

type Cluster added in v0.40.0

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

Cluster instruments this node's standing in the cluster member set — the state that decides whether any peer routes anything here at all. self_absent is the alertable form of a node that is up and serving but missing from etcd: the failure this cannot be inferred from any other signal, because the node itself looks perfectly healthy while it is happening.

func (*Cluster) Record added in v0.40.0

func (c *Cluster) Record(ctx context.Context, absent bool, rejoins int64)

Record publishes this node's membership standing: absent is whether it is currently missing from the member set, rejoins the re-registrations since the previous call.

type Config

type Config struct {
	Logger         *zap.Logger
	TracerProvider trace.TracerProvider
	MeterProvider  metric.MeterProvider
}

Config is the embedder-supplied observability configuration. A nil field selects the no-op implementation for that pillar.

type Disk added in v0.40.0

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

Disk instruments the medium's ability to take what the node accepts. A full disk or an exhausted inode table is not a transient backend fault: the node keeps acking writes it cannot store, so the two states need separate signals — a gauge that stands while the engine refuses writes, and a counter of the writes it refused.

func (*Disk) Record added in v0.40.0

func (d *Disk) Record(ctx context.Context, sig string, outOfSpace bool, rejected int64)

Record publishes a signal's disk-pressure state: whether its engine is currently refusing writes for want of room, and how many writes it refused since the previous call. Both are published together, from the flush that decides the state — the ingest path that counts a rejection carries no context of its own, and a counter is as useful at flush cadence as per write.

type Fetch

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

Fetch instruments a fetch over the head ∪ parts.

func (*Fetch) ForcedAdmission added in v0.37.0

func (f *Fetch) ForcedAdmission(ctx context.Context, sig string)

ForcedAdmission accounts one query admitted over the decode-memory ceiling because its wait made no progress. It is a liveness escape, so a non-zero rate means the budget is oversubscribed (or a caller holds several unscoped reads open) and the ceiling is not holding.

func (*Fetch) Record

func (f *Fetch) Record(ctx context.Context, sig string, dur time.Duration, series, partsScanned, rows int64)

Record accounts one fetch (matched `series` series, scanned `partsScanned` parts, returned `rows` rows, took dur) for the given signal.

type Flush

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

Flush instruments a head→part flush.

func (*Flush) Record

func (f *Flush) Record(ctx context.Context, sig string, dur time.Duration, rows int64)

Record accounts one flush: the row count written and the wall time dur, for the given signal.

type Merge

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

Merge instruments a background merge (compaction/retention/downsample/recompress).

func (*Merge) Record

func (m *Merge) Record(ctx context.Context, sig string, dur time.Duration, partsIn int64)

Record accounts one merge that compacted partsIn source parts in dur, for the given signal.

type Obs

type Obs struct {
	Log       *zap.Logger
	Tracer    trace.Tracer
	Admission *Admission
	Flush     *Flush
	Merge     *Merge
	Parts     *Parts
	Fetch     *Fetch
	Backend   *Backend
	WAL       *WAL
	RPC       *RPC
	Cluster   *Cluster
	Disk      *Disk
}

Obs is the observability handle passed to each subsystem. Log and Tracer are always non-nil (no-op when unconfigured); Admission holds the ingest meta-metrics.

func New

func New(cfg Config) (*Obs, error)

New builds the observability handle, defaulting each unset pillar to its no-op implementation. It returns an error only if the meter rejects an instrument name (it does not for valid names).

func NewNop

func NewNop() *Obs

NewNop returns a fully no-op handle (the default for tests and unconfigured stores). It never errors.

func (*Obs) Base

func (o *Obs) Base(ctx context.Context) context.Context

Base installs the injected logger as the zctx base in ctx, so any layer below can retrieve a trace-correlated logger via zctx.From without holding the obs handle. Seed it at each operation entry, before starting the span; zctx.From then attaches span_id/trace_id from the active span.

func (*Obs) Logger

func (o *Obs) Logger(ctx context.Context) *zap.Logger

Logger returns the trace-correlated logger for ctx — the injected base with span_id/trace_id attached when a span is active. It seeds the base first, so it is correct even when the caller forgot to (or could not) seed ctx upstream.

type Parts added in v0.37.0

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

Parts reports the merge selector's view of a signal's flushed parts as gauges: how many parts there are, how many are sealed (no merge will reconsider them), how many a merge may still take, how many the next merge would select, and the seal threshold in effect. Gauges rather than a log line because the question they answer — is compaction ever going to reduce this part count? — is asked of a dashboard over time, not of one cycle.

func (*Parts) Record added in v0.37.0

func (p *Parts) Record(ctx context.Context, sig string, total, sealed, backlog, candidates, capBytes int64)

Record publishes one signal's part shape, summed over the tenants this node holds. The values are tagged by signal only: tenant ids are unbounded, and [storage.Storage.Inspect] is the per-tenant surface.

type RPC

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

RPC instruments the node-to-node cluster transport's reliability behavior: how often calls are attempted, retried, or hedged (an opportunistic concurrent attempt fired because the in-flight one was slow). Counts are tagged by op ("read"/"write"/"series"/"side"), so a rising retry/hedge rate localizes a degrading link or peer.

func (*RPC) Attempt

func (r *RPC) Attempt(ctx context.Context, op string)

Attempt accounts one transport attempt (including the first) for op.

func (*RPC) Hedge

func (r *RPC) Hedge(ctx context.Context, op string)

Hedge accounts one hedged (opportunistic concurrent) attempt for op.

func (*RPC) Retry

func (r *RPC) Retry(ctx context.Context, op string)

Retry accounts one sequential retry for op.

func (*RPC) ShardAbsent added in v0.37.0

func (r *RPC) ShardAbsent(ctx context.Context, op string)

ShardAbsent accounts one read of a shard this node is a ring owner of but holds no data for, so the read failed over to another owner instead of answering empty. A sustained rate means the ring and the data disagree — a rebalance whose backfill has not caught up, or a lagging membership view.

func (*RPC) ShardIncomplete added in v0.38.0

func (r *RPC) ShardIncomplete(ctx context.Context, op string)

ShardIncomplete accounts one read of a shard this node holds but cannot fully answer for: it came back from a restart (or a rebalance) without the head the shard held unflushed, so the query window overlaps data only another owner has, and the read failed over. It clears once the shard's parts cover that window; a sustained rate means no owner is flushing.

type WAL

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

WAL instruments the write-ahead log. The recording methods use a background context (the WAL writer carries none) and are called at append/fsync/rotation granularity, never per sample.

func (*WAL) Append

func (w *WAL) Append()

Append accounts one WAL record-batch append.

func (*WAL) Fsync

func (w *WAL) Fsync()

Fsync accounts one WAL fsync.

func (*WAL) Rotate

func (w *WAL) Rotate()

Rotate accounts one WAL segment rotation.

Jump to

Keyboard shortcuts

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