Documentation
¶
Overview ¶
Package telemetry configures OpenTelemetry for Tacklr hosts and process tools.
Host API:
- Config, Init — OTLP traces, metrics, and logs
- InstallDefault, InstallDefaultWithOTLP, NewLogger — slog setup
- MeterProviderFromPrometheusRegisterer — Prometheus scrape
- DefaultResource — service resource
- StdioWatchDog — AgentWatchDog that writes to stderr
- server.WithTracerProvider, WithMeterProvider — registry providers
Span starters, Instruments.Record*, attribute constants, and EmitEvent are for the harness and server packages. Hosts must not start tacklr spans or record harness metrics; that can break traces and double-count metrics.
Index ¶
- Constants
- func AgentIDFromContext(ctx context.Context) string
- func ContextWithAfterTools(ctx context.Context) context.Context
- func ContextWithAgentID(ctx context.Context, agentID string) context.Context
- func ContextWithInstruments(ctx context.Context, inst *Instruments) context.Context
- func ContextWithMeter(ctx context.Context, m metric.Meter) context.Context
- func ContextWithModelIdentity(ctx context.Context, id ModelIdentity) context.Context
- func ContextWithTracer(ctx context.Context, t trace.Tracer) context.Context
- func DefaultResource(serviceName, serviceVersion string) (*resource.Resource, error)
- func EmitEvent(ctx context.Context, name string, attrs ...log.KeyValue)
- func EmitEventSeverity(ctx context.Context, name string, severity log.Severity, attrs ...log.KeyValue)
- func Init(ctx context.Context, cfg Config) (shutdown func(context.Context) error, err error)
- func InstallDefault(base slog.Handler)
- func InstallDefaultWithOTLP(base, otlp slog.Handler)
- func Logger() log.Logger
- func Meter() metric.Meter
- func MeterFromContext(ctx context.Context) metric.Meter
- func MeterFromProvider(mp metric.MeterProvider) metric.Meter
- func MeterProviderFromPrometheusRegisterer(reg prometheus.Registerer, serviceName, serviceVersion string) (*sdkmetric.MeterProvider, error)
- func NewBrainObserver() brain.Observer
- func NewLogger(base slog.Handler) *slog.Logger
- func NewOTLPSlogHandler(name string) slog.Handler
- func SetMeterProvider(mp metric.MeterProvider)
- func SetTracerProvider(tp trace.TracerProvider)
- func Tracer() trace.Tracer
- func TracerFromContext(ctx context.Context) trace.Tracer
- func TracerFromProvider(tp trace.TracerProvider) trace.Tracer
- type BrainObserver
- type BrainSpan
- type Config
- type HandoffSpan
- type Instruments
- func (i *Instruments) RecordBrain(ctx context.Context, agentID, op, outcome, degrade string, empty bool, ...)
- func (i *Instruments) RecordCheckpointSave(ctx context.Context, outcome string)
- func (i *Instruments) RecordCompress(ctx context.Context, agentID string)
- func (i *Instruments) RecordHandoff(ctx context.Context, agentID, outcome string)
- func (i *Instruments) RecordInterrupt(ctx context.Context, agentID, kind string)
- func (i *Instruments) RecordModel(ctx context.Context, agentID, phase, outcome, errClass string, d time.Duration)
- func (i *Instruments) RecordSessionCreated(ctx context.Context)
- func (i *Instruments) RecordTokens(ctx context.Context, agentID string, input, output, reasoning int)
- func (i *Instruments) RecordTool(ctx context.Context, agentID, tool, namespace, status string, d time.Duration)
- func (i *Instruments) RecordTurnEnd(ctx context.Context, agentID, turnKind, outcome string, d time.Duration)
- func (i *Instruments) RecordTurnStart(ctx context.Context, agentID string)
- type ModelIdentity
- type ModelSpan
- type MultiHandler
- type PlanInstallSpan
- type SpanHandler
- type StdioWatchDog
- func (s *StdioWatchDog) RecordError(err error) error
- func (s *StdioWatchDog) RecordOutput(msg *streaming.Message) error
- func (s *StdioWatchDog) RecordThinking(msg *streaming.Message) error
- func (s *StdioWatchDog) RecordTokens(input, output int) error
- func (s *StdioWatchDog) RecordToolCalls(msg *streaming.Message) error
- func (s *StdioWatchDog) RecordToolResult(msg *streaming.Message) error
- type TokenUsage
- type ToolSpan
- type TurnAttrs
- type TurnSpan
- type WindowShape
Constants ¶
const ( SpanTurn = "tacklr.turn" SpanTool = "tacklr.tool" SpanPlanInstall = "tacklr.plan.install" SpanContextHandoff = "tacklr.context.handoff" SpanModel = "tacklr.model" SpanBrain = "tacklr.brain" )
Span names (use these; backends index span name).
Trace shape:
tacklr.turn
log: prompt.received | resume.received
tacklr.model | tacklr.tool | tacklr.plan.install | tacklr.context.handoff
tacklr.brain (under tool when knowledge builtins run)
log: turn.ended
Set static attributes at span start. Outcome and error enums at end only. Do not use high-cardinality values as metric labels; use log events for free text. Lifecycle milestones use OTel Logs SetEventName, not span.AddEvent.
const ( AttrArea = "tacklr.area" AttrSessionID = "tacklr.session_id" AttrAgentID = "tacklr.agent_id" AttrThreadID = "tacklr.thread_id" AttrTurnKind = "tacklr.turn.kind" // prompt | resume AttrLoadSession = "tacklr.load_session" AttrToolName = "tacklr.tool.name" AttrToolNS = "tacklr.tool.namespace" AttrToolStatus = "tacklr.tool.status" // success | error | interrupt | … AttrOpenTodos = "tacklr.open_todos" // remaining todos at handoff AttrOutcome = "tacklr.outcome" // ok | error | cancelled | fallback // Model invoke (tacklr.model) — start attrs where possible. AttrModelPhase = "tacklr.model.phase" // turn | handoff | compress AttrModelSeq = "tacklr.model.seq" AttrContextMsgs = "tacklr.context.messages" AttrContextToolPairs = "tacklr.context.tool_pairs" AttrHTTPStatus = "tacklr.http.status" AttrErrorCode = "tacklr.error.code" AttrErrorClass = "tacklr.error.class" // bucketed enum AttrAfterTools = "tacklr.model.after_tools" // Brain retrieval (tacklr.brain) — span attrs for trace debug only. // Metrics use LabelBrainOp / LabelDegrade / LabelEmpty (see RecordBrain). AttrBrainOp = "tacklr.brain.op" // see BrainOp* closed enum AttrBrainDegrade = "tacklr.brain.degrade" // none | lexical_only | containment_only AttrBrainHits = "tacklr.brain.hits" // page size; not a metric label (cardinality) // OpenTelemetry GenAI semantic conventions (stable keys). // https://opentelemetry.io/docs/specs/semconv/gen-ai/ AttrGenAIOperationName = "gen_ai.operation.name" AttrGenAIProviderName = "gen_ai.provider.name" AttrGenAIRequestModel = "gen_ai.request.model" AttrGenAIInputTokens = "gen_ai.usage.input_tokens" AttrGenAIOutputTokens = "gen_ai.usage.output_tokens" )
Span and log attribute keys (static identifiers only).
const ( ModelPhaseTurn = "turn" ModelPhaseHandoff = "handoff" ModelPhaseCompress = "compress" )
Model phase values for AttrModelPhase (closed enum).
const ( GenAIOperationChat = "chat" GenAIProviderAzure = "azure.openai" GenAIProviderOpenAI = "openai" GenAIProviderUnknown = "unknown" )
GenAI operation / provider values (closed enums for low cardinality).
const ( ErrorClassOK = "ok" ErrorClassProvider4xx = "provider_4xx" ErrorClassProvider5xx = "provider_5xx" ErrorClassMaxTokens = "max_tokens" ErrorClassCancelled = "cancelled" ErrorClassTimeout = "timeout" ErrorClassOther = "other" )
Error class buckets for metrics/span attrs (closed enum).
const ( BrainOpSearch = "search" BrainOpFindExact = "find_exact" BrainOpFindObjects = "find_objects" BrainOpFindLinks = "find_links" BrainOpContinue = "continue" BrainOpExpand = "expand" BrainOpExpandMany = "expand_many" )
Brain op values for AttrBrainOp / LabelBrainOp (closed enum). Keep in sync with brain.Op constants.
const ( BrainDegradeNone = "none" BrainDegradeLexicalOnly = "lexical_only" BrainDegradeContainmentOnly = "containment_only" )
Brain degrade modes (closed enum).
const ( HandoffOutcomeOK = "ok" HandoffOutcomeFallback = "fallback" HandoffOutcomeError = "error" )
Handoff outcome values.
const ( EventPromptReceived = "prompt.received" EventResumeReceived = "resume.received" EventTurnEnded = "turn.ended" EventProviderFailed = "provider.failed" EventModelAfterTools = "model.after_tools" )
Log event names (OTel Logs API Record.SetEventName).
const ( EventAttrPromptLen = "prompt_len" EventAttrResumeInterruptCount = "resume_interrupt_count" EventAttrOutcome = "outcome" EventAttrBodySnip = "body_snip" EventAttrInputItems = "input_items" )
Event attribute keys on log-based events.
const ( AreaRegistry = "registry" AreaHarness = "harness" AreaModelTasks = "model_tasks" AreaContext = "context" AreaInference = "inference" AreaBrain = "brain" )
Area values for AttrArea.
const ( OutcomeOK = "ok" OutcomeError = "error" OutcomeCancelled = "cancelled" )
Outcome values for AttrOutcome / EventAttrOutcome.
const ( MetricTurnDuration = "tacklr.turn.duration" MetricTurnTotal = "tacklr.turn.total" MetricTurnActive = "tacklr.turn.active" MetricToolCalls = "tacklr.tool.calls" MetricToolDuration = "tacklr.tool.duration" MetricInterruptTotal = "tacklr.interrupt.total" MetricHandoffTotal = "tacklr.context.handoff.total" MetricCompressTotal = "tacklr.context.compress.total" MetricSessionCreated = "tacklr.session.created.total" MetricCheckpointSave = "tacklr.checkpoint.save.total" MetricModelDuration = "tacklr.model.duration" MetricModelTotal = "tacklr.model.total" MetricTokensInput = "tacklr.tokens.input" MetricTokensOutput = "tacklr.tokens.output" MetricTokensReasoning = "tacklr.tokens.reasoning" MetricBrainTotal = "tacklr.brain.total" MetricBrainDuration = "tacklr.brain.duration" )
Metric names (OTel). Prometheus export sanitizes '.' → '_'.
const ( LabelAgentID = "agent_id" LabelTurnKind = "turn_kind" LabelOutcome = "outcome" LabelTool = "tool" LabelToolNS = "tool_namespace" LabelStatus = "status" LabelKind = "kind" // interrupt kind LabelModelPhase = "model_phase" LabelErrorClass = "error_class" LabelBrainOp = "brain_op" LabelDegrade = "degrade" LabelEmpty = "empty" // "true" | "false" )
Label keys (low cardinality only — closed enums / config ids, never free text).
const InstrumentationName = "github.com/ryanaldo34/tacklr"
InstrumentationName is the OpenTelemetry instrumentation library name for Tacklr spans and meters. Hosts that build Tracer/Meter from their own providers should use this name (or call TracerFromProvider / MeterFromProvider).
Variables ¶
This section is empty.
Functions ¶
func AgentIDFromContext ¶
AgentIDFromContext returns agent_id or "".
func ContextWithAfterTools ¶
ContextWithAfterTools marks the next model span as after a tool batch (harness use).
func ContextWithAgentID ¶
ContextWithAgentID attaches agent_id for tool/handoff metrics.
func ContextWithInstruments ¶
func ContextWithInstruments(ctx context.Context, inst *Instruments) context.Context
ContextWithInstruments attaches pre-built Instruments for the turn (and children).
func ContextWithMeter ¶
ContextWithMeter attaches m for MeterFromContext. Prefer ContextWithInstruments when instruments are pre-built for a registry.
func ContextWithModelIdentity ¶
func ContextWithModelIdentity(ctx context.Context, id ModelIdentity) context.Context
ContextWithModelIdentity attaches static GenAI identity for model spans.
func ContextWithTracer ¶
ContextWithTracer returns a child context that causes TracerFromContext to prefer t over the global provider. A nil t is ignored.
func DefaultResource ¶
DefaultResource builds a shared Resource for TracerProvider and MeterProvider so backends can correlate service.name across traces, metrics, and logs.
func EmitEvent ¶
EmitEvent emits an OTel log record with EventName set (span-correlated). Severity defaults to Info; use EmitEventSeverity for errors.
func EmitEventSeverity ¶
func EmitEventSeverity(ctx context.Context, name string, severity log.Severity, attrs ...log.KeyValue)
EmitEventSeverity is EmitEvent with an explicit severity.
func Init ¶
Init installs global TracerProvider, MeterProvider (unless DisableMetrics), LoggerProvider (unless DisableLogs), and a W3C text-map propagator. One OTLP endpoint serves traces, metrics, and logs so hosts can point a collector at a single address (Tempo + Mimir/Prometheus + Loki). Returns a shutdown that flushes exporters.
func InstallDefault ¶
InstallDefault wraps base with span correlation. Safe to call after Init.
func InstallDefaultWithOTLP ¶
InstallDefaultWithOTLP dual-writes slog to base (e.g. stderr) and OTLP logs (Loki via the collector). base and otlp may be nil (otlp skipped when nil). Span correlation is applied once on the combined handler.
func MeterFromContext ¶
MeterFromContext returns a context meter or the global Meter.
func MeterFromProvider ¶
func MeterFromProvider(mp metric.MeterProvider) metric.Meter
MeterFromProvider returns a Tacklr-scoped Meter from mp (or global if mp is nil).
func MeterProviderFromPrometheusRegisterer ¶
func MeterProviderFromPrometheusRegisterer(reg prometheus.Registerer, serviceName, serviceVersion string) (*sdkmetric.MeterProvider, error)
MeterProviderFromPrometheusRegisterer builds a MeterProvider that records into reg for classic Prometheus scrape (host serves GET /metrics via promhttp).
The host owns the HTTP server and scrape URL, for example:
reg := prometheus.NewRegistry()
mp, err := telemetry.MeterProviderFromPrometheusRegisterer(reg, "my-agent", "")
// server.NewRegistry(..., server.WithMeterProvider(mp))
// http.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))
serviceName/serviceVersion set the same resource attributes as OTLP Init.
func NewBrainObserver ¶
NewBrainObserver returns an Observer for brain.WithObserver.
func NewOTLPSlogHandler ¶
NewOTLPSlogHandler returns a slog.Handler that exports records via the global LoggerProvider (OTLP → collector → Loki). Call after Init so the provider is set. name is the instrumentation scope (typically the service name).
func SetMeterProvider ¶
func SetMeterProvider(mp metric.MeterProvider)
SetMeterProvider installs mp as the process-wide MeterProvider and rebuilds the cached global Instruments so later Init/SetMeterProvider calls take effect. Prefer server.WithMeterProvider for library hosts. Pass nil for noop.
func SetTracerProvider ¶
func SetTracerProvider(tp trace.TracerProvider)
SetTracerProvider installs tp as the process-wide OpenTelemetry TracerProvider. Hosts that already own OTEL should prefer server.WithTracerProvider on the registry instead of replacing the global. Pass nil for a no-op provider.
func Tracer ¶
Tracer returns the package tracer from the global TracerProvider (noop-safe when Init was not called with an endpoint).
func TracerFromContext ¶
TracerFromContext returns the tracer attached with ContextWithTracer, or the global package tracer when none is set.
func TracerFromProvider ¶
func TracerFromProvider(tp trace.TracerProvider) trace.Tracer
TracerFromProvider returns a Tacklr-scoped Tracer from tp. If tp is nil, returns the global Tracer().
Types ¶
type BrainObserver ¶
type BrainObserver struct{}
BrainObserver maps brain.Observer to tacklr.brain OTel spans/metrics.
type BrainSpan ¶
type BrainSpan struct {
// contains filtered or unexported fields
}
BrainSpan is an in-flight tacklr.brain span.
func StartBrainSpan ¶
StartBrainSpan starts a tacklr.brain child span.
type Config ¶
type Config struct {
ServiceName string
ServiceVersion string
// OTLPEndpoint is host:port or full URL. Empty uses OTEL_EXPORTER_OTLP_ENDPOINT
// when set; if still empty, tracing and metrics are no-op.
OTLPEndpoint string
// Protocol is "grpc" (default) or "http".
Protocol string
// Insecure disables TLS for the exporters (local collectors / Alloy).
Insecure bool
// SampleRatio in (0,1]; values <=0 are treated as 1.0 (always sample traces).
SampleRatio float64
// DisableMetrics skips MeterProvider setup (traces only). Default false:
// the same OTLP endpoint receives metrics.
DisableMetrics bool
// DisableLogs skips LoggerProvider setup. Default false: lifecycle events
// (prompt.received, provider.failed, …) export as OTel log records correlated
// to the active span (preferred over span.AddEvent).
DisableLogs bool
}
Config configures OTLP traces and metrics for a simple host process. An empty OTLPEndpoint (and no OTEL env endpoint) installs no-op providers.
type HandoffSpan ¶
type HandoffSpan struct {
// contains filtered or unexported fields
}
HandoffSpan is an in-flight tacklr.context.handoff span. Call End once.
func StartHandoffSpan ¶
StartHandoffSpan starts a context-handoff span. openTodos is remaining work.
func (*HandoffSpan) End ¶
func (s *HandoffSpan) End(outcome string, err error)
End ends the handoff span and records the handoff metric. outcome is HandoffOutcomeOK, HandoffOutcomeFallback, or HandoffOutcomeError.
type Instruments ¶
type Instruments struct {
// contains filtered or unexported fields
}
Instruments holds cached metric instruments for one Meter.
func InstrumentsFromContext ¶
func InstrumentsFromContext(ctx context.Context) *Instruments
InstrumentsFromContext returns instruments from context, or a shared set bound to the global meter (lazy).
func MustInstruments ¶
func MustInstruments(m metric.Meter) *Instruments
MustInstruments builds instruments from m. Panics only on programmer error from the SDK (invalid names); treated as init-time failure.
func NewInstruments ¶
func NewInstruments(m metric.Meter) (*Instruments, error)
NewInstruments creates counters/histograms on m.
func (*Instruments) RecordBrain ¶
func (i *Instruments) RecordBrain(ctx context.Context, agentID, op, outcome, degrade string, empty bool, d time.Duration)
RecordBrain records one knowledge-retrieval op.
Counter labels: agent_id, brain_op, outcome, degrade, empty ("true"|"false"). empty is only on the counter (empty-result rate); duration omits it to keep histogram series smaller. Hits live on the span only (per-request debug).
func (*Instruments) RecordCheckpointSave ¶
func (i *Instruments) RecordCheckpointSave(ctx context.Context, outcome string)
func (*Instruments) RecordCompress ¶
func (i *Instruments) RecordCompress(ctx context.Context, agentID string)
func (*Instruments) RecordHandoff ¶
func (i *Instruments) RecordHandoff(ctx context.Context, agentID, outcome string)
RecordHandoff records a context handoff. outcome is a closed enum (HandoffOutcomeOK | HandoffOutcomeFallback | HandoffOutcomeError).
func (*Instruments) RecordInterrupt ¶
func (i *Instruments) RecordInterrupt(ctx context.Context, agentID, kind string)
func (*Instruments) RecordModel ¶
func (i *Instruments) RecordModel(ctx context.Context, agentID, phase, outcome, errClass string, d time.Duration)
RecordModel records one model invoke (duration + count). phase and errClass must be closed enums (ModelPhase* / ErrorClass*).
func (*Instruments) RecordSessionCreated ¶
func (i *Instruments) RecordSessionCreated(ctx context.Context)
func (*Instruments) RecordTokens ¶
func (i *Instruments) RecordTokens(ctx context.Context, agentID string, input, output, reasoning int)
RecordTokens adds provider-reported token counts (no high-cardinality labels).
func (*Instruments) RecordTool ¶
func (*Instruments) RecordTurnEnd ¶
func (*Instruments) RecordTurnStart ¶
func (i *Instruments) RecordTurnStart(ctx context.Context, agentID string)
type ModelIdentity ¶
type ModelIdentity struct {
// Provider is a closed enum: azure.openai | openai | unknown.
Provider string
// Model is the deployment/model id (treat as low-cardinality config).
Model string
// Operation defaults to GenAIOperationChat when empty.
Operation string
}
ModelIdentity is static request identity for GenAI span attrs (set at span start).
func NewModelIdentity ¶
func NewModelIdentity(model, baseURL string) ModelIdentity
NewModelIdentity builds GenAI identity from deployment config (model id + API base URL).
type ModelSpan ¶
type ModelSpan struct {
// contains filtered or unexported fields
}
ModelSpan is an in-flight tacklr.model span. Call End once.
func StartModelSpan ¶
func StartModelSpan(ctx context.Context, phase string, seq int, shape WindowShape) (context.Context, *ModelSpan)
StartModelSpan starts a model span. Emits model.after_tools when ContextWithAfterTools is set.
func (*ModelSpan) End ¶
func (m *ModelSpan) End(err error, usage TokenUsage)
End ends the model span with outcome, usage, and metrics. HTTP status and code come from err when it implements providerStatus.
type MultiHandler ¶
MultiHandler fans out each record to every child handler (e.g. stderr + OTLP). Enabled is true if any child is enabled; Handle returns the first error.
type PlanInstallSpan ¶
type PlanInstallSpan struct {
// contains filtered or unexported fields
}
PlanInstallSpan is an in-flight tacklr.plan.install span. Call End once.
func StartPlanInstallSpan ¶
func StartPlanInstallSpan(ctx context.Context, sessionID string) (context.Context, *PlanInstallSpan)
StartPlanInstallSpan starts a plan-document install span.
func (*PlanInstallSpan) End ¶
func (s *PlanInstallSpan) End(err error)
End ends the span. err nil means ok; non-nil means error.
type SpanHandler ¶
type SpanHandler struct {
// contains filtered or unexported fields
}
SpanHandler wraps a slog.Handler and, for records that carry a context with an active span, attaches trace_id/span_id so logs correlate with traces.
It does not mirror log records as span events — that floods the turn lifecycle view with operational noise. Use a log backend that joins on trace_id instead.
func NewSpanHandler ¶
func NewSpanHandler(base slog.Handler) *SpanHandler
NewSpanHandler wraps base. base must not be nil.
type StdioWatchDog ¶
type StdioWatchDog struct{}
StdioWatchDog implements tacklr.AgentWatchDog via streaming.Message (type alias).
func NewStdioWatchDog ¶
func NewStdioWatchDog() *StdioWatchDog
NewStdioWatchDog returns a watchdog that logs agent activity to slog.
func (*StdioWatchDog) RecordError ¶
func (s *StdioWatchDog) RecordError(err error) error
func (*StdioWatchDog) RecordOutput ¶
func (s *StdioWatchDog) RecordOutput(msg *streaming.Message) error
func (*StdioWatchDog) RecordThinking ¶
func (s *StdioWatchDog) RecordThinking(msg *streaming.Message) error
func (*StdioWatchDog) RecordTokens ¶
func (s *StdioWatchDog) RecordTokens(input, output int) error
func (*StdioWatchDog) RecordToolCalls ¶
func (s *StdioWatchDog) RecordToolCalls(msg *streaming.Message) error
func (*StdioWatchDog) RecordToolResult ¶
func (s *StdioWatchDog) RecordToolResult(msg *streaming.Message) error
type TokenUsage ¶
TokenUsage is provider-reported token consumption for one model invoke.
type ToolSpan ¶
type ToolSpan struct {
// contains filtered or unexported fields
}
ToolSpan is an in-flight tacklr.tool span. Call Finish once.
func StartToolSpan ¶
StartToolSpan starts a child tool span.
type TurnAttrs ¶
type TurnAttrs struct {
AgentID string
ThreadID string
SessionID string
Kind string // prompt | resume
LoadSession bool
}
TurnAttrs are static attributes set when a turn starts.
type TurnSpan ¶
type TurnSpan struct {
// contains filtered or unexported fields
}
TurnSpan is the root tacklr.turn span. Call End once.
func StartTurnSpan ¶
StartTurnSpan starts the root turn span and records turn-active. Uses TracerFromContext (set ContextWithTracer first).
type WindowShape ¶
WindowShape is a low-cardinality snapshot of the context window for model spans.