telemetry

package
v0.17.0 Latest Latest
Warning

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

Go to latest
Published: Oct 3, 2026 License: MIT Imports: 14 Imported by: 0

README

telemetry

import "github.com/kitsunium/sdk/framework/telemetry"

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

The ring's bounds and default, in events.

const (
    MinBuffer     int = 64
    MaxBuffer     int = 1 << 20
    DefaultBuffer int = 4096
)

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 CodeMisconfigured errs.Code = 0x00_04_03_01 // 0.4.3.1

CodeRunning identifies a Start on an exporter already started.

const CodeRunning errs.Code = 0x00_04_03_02 // 0.4.3.2

Protocol names the wire this package speaks, in the handshake.

const Protocol string = "kit-telemetry/v1"

RecordSize is the size of one record on the wire.

const RecordSize int = 64

Variables

var (
    // Misconfigured refuses an exporter that cannot be built as asked; the
    // rule field says which rule failed.
    Misconfigured = errs.Define(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",
        errs.WithExitCode(78))

    // Running refuses a second Start.
    Running = errs.Define(CodeRunning, "RUNNING",
        "The telemetry exporter is already running",
        "framework/telemetry: Start called on a started exporter")
)

type Emitter

Emitter is where a product reports: the telemetry port. Emit copies e and never keeps it; it must not block and must not allocate.

type Emitter interface {
    Emit(e *Event)
}

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",
    }

    // Nop is the emitter that reports nothing: what a product holds unless it
    // was started with an exporter.
    Nop Emitter = nop{}
)

type Event

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 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
}

func Decode
func Decode(b []byte) (e Event, seq uint64, ok bool)

Decode reads one record, as a client does: the event and its sequence number. ok is false for a record of another size or version.

type Exporter

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.

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

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) Dropped
func (e *Exporter) Dropped() uint64

Dropped is how many events a full ring refused.

func (*Exporter) Emit
func (e *Exporter) Emit(ev *Event)

Emit copies ev into the ring, or drops it when the ring is full. It never blocks and never allocates.

func (*Exporter) Instance
func (e *Exporter) Instance() string

Instance is the process's instance identifier, in the handshake.

func (*Exporter) Ref
func (e *Exporter) Ref(id string) NodeRef

Ref is the reference of node id in the handshake's table; zero when the table does not hold it.

func (*Exporter) Sent
func (e *Exporter) Sent() uint64

Sent is how many records reached at least one client.

func (*Exporter) Start
func (e *Exporter) Start(ctx context.Context) error

Start opens the socket and starts the two goroutines: one accepts clients and greets them, one drains the ring to them. Both end at Stop.

func (*Exporter) Stop
func (e *Exporter) Stop(ctx context.Context) error

Stop closes the socket and every client, and waits for the goroutines.

type ExporterConfig

ExporterConfig is where the exporter listens, who may attach, and how much it holds for a slow reader.

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
}

type HelloValue

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 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
}

type Kind

Kind says what an event reports.

type Kind uint8

The kinds.

const (
    // KindSpan is one unit of work that ended on a node.
    KindSpan Kind = 1
    // KindPhase is the process changing phase: starting, serving, draining,
    // stopped, failed — Op carries it.
    KindPhase Kind = 2
)

type NodeRef

NodeRef is a node's index in the handshake's node table, from 1; zero is "no node".

type NodeRef uint32

type Op

Op is what the work was: the span operations of framework/model.

type Op uint8

The operations, in the order of their names in OpNames; zero is none.

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
)

func OpOf
func OpOf(name string) Op

OpOf is the Op named name, or OpNone.

type Outcome

Outcome says how the work ended.

type Outcome uint8

The outcomes.

const (
    OutcomeOK    Outcome = 1
    OutcomeError Outcome = 2
)

Generated by gomarkdoc

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

View Source
const (
	MinBuffer     int = 64
	MaxBuffer     int = 1 << 20
	DefaultBuffer int = 4096
)

The ring's bounds and default, in events.

View Source
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.

View Source
const CodeRunning errs.Code = 0x00_04_03_02 // 0.4.3.2

CodeRunning identifies a Start on an exporter already started.

View Source
const Protocol string = "kit-telemetry/v1"

Protocol names the wire this package speaks, in the handshake.

View Source
const RecordSize int = 64

RecordSize is the size of one record on the wire.

Variables

View Source
var (
	// Misconfigured refuses an exporter that cannot be built as asked; the
	// rule field says which rule failed.
	Misconfigured = errs.Define(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",
		errs.WithExitCode(78))

	// Running refuses a second Start.
	Running = errs.Define(CodeRunning, "RUNNING",
		"The telemetry exporter is already running",
		"framework/telemetry: Start called on a started exporter")
)

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",
	}

	// 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.

func Decode

func Decode(b []byte) (e Event, seq uint64, ok bool)

Decode reads one record, as a client does: the event and its sequence number. ok is false for a record of another size or version.

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) Dropped

func (e *Exporter) Dropped() uint64

Dropped is how many events a full ring refused.

func (*Exporter) Emit

func (e *Exporter) Emit(ev *Event)

Emit copies ev into the ring, or drops it when the ring is full. It never blocks and never allocates.

func (*Exporter) Instance

func (e *Exporter) Instance() string

Instance is the process's instance identifier, in the handshake.

func (*Exporter) Ref

func (e *Exporter) Ref(id string) NodeRef

Ref is the reference of node id in the handshake's table; zero when the table does not hold it.

func (*Exporter) Sent

func (e *Exporter) Sent() uint64

Sent is how many records reached at least one client.

func (*Exporter) Start

func (e *Exporter) Start(ctx context.Context) error

Start opens the socket and starts the two goroutines: one accepts clients and greets them, one drains the ring to them. Both end at Stop.

func (*Exporter) Stop

func (e *Exporter) Stop(ctx context.Context) error

Stop closes the socket and every client, and waits for the goroutines.

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 = 1
	// KindPhase is the process changing phase: starting, serving, draining,
	// stopped, failed — Op carries it.
	KindPhase Kind = 2
)

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 operations, in the order of their names in OpNames; zero is none.

func OpOf

func OpOf(name string) Op

OpOf is the Op named name, or OpNone.

type Outcome

type Outcome uint8

Outcome says how the work ended.

const (
	OutcomeOK    Outcome = 1
	OutcomeError Outcome = 2
)

The outcomes.

Jump to

Keyboard shortcuts

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