Documentation
¶
Overview ¶
Package telemetry — the exporter: a bounded ring producers never wait on, drained to the clients attached to a private socket, which it never reads.
Package telemetry — the compile-time proof that Exporter is an Emitter.
Package telemetry is the port a running product reports what it does on, and the exporter that hands it to a tool attached to the product (ADR 0149).
It is not the trace domain. pkg/v1/observe/trace builds spans a backend stores and carries its context through context.WithValue; this port carries nothing through a context, builds nothing a caller keeps, and costs a producer one fixed-size copy into a bounded ring — zero allocations, pinned by a test (testing.AllocsPerRun) and measured in BENCH.md:
emitter.Emit(&telemetry.Event{Kind: telemetry.KindSpan, Op: telemetry.OpRequest,
Node: ref, Start: start, Duration: d, Outcome: telemetry.OutcomeOK})
A closed schema ¶
An Event holds numbers only: enumerations (Kind, Op, Outcome), a dotted-quad error code, instants, identifiers a trace already carries, and NODE REFERENCES — indexes into the table of node IDs the exporter sends once, in its handshake, each one checked against the ID grammar (framework/model.ParseID). There is no free text, so there is no field a person's name, an address or a request body could travel in: the schema itself is what keeps personal data out, in every environment.
Inert unless configured ¶
Nop is the emitter a product holds by default: Emit returns at once. An Exporter exists only when the product was started with one, and it only EMITS — it never reads what a client sends, so nothing reaches the product through it. It listens on a private socket (pkg/v1/proc/ipc, ADR 0148): the product's account and the UIDs and GIDs the deployment names, under the runtime directory; a stale socket is replaced, a live one refused. A client connects, reads one handshake line — product, binary, role, instance, revision, model version, design digest, the node table, the first sequence number — then fixed-size records (RecordSize bytes each) for as long as it reads. A slow client loses records, counted; the product never waits.
Package telemetry — the interfaces: what a producer emits to, and what the exporter needs of its listener and of a client.
Index ¶
Constants ¶
const ( MinBuffer int = 64 MaxBuffer int = 1 << 20 DefaultBuffer int = 4096 )
The ring's bounds and default, in events.
const CodeMisconfigured errs.Code = 0x00_04_03_01 // 0.4.3.1
CodeMisconfigured identifies an exporter configuration that cannot be honoured: no socket path, a buffer outside its bounds, an ID outside the grammar in the node table.
const CodeRunning errs.Code = 0x00_04_03_02 // 0.4.3.2
CodeRunning identifies a Start on an exporter already started.
const Protocol string = "app-telemetry/v1"
Protocol names the wire this package speaks, in the handshake. Since ADR 0180 step 4 it is app-telemetry/v1, a name the product sends; the wire is unchanged, and a collector accepts kit-telemetry/v1 as the same for two minors.
const RecordSize int = 64
RecordSize is the size of one record on the wire.
Variables ¶
var ( // Misconfigured refuses an exporter that cannot be built as asked; the // rule field says which rule failed. Misconfigured = errs.Static(CodeMisconfigured, "MISCONFIGURED", "The telemetry exporter is misconfigured", "framework/telemetry: no socket path, a buffer outside [64, 1<<20], or a node ID outside the grammar; the rule field says which", 0, 78) // Running refuses a second Start. Running = errs.Static(CodeRunning, "RUNNING", "The telemetry exporter is already running", "framework/telemetry: Start called on a started exporter", 0, 0) )
Functions ¶
This section is empty.
Types ¶
type Emitter ¶
type Emitter interface {
Emit(e *Event)
}
Emitter is where a product reports: the telemetry port. Emit copies e and never keeps it; it must not block and must not allocate.
var ( // OpNames are the operations' names, as framework/model spells them, // indexed by Op. The handshake sends them, so a reader never hard-codes // the table. OpNames = [opCount]string{ "", "request", "call", "read", "write", "publish", "deliver", "transition", "run", "auth", "send", "deliver-mail", "secret", "dispatch", "ask", "handle", "connect", "cli", "starting", "serving", "draining", "stopped", "failed", "closed", "open", "half-open", } // Nop is the emitter that reports nothing: what a product holds unless it // was started with an exporter. Nop Emitter = nop{} )
type Event ¶
type Event struct {
Kind Kind
Op Op
Outcome Outcome
// Node is where the work ran; From, the node it came from, if any.
Node, From NodeRef
// Code is the dotted-quad code of the error that ended it, 0 for none.
Code uint32
// Start is when it began, in Unix nanoseconds; Duration, how long it took.
Start, Duration int64
// TraceID and SpanID are the trace's, when there is one.
TraceID [16]byte
SpanID [8]byte
}
Event is one report. Its fields are numbers only — see the package comment: there is no field a person's data could travel in, in any environment.
type Exporter ¶
type Exporter struct {
// contains filtered or unexported fields
}
Exporter is an Emitter that hands events to the clients attached to its socket. It never blocks a producer: a full ring drops the event and counts it.
func NewExporter ¶
func NewExporter(cfg *ExporterConfig) (*Exporter, error)
NewExporter checks cfg and builds an exporter that listens nowhere yet: Start opens its socket.
func (*Exporter) Emit ¶
Emit copies ev into the ring, or drops it when the ring is full. It never blocks and never allocates.
func (*Exporter) Ref ¶
Ref is the reference of node id in the handshake's table; zero when the table does not hold it.
type ExporterConfig ¶
type ExporterConfig struct {
// Path is the private socket's absolute path (pkg/v1/proc/ipc).
Path string
// AllowUIDs and AllowGIDs admit accounts besides the product's own: the
// on-call group declared at deployment.
AllowUIDs, AllowGIDs []int
// Buffer is the ring's size in events, rounded up to a power of two, in
// [MinBuffer, MaxBuffer]; zero is DefaultBuffer.
Buffer int
// Hello is what the handshake says.
Hello HelloValue
}
ExporterConfig is where the exporter listens, who may attach, and how much it holds for a slow reader.
type HelloValue ¶
type HelloValue struct {
// Product, Binary and Role name what runs: the app, the binary and the
// process role it is (framework/model's IDs).
Product, Binary, Role string
// Revision is the VCS commit the binary was built from (vcs.revision).
Revision string
// Digest is the design's digest the code was generated from, when known.
Digest string
// Nodes are the node IDs events refer to: Nodes[i] is NodeRef(i+1).
Nodes []string
}
HelloValue is what the handshake says about the process, besides the operations and the record size: which product, binary and role run, from which revision and design, and the node table events refer to.
type Kind ¶
type Kind uint8
Kind says what an event reports.
const ( // KindSpan is one unit of work that ended on a node. KindSpan Kind = iota + 1 // KindPhase is the process changing phase: starting, serving, draining, // stopped, failed — Op carries it. KindPhase // KindRetry is a port's call about to be tried again: Node is the port, // Code the failure's, Duration the wait before the next attempt. KindRetry // KindBreaker is a port's breaker changing phase: Node is the port, Op // the phase it enters — closed, open, half-open. KindBreaker // KindRestart is a supervised loop restarting after a failure — a // consumer, a declared or a hand-written loop —: Node is its node, Code // the failure's, Duration the wait before it runs again. A reader counts // a node's restarts by counting these. KindRestart // KindGaveUp is a supervised loop the framework stopped restarting, its // failures over their bound: Node is its node, Code the give-up's. The // product is no longer live from then on. KindGaveUp )
The kinds.
type NodeRef ¶
type NodeRef uint32
NodeRef is a node's index in the handshake's node table, from 1; zero is "no node".
type Op ¶
type Op uint8
Op is what the work was: the span operations of framework/model.
const ( OpNone Op = iota OpRequest OpCall OpRead OpWrite OpPublish OpDeliver OpTransition OpRun OpAuth OpSend OpDeliverMail OpSecret OpDispatch OpAsk OpHandle OpConnect OpCLI // The phases, for KindPhase. OpStarting OpServing OpDraining OpStopped OpFailed // The breaker's phases, for KindBreaker. OpClosed OpOpen OpHalfOpen )
The operations, in the order of their names in OpNames; zero is none.