telemetry

package
v0.2.1 Latest Latest
Warning

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

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

Documentation

Overview

Package telemetry configures OpenTelemetry for Tacklr hosts and process tools.

Default export is the LGTM stack via one OTLP endpoint (Grafana Alloy or the OpenTelemetry Collector → Tempo, Loki, Mimir/Prometheus, Grafana).

Host API:

  • Config, Init — process-wide OTLP traces/metrics/logs with Temporal's ReplaySafe tracer provider. Call before durable/temporal.Dial.
  • MeterProviderFromPrometheusRegisterer — Prometheus scrape
  • DefaultResource — service resource

Span starters, Instruments.Record*, attribute constants, and EmitEvent are for the harness and durable packages. Hosts must not start tacklr spans or record harness metrics; that can break traces and double-count metrics.

Index

Constants

View Source
const (
	SpanTurn           = "tacklr.turn"
	SpanTool           = "tacklr.tool"
	SpanPlanInstall    = "tacklr.plan.install"
	SpanContextHandoff = "tacklr.context.handoff"
	SpanModel          = "tacklr.model"
)

Span names (use these; backends index span name).

Trace shape (workflow is the primary instrumentor; do not wrap these in extra SDK/activity spans):

tacklr.turn                 static attrs: area, runtime, agent_id, session_id, turn.kind
  log: prompt.received | resume.received | turn.yielded | turn.ended
  tacklr.model | tacklr.tool | tacklr.plan.install | tacklr.context.handoff

Set static attributes at span start. Outcome and error enums at end only. Dynamic values (prompt text length, retry attempt, error body) belong on span-correlated logs, not as span attributes. Do not use high-cardinality values as metric labels; use log events for free text. Lifecycle milestones use OTel Logs SetEventName, not span.AddEvent.

View Source
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"
	AttrRuntime     = "tacklr.runtime" // embed | inprocess | temporal
	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"

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

View Source
const (
	TurnKindPrompt = "prompt"
	TurnKindResume = "resume"
)

Turn kind values for AttrTurnKind (closed enum).

View Source
const (
	RuntimeEmbed     = "embed"
	RuntimeInProcess = "inprocess"
	RuntimeTemporal  = "temporal"
)

Runtime values for AttrRuntime (closed enum). Durable backends that are not Temporal should pick a stable id of their own (e.g. "azure-df") rather than overloading these.

View Source
const (
	ModelPhaseTurn     = "turn"
	ModelPhaseHandoff  = "handoff"
	ModelPhaseCompress = "compress"
)

Model phase values for AttrModelPhase (closed enum).

View Source
const (
	GenAIOperationChat   = "chat"
	GenAIProviderAzure   = "azure.openai"
	GenAIProviderOpenAI  = "openai"
	GenAIProviderUnknown = "unknown"
)

GenAI operation / provider values (closed enums for low cardinality).

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

View Source
const (
	HandoffOutcomeOK       = "ok"
	HandoffOutcomeFallback = "fallback"
	HandoffOutcomeError    = "error"
)

Handoff outcome values.

View Source
const (
	EventPromptReceived  = "prompt.received"
	EventResumeReceived  = "resume.received"
	EventTurnEnded       = "turn.ended"
	EventTurnYielded     = "turn.yielded"
	EventChildSpawned    = "workflow.child_spawned"
	EventProviderFailed  = "provider.failed"
	EventModelAfterTools = "model.after_tools"
	EventFuseMount       = "vfs.fuse.mount"
	EventFuseMountError  = "vfs.fuse.mount_error"
	EventFuseUnmount     = "vfs.fuse.unmount"
	EventFuseUnavailable = "vfs.fuse.unavailable"
)

Log event names (OTel Logs API Record.SetEventName).

View Source
const (
	EventAttrPromptLen            = "prompt_len"
	EventAttrResumeInterruptCount = "resume_interrupt_count"
	EventAttrOutcome              = "outcome"
	EventAttrBodySnip             = "body_snip"
	EventAttrInputItems           = "input_items"
)

Event attribute keys on log-based events.

View Source
const (
	AreaRuntime    = "runtime"
	AreaHarness    = "harness"
	AreaModelTasks = "model_tasks"
	AreaContext    = "context"
	AreaInference  = "inference"
)

Area values for AttrArea.

View Source
const (
	OutcomeOK        = "ok"
	OutcomeError     = "error"
	OutcomeCancelled = "cancelled"
	OutcomeYield     = "yield"
)

Outcome values for AttrOutcome / EventAttrOutcome.

View Source
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"
	MetricFuseMount       = "tacklr.fuse.mount.total"
)

Metric names (OTel). Prometheus export sanitizes '.' → '_'.

View Source
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"
)

Label keys (low cardinality only — closed enums / config ids, never free text).

View Source
const (
	FuseMountOutcomeOK          = "ok"
	FuseMountOutcomeError       = "error"
	FuseMountOutcomeUnavailable = "unavailable"
)

Fuse mount outcomes for RecordFuseMount (closed enum).

View Source
const InstrumentationName = "github.com/ryanaldo34/tacklr"

InstrumentationName is the OpenTelemetry instrumentation scope for Tacklr.

Variables

This section is empty.

Functions

func AgentIDFromContext

func AgentIDFromContext(ctx context.Context) string

AgentIDFromContext returns agent_id or "".

func BindTurnContext added in v0.2.0

func BindTurnContext(ctx context.Context, agentID, sessionID string) context.Context

BindTurnContext attaches agent/session identity so child spans and metrics pick up labels from context.

func ClassifyErrorClass added in v0.2.0

func ClassifyErrorClass(err error, httpStatus int) string

ClassifyErrorClass buckets err into a closed error.class enum.

func ContextWithAfterTools

func ContextWithAfterTools(ctx context.Context) context.Context

ContextWithAfterTools marks the next model span as after a tool batch (harness use).

func ContextWithAgentID

func ContextWithAgentID(ctx context.Context, agentID string) context.Context

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

func ContextWithMeter(ctx context.Context, m metric.Meter) context.Context

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 ContextWithSessionID added in v0.2.0

func ContextWithSessionID(ctx context.Context, sessionID string) context.Context

ContextWithSessionID attaches session_id for child spans.

func DefaultResource

func DefaultResource(serviceName, serviceVersion string) *resource.Resource

DefaultResource builds a shared Resource for TracerProvider and MeterProvider so backends can correlate service.name across traces, metrics, and logs. Empty serviceName becomes "tacklr".

func EmitEvent

func EmitEvent(ctx context.Context, name string, attrs ...log.KeyValue)

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 EmitTurnReceived added in v0.2.0

func EmitTurnReceived(ctx context.Context, kind string, promptLen, resumeCount int)

EmitTurnReceived logs prompt.received or resume.received with dynamic sizes.

func Init

func Init(ctx context.Context, cfg Config) (func(context.Context) error, error)

Init installs the process-wide TracerProvider (ReplaySafe), MeterProvider, LoggerProvider, and W3C propagator. Call once, before durable/temporal.Dial. The Temporal OTEL v2 plugin and harness both use otel.GetTracerProvider().

func Logger

func Logger() log.Logger

Logger returns the package Logger from the global LoggerProvider (noop-safe).

func Meter

func Meter() metric.Meter

Meter returns a Tacklr-scoped Meter from the global MeterProvider.

func MeterFromContext

func MeterFromContext(ctx context.Context) metric.Meter

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

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 := telemetry.MeterProviderFromPrometheusRegisterer(reg, "my-agent", "")
// inprocess.New(catalog) / temporal.NewWorker(...)
// http.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))

serviceName/serviceVersion set the same resource attributes as OTLP Init.

func RecordCheckpointAttempt added in v0.2.0

func RecordCheckpointAttempt(ctx context.Context, err error)

RecordCheckpointAttempt records one harness snapshot persist (ok or error).

func SessionIDFromContext added in v0.2.0

func SessionIDFromContext(ctx context.Context) string

SessionIDFromContext returns session_id or "".

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 telemetry.Init / SetMeterProvider. Pass nil for noop.

func SetTracerProvider

func SetTracerProvider(tp trace.TracerProvider)

SetTracerProvider installs tp as the process-wide TracerProvider. Hosts that already own OTEL should pass a ReplaySafe provider for Temporal.

func Tracer

func Tracer() trace.Tracer

Tracer is otel.Tracer(InstrumentationName) on the process-wide provider.

Types

type Config

type Config struct {
	ServiceName    string
	ServiceVersion string
	OTLPEndpoint   string // host:port or URL; falls back to OTEL_EXPORTER_OTLP_ENDPOINT
	Protocol       string // "grpc" (default) or "http"
	Insecure       bool
	SampleRatio    float64 // (0,1]; <=0 means always sample
	DisableMetrics bool
	DisableLogs    bool
}

Config is the host-facing OTLP setup. Empty OTLPEndpoint (and no OTEL_EXPORTER_OTLP_ENDPOINT) still installs Temporal's ReplaySafe tracer provider so SessionWorkflow can call temporalotel.Tracer.

type HandoffSpan

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

HandoffSpan is an in-flight tacklr.context.handoff span. Call End once.

func StartHandoffSpan

func StartHandoffSpan(ctx context.Context, openTodos int) (context.Context, *HandoffSpan)

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. Names are constants; the SDK only errors on invalid names, which would be a compile-time programmer error.

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) RecordFuseMount added in v0.2.0

func (i *Instruments) RecordFuseMount(ctx context.Context, outcome string)

RecordFuseMount increments tacklr.fuse.mount.total{outcome=...}.

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 (i *Instruments) RecordTool(ctx context.Context, agentID, tool, namespace, status string, d time.Duration)

func (*Instruments) RecordTurnEnd

func (i *Instruments) RecordTurnEnd(ctx context.Context, agentID, turnKind, outcome string, d time.Duration)

func (*Instruments) RecordTurnOutcome added in v0.2.0

func (i *Instruments) RecordTurnOutcome(ctx context.Context, agentID, turnKind, outcome string, d time.Duration)

RecordTurnOutcome increments turn totals and duration without touching the in-flight gauge. Temporal workflows use this: replay would double-count RecordTurnStart/RecordTurnEnd on the active gauge.

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

type TokenUsage struct {
	Input     int
	Output    int
	Reasoning int
}

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

func StartToolSpan(ctx context.Context, name, namespace string) (context.Context, *ToolSpan)

StartToolSpan starts a child tool span.

func (*ToolSpan) Finish

func (t *ToolSpan) Finish(status string, err error)

Finish ends the tool span and records metrics. status is success, error, interrupt, or similar.

type TurnAttrs

type TurnAttrs struct {
	AgentID     string
	ThreadID    string
	SessionID   string
	Kind        string // prompt | resume
	LoadSession bool
	// Runtime is a closed enum (RuntimeEmbed | RuntimeInProcess | RuntimeTemporal)
	// or a host-defined durable-backend id. Empty omits the attribute.
	Runtime string
}

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

func StartTurnSpan(ctx context.Context, a TurnAttrs) (context.Context, *TurnSpan)

StartTurnSpan starts the root turn span on the process-wide tracer.

func (*TurnSpan) End

func (t *TurnSpan) End(outcome string)

End ends the turn span, emits turn.ended, and records metrics. outcome is a closed enum (OutcomeOK, OutcomeError, OutcomeCancelled, OutcomeYield).

type WindowShape

type WindowShape struct {
	Messages  int
	ToolPairs int
}

WindowShape is a low-cardinality snapshot of the context window for model spans.

Jump to

Keyboard shortcuts

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