goose
Send goose (the aaif open-source AI coding agent) telemetry — traces, metrics, and logs — to Last9 via OpenTelemetry.
goose is an aaif open-source AI coding agent. It emits structured OpenTelemetry data for every session: agent reply spans, model provider calls, tool dispatches, session token counts, and duration. Routing this to Last9 lets you measure adoption, model latency, cost, and tool reliability — within your existing observability stack.
goose exports all three OpenTelemetry signal types:
- Traces — spans covering
reply,reply_stream,complete,stream_response_from_provider,dispatch_tool_call, plus events likeWAITING_LLM_STREAM_START/END - Metrics — derived from
monotonic_counter.*attributes on log events; instrumented viatracing-opentelemetry - Logs — session events with token counts, duration, exit type, message count
Default temporality is cumulative, so metrics ingest cleanly into Last9 without conversion.
What gets exported
Spans
| Span | When |
|---|---|
reply | Top-level session reply (carries user_message, trace_input, session.id) |
reply_stream | Streaming response loop |
stream_response_from_provider | Single LLM streaming call (events: WAITING_LLM_STREAM_START, WAITING_LLM_STREAM_END) |
complete | Provider completion call (carries gen_ai.request.model) |
dispatch_tool_call | Single tool invocation (carries input, output, session.id) |
Session counters (emitted as log attributes)
| Attribute | Description |
|---|---|
monotonic_counter.goose.session_tokens | Total tokens consumed in the session |
monotonic_counter.goose.session_duration_ms | Total session wall time |
monotonic_counter.goose.session_completions | Number of completed sessions |
These counters propagate as native OTel metrics when tracing-opentelemetry’s MetricsLayer is active.
Prerequisites
- Last9 account — Sign up at app.last9.io
- goose installed —
brew install block-goose-clior follow install docs - OTLP credentials — Get your endpoint and auth header from Integrations → OpenTelemetry
Setup
goose honors the standard OpenTelemetry SDK environment variables — no custom prefix.
-
Get your Last9 OTLP credentials
Navigate to Integrations → OpenTelemetry in your Last9 dashboard. Copy:
- OTLP Endpoint (e.g.,
https://otlp.last9.ioorhttps://otlp-aps1.last9.io:443) - Authorization header value (e.g.,
Basic <base64-token>)
- OTLP Endpoint (e.g.,
-
Add environment variables to your shell profile
Append the following to
~/.zshrc,~/.bashrc, or equivalent:export OTEL_EXPORTER_OTLP_ENDPOINT="https://<your-last9-otlp-endpoint>"export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic <your-last9-auth-token>"export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobufexport OTEL_SERVICE_NAME=gooseexport OTEL_RESOURCE_ATTRIBUTES="deployment.environment=local"export OTEL_EXPORTER_OTLP_ENDPOINT="https://<your-last9-otlp-endpoint>:4317"export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic <your-last9-auth-token>"export OTEL_EXPORTER_OTLP_PROTOCOL=grpcexport OTEL_SERVICE_NAME=goose -
Reload your shell
source ~/.zshrc -
Run goose
goose sessionOr non-interactively:
goose run -t "explain this file" -
Verify data is arriving
- Traces — open Traces in Last9, filter by
service.name = goose. Look forreply,complete,stream_response_from_providerspan names - Metrics — open Metrics, search for
goose_session_tokensorgoose_session_duration_ms - Logs — open Logs, filter by
service.name = goose. Session events includetotal_tokens,duration_ms,exit_type
- Traces — open Traces in Last9, filter by
Configuration reference
Core
| Variable | Description |
|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT | Base OTLP endpoint (SDK appends /v1/traces, etc.) |
OTEL_EXPORTER_OTLP_HEADERS | key=value comma-separated auth headers |
OTEL_EXPORTER_OTLP_PROTOCOL | grpc, http/protobuf, or http/json |
OTEL_SERVICE_NAME | Service name override (defaults to goose) |
OTEL_RESOURCE_ATTRIBUTES | Comma-separated key=value resource tags |
OTEL_SDK_DISABLED | Set true to disable all OTel export |
Per-signal control
| Variable | Description |
|---|---|
OTEL_TRACES_EXPORTER | otlp, console, none |
OTEL_METRICS_EXPORTER | otlp, console, none |
OTEL_LOGS_EXPORTER | otlp, console, none |
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT | Traces-only endpoint override |
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT | Metrics-only endpoint override |
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT | Logs-only endpoint override |
Sampling and tuning
| Variable | Description |
|---|---|
OTEL_TRACES_SAMPLER | parentbased_traceidratio, always_on, etc. |
OTEL_TRACES_SAMPLER_ARG | Sampling ratio (e.g. 0.1 for 10%) |
OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE | cumulative (default), delta, or lowmemory |
OTEL_EXPORTER_OTLP_TIMEOUT | Export timeout in milliseconds |
Anonymous usage data (separate from OTel)
| Variable | Description |
|---|---|
GOOSE_TELEMETRY_ENABLED | Enable/disable goose’s anonymous usage data collection (separate from the OpenTelemetry export above) |
Configuration via goose config file
Alternatively, configure via ~/.config/goose/config.yaml:
otel_exporter_otlp_endpoint: "https://<your-last9-otlp-endpoint>"otel_exporter_otlp_timeout: 30Environment variables take precedence over config file values.
What you can do in Last9
Model latency tracking (traces)
stream_response_from_provider span duration is end-to-end LLM call latency. Filter by gen_ai.request.model to compare providers/models. p95/p99 over time catches degradation:
histogram_quantile(0.95, sum by (le, gen_ai_request_model) (rate(traces_span_metrics_duration_milliseconds_bucket{ServiceName="goose",SpanName="stream_response_from_provider"}[5m])))Token consumption (logs / metrics)
Per-session token counters are emitted as log attributes (monotonic_counter.goose.session_tokens). Aggregate via Last9 logs panel or convert to a metric. Sum over a time window for daily/weekly totals.
Session duration distribution (logs / metrics)
monotonic_counter.goose.session_duration_ms plus the structured log fields (exit_type, message_count, total_tokens) let you find long-running sessions or sessions that exited abnormally.
Tool reliability (traces)
dispatch_tool_call spans carry input, output, and session.id. Filter for failed spans (StatusCode=ERROR) to spot tool errors. Group by tool name from span attributes.
Session replay via session.id (traces + logs)
Every span and log carries session.id. Filter by it to reconstruct a single goose session — agent loop, model calls, tool dispatches — in trace order.
Sampling tip
For high-volume environments, sample 10% of traces to reduce volume:
export OTEL_TRACES_SAMPLER="parentbased_traceidratio"export OTEL_TRACES_SAMPLER_ARG="0.1"Counters and logs continue at full rate; only trace volume reduces.
Troubleshooting
-
No data in Last9
- Confirm
echo $OTEL_EXPORTER_OTLP_ENDPOINTin the same shell where you rungoose. Restart the shell after editing~/.zshrc. - Verify
OTEL_SDK_DISABLEDis not set totrue.
- Confirm
-
401 / authentication errors
- Header format must be
Authorization=Basic <token>(key=value, not HTTP colon syntax) - Regenerate the token from Integrations → OpenTelemetry if it has expired
- Header format must be
-
Service name appears as
unknown_service- Set
OTEL_SERVICE_NAME=gooseexplicitly. goose’s resource builder defaults togoosebut env vars take precedence.
- Set
-
High trace volume
- Set
OTEL_TRACES_SAMPLER=parentbased_traceidratioandOTEL_TRACES_SAMPLER_ARG=0.1to sample 10% of traces
- Set
-
goose anonymous telemetry vs OpenTelemetry export
- These are separate.
GOOSE_TELEMETRY_ENABLEDcontrols goose’s built-in anonymous usage data collection. TheOTEL_*vars control the OpenTelemetry export to your collector. You can run both, neither, or just one.
- These are separate.
Please get in touch with us on Discord or Email if you have any questions.