Skip to main content
Agent SDK for Go emits distributed traces via OpenTelemetry. Traces are no-op by default — no extra imports or init code required until you wire an exporter.

Default: no-op

Without WithObservabilityConfig or WithTracer, the agent uses built-in no-op tracers. Zero overhead. Requires a running OpenTelemetry-compatible collector (e.g. OpenTelemetry Collector or Jaeger). Quick local setup:
docker run --rm -p 4317:4317 -p 16686:16686 jaegertracing/all-in-one:latest
Configure traces, metrics, and logs in one block with WithObservabilityConfig:
a, err := agent.NewAgent(
    agent.WithTemporalConfig(cfg),
    agent.WithLLMClient(llmClient),
    agent.WithObservabilityConfig(&agent.ObservabilityConfig{
        Endpoint: "collector:4317",        // gRPC (default)
        Protocol: agent.OTLPProtocolGRPC,  // or OTLPProtocolHTTP
        Insecure: true,                    // dev only — omit for TLS in production
        // DisableTraces: true,            // opt out of traces only
    }),
)
defer a.Close() // flushes all OTLP exporters — required
defer a.Close() is required to flush buffered OTLP spans before process exit. Without it, spans from the last batch may be silently dropped. Similarly, call w.Stop() on AgentWorker processes.
Insecure: true disables TLS on the collector connection. Use only in development or trusted internal networks. Omit it (defaults to TLS) for production OTLP endpoints.
FieldDescription
EndpointOTLP collector URL — e.g. collector:4317 (gRPC) or http://collector:4318 (HTTP)
ProtocolOTLPProtocolGRPC (default) or OTLPProtocolHTTP
InsecureDisable TLS — dev/trusted networks only
DisableTracesSkip trace export while keeping metrics/logs
Use the same WithObservabilityConfig on NewAgent and NewAgentWorker so worker activity spans reach the same backend. Observability config participates in the Temporal agent fingerprint — caller and worker must match.

Bring your own tracer

Use WithTracer when you already have an OpenTelemetry provider or need fine-grained control via pkg/observability:
import "github.com/agenticenv/agent-sdk-go/pkg/observability"

tracer, err := observability.NewTracer(
    observability.WithName("my-service"),
    observability.WithEndpoint("collector:4317"),
    observability.WithInsecure(true),
)

a, err := agent.NewAgent(
    agent.WithLLMClient(llmClient),
    agent.WithTracer(tracer),
)
When WithObservabilityConfig enables traces, any WithTracer value is replaced by the OTLP tracer built from config. pkg/observability exposes additional options not on ObservabilityConfig — sampling ratio, batch timeout, export timeout, custom headers, service version, and deployment environment. See observability.Config.

Spans

SpanEmitted by
agent.runAgent.Run
agent.run.asyncAgent.RunAsync
agent.streamAgent.Stream (dispatch phase)
agent.loopIn-process agent loop (local runtime)
a2a.executeA2A server executor per request
llm.generateSync LLM call
llm.streamStreaming LLM call
tool.executeTool execution
tool.authorizeProgrammatic tool authorization
retriever.searchRetriever search (prefetch or agentic)
conversation.get_messagesLoad conversation history
conversation.add_messagesPersist conversation messages
memory.recallLoad scoped memories before a run
memory.storePersist one memory record
memory.store.batchPersist multiple records in one call
memory.dedupSemantic dedup lookup before store
memory.extractRun-end memory extraction (StoreModeAlways)

Common attributes

Spans and metrics share attribute keys where applicable:
AttributeWhen set
agent.nameAgent API spans (Run, Stream)
conversation.idWhen conversation options are passed
input.lengthRun input character count
modelLLM spans
providerLLM spans — openai, anthropic, gemini
toolTool execution spans
retrieverRetriever search spans
memory.kindMemory store/recall spans
memory.dedupDedup lookup spans
queryMemory recall spans

Temporal workflow traces

On the Temporal runtime, the agent loop runs as a Temporal workflow. The SDK emits its own spans (agent.loop, llm.generate, tool.execute, etc.) as child spans under the workflow execution — visible in any OTLP-connected backend. Temporal’s own server-side traces (workflow scheduling, history replay) are separate and require a Temporal-instrumented deployment. To correlate agent spans with Temporal workflow IDs, use WithObservabilityConfig on both the agent and worker process. The workflow.id appears as an attribute on the agent.run span.

Example collector config

Minimal otel-collector-config.yaml — accepts OTLP gRPC and exports to Jaeger and logging:
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: "0.0.0.0:4317"
      http:
        endpoint: "0.0.0.0:4318"

exporters:
  debug:
    verbosity: detailed
  otlp/jaeger:
    endpoint: "jaeger:4317"
    tls:
      insecure: true

service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [debug, otlp/jaeger]
Run with:
docker run --rm \
  -p 4317:4317 -p 4318:4318 \
  -v $(pwd)/otel-collector-config.yaml:/etc/otelcol/config.yaml \
  otel/opentelemetry-collector:latest

Worker shutdown

  • Agenta.Close() flushes trace exporters
  • Workerw.Stop() flushes OTLP on standalone worker processes
Embedded local workers flush via Agent.Close(). Example: Observability · Hooks.

Example

Observability

OTLP traces, metrics, and logs

Metrics

Counters and histograms alongside traces

Logs

OTLP log export

Telemetry

Run-level behavioral data on results

Worker Separation

Same observability config on agent and worker