Documentation
¶
Overview ¶
Package telemetry processes tenant-owned business metrics.
Application stacks EMIT metric intents into the request envelope at `_txc.telemetry.metrics` (an array of {name, kind, value, unit, attrs} objects; MergeJSON's array-append semantics accumulate contributions from multiple rules). After the request completes — off the response path — the chassis validates, redacts, and enriches the intents, then hands them to the configured Exporter. Export is best-effort: a failure can drop metrics (counted via DropFunc) but never affects the request.
Enablement is per tenant, by convention: a tenant that sets the SecretEndpointName secret (`txco secrets set TELEMETRY_ENDPOINT`) has telemetry on; without it, intents are dropped. There is no config table — the endpoint and its auth headers ARE the configuration, and they are credentials, so the tenant secret store is where they live.
Known v1 gaps, accepted deliberately: requests completed on the continuation/deferred paths bypass the request-end seam; intents are visible in trace artifacts like any other envelope field; only the tenant-wide secret scope is consulted (no per-stack override).
Index ¶
Constants ¶
const ( SecretEndpointName = "TELEMETRY_ENDPOINT" SecretHeadersName = "TELEMETRY_HEADERS" )
Conventional tenant secret names — the tenant-facing enablement contract. SecretEndpointName holds the destination URL (https required, plain http allowed for loopback); its presence turns the feature on for the tenant. SecretHeadersName is optional and holds request headers in the OTel env-var format: "k1=v1,k2=v2".
Variables ¶
var ErrSecretNotFound = errors.New("telemetry: secret not found")
ErrSecretNotFound is the seam's own not-found sentinel so backends never import the secret store; the server-side SecretSource adapter maps the store's not-found error to this one.
Functions ¶
func HasMetrics ¶
HasMetrics reports whether the payload carries any metric intents — the zero-cost fast path for the overwhelmingly common case of a request that emits none.
func Register ¶
func Register(name string, c Constructor)
Register adds an exporter constructor. Called from a backend package's init().
Types ¶
type Constructor ¶
type Constructor func(ExporterConfig) (Exporter, error)
Constructor builds an Exporter from resolved config. Called by Open.
type DropFunc ¶
DropFunc counts metric intents that were dropped rather than exported, tagged with a small fixed reason vocabulary. May be nil — invoke it through Drop.
type Exporter ¶
type Exporter interface {
Name() string
Record(ctx context.Context, tenant string, events []MetricEvent)
Close(ctx context.Context) error
}
Exporter delivers validated metric events for one tenant at a time. Record must be best-effort and quick: buffer/aggregate in memory and ship in the background; never block on the network. Close flushes whatever is pending, bounded by the caller's context.
type ExporterConfig ¶
type ExporterConfig struct {
// NodeID is a stable identity for this chassis (FQDN-ish), for
// attribution when many nodes export the same tenant's metrics.
NodeID string
// Environment is the chassis environment (dev/stage/prod).
Environment string
// Logger is the chassis logger; a backend may emit observability
// lines but must never log secret values.
Logger *zap.Logger
// HTTPClient is the egress-guarded outbound client a network
// backend must use for tenant-supplied destinations.
HTTPClient *http.Client
// Secrets resolves per-tenant configuration secrets.
Secrets SecretSource
// Dropped counts metric intents dropped instead of exported.
Dropped DropFunc
}
ExporterConfig carries the node/runtime context a backend may need, resolved from chassis config. It is deliberately generic — the same posture as usage.SinkConfig — so the seam stays unopinionated; a backend reads any backend-specific settings in its constructor.
type MetricEvent ¶
type MetricEvent struct {
Tenant string
Stack string
Src string
Name string
Kind string // "counter" | "histogram"
Value float64
Unit string
// Attrs values are string, float64, or bool only (schema.go
// enforces this before an event is built).
Attrs map[string]any
Time time.Time
}
MetricEvent is one validated, enriched metric ready for export.
func ParseAndValidate ¶
func ParseAndValidate(payload []byte, tenant, stack, src string, now time.Time, dropped DropFunc) []MetricEvent
ParseAndValidate extracts `_txc.telemetry.metrics` from the final request envelope and returns the events that survive validation, enriched with the trusted request context (tenant/stack/src/time). Invalid entries are dropped (counted via dropped), never fatal.
type Processor ¶
type Processor struct {
// contains filtered or unexported fields
}
Processor is the request-end dispatcher: it reads metric intents off the final envelope, validates them, and hands survivors to the exporter. Construct once at server start; call Process from the request-completion path (after the response is written) and Close on shutdown. All methods are nil-receiver-safe so callers can hold a nil *Processor when the feature is off.
func NewProcessor ¶
NewProcessor builds a Processor around an opened Exporter. logger and dropped may be nil.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package log is the bundled "log" telemetry exporter: every validated metric event becomes one structured chassis log line.
|
Package log is the bundled "log" telemetry exporter: every validated metric event becomes one structured chassis log line. |
|
Package otlp is the bundled "otlp" telemetry exporter: each tenant's validated metric events feed a tenant-private OTel MeterProvider whose periodic reader ships OTLP/HTTP batches to the endpoint named by the tenant's TELEMETRY_ENDPOINT secret (auth headers from the optional TELEMETRY_HEADERS secret, OTel "k1=v1,k2=v2" format).
|
Package otlp is the bundled "otlp" telemetry exporter: each tenant's validated metric events feed a tenant-private OTel MeterProvider whose periodic reader ships OTLP/HTTP batches to the endpoint named by the tenant's TELEMETRY_ENDPOINT secret (auth headers from the optional TELEMETRY_HEADERS secret, OTel "k1=v1,k2=v2" format). |