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
- func AgentIDFromContext(ctx context.Context) string
- func BindTurnContext(ctx context.Context, agentID, sessionID string) context.Context
- func ClassifyErrorClass(err error, httpStatus int) 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 ContextWithSessionID(ctx context.Context, sessionID string) context.Context
- func DefaultResource(serviceName, serviceVersion string) *resource.Resource
- func EmitEvent(ctx context.Context, name string, attrs ...log.KeyValue)
- func EmitEventSeverity(ctx context.Context, name string, severity log.Severity, attrs ...log.KeyValue)
- func EmitTurnReceived(ctx context.Context, kind string, promptLen, resumeCount int)
- func Init(ctx context.Context, cfg Config) (func(context.Context) error, error)
- 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
- func RecordCheckpointAttempt(ctx context.Context, err error)
- func SessionIDFromContext(ctx context.Context) string
- func SetMeterProvider(mp metric.MeterProvider)
- func SetTracerProvider(tp trace.TracerProvider)
- func Tracer() trace.Tracer
- type Config
- type HandoffSpan
- type Instruments
- func (i *Instruments) RecordCheckpointSave(ctx context.Context, outcome string)
- func (i *Instruments) RecordCompress(ctx context.Context, agentID string)
- func (i *Instruments) RecordFuseMount(ctx context.Context, outcome 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) RecordTurnOutcome(ctx context.Context, agentID, turnKind, outcome string, d time.Duration)
- func (i *Instruments) RecordTurnStart(ctx context.Context, agentID string)
- type ModelIdentity
- type ModelSpan
- type PlanInstallSpan
- 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" )
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.
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).
const ( TurnKindPrompt = "prompt" TurnKindResume = "resume" )
Turn kind values for AttrTurnKind (closed enum).
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.
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 ( HandoffOutcomeOK = "ok" HandoffOutcomeFallback = "fallback" HandoffOutcomeError = "error" )
Handoff outcome values.
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" )
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 ( AreaRuntime = "runtime" AreaHarness = "harness" AreaModelTasks = "model_tasks" AreaContext = "context" AreaInference = "inference" )
Area values for AttrArea.
const ( OutcomeOK = "ok" OutcomeError = "error" OutcomeCancelled = "cancelled" OutcomeYield = "yield" )
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" MetricFuseMount = "tacklr.fuse.mount.total" )
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" )
Label keys (low cardinality only — closed enums / config ids, never free text).
const ( FuseMountOutcomeOK = "ok" FuseMountOutcomeError = "error" )
Fuse mount outcomes for RecordFuseMount (closed enum).
const InstrumentationName = "github.com/ryanaldo34/tacklr"
InstrumentationName is the OpenTelemetry instrumentation scope for Tacklr.
Variables ¶
This section is empty.
Functions ¶
func AgentIDFromContext ¶
AgentIDFromContext returns agent_id or "".
func BindTurnContext ¶ added in v0.2.0
BindTurnContext attaches agent/session identity so child spans and metrics pick up labels from context.
func ClassifyErrorClass ¶ added in v0.2.0
ClassifyErrorClass buckets err into a closed error.class enum.
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 ContextWithSessionID ¶ added in v0.2.0
ContextWithSessionID attaches session_id for child spans.
func DefaultResource ¶
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 ¶
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
EmitTurnReceived logs prompt.received or resume.received with dynamic sizes.
func Init ¶
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 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
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
RecordCheckpointAttempt records one harness snapshot persist (ok or error).
func SessionIDFromContext ¶ added in v0.2.0
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.
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 ¶
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 (*Instruments) RecordTurnEnd ¶
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 ¶
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
// 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 ¶
StartTurnSpan starts the root turn span on the process-wide tracer.
type WindowShape ¶
WindowShape is a low-cardinality snapshot of the context window for model spans.