# goose

> Send goose (the aaif open-source AI coding agent) telemetry — traces, metrics, and logs — to Last9 via OpenTelemetry.

Source: https://last9.io/docs/integrations/goose/

[goose](https://github.com/aaif-goose/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 like `WAITING_LLM_STREAM_START`/`END`
- **Metrics** — derived from `monotonic_counter.*` attributes on log events; instrumented via `tracing-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

1. **Last9 account** — Sign up at [app.last9.io](https://app.last9.io)
2. **goose installed** — `brew install block-goose-cli` or follow [install docs](https://goose-docs.ai/docs/getting-started/installation/)
3. **OTLP credentials** — Get your endpoint and auth header from [**Integrations → OpenTelemetry**](https://app.last9.io/integrations?integration=OpenTelemetry)

## Setup

goose honors the standard [OpenTelemetry SDK environment variables](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/) — no custom prefix.

1. **Get your Last9 OTLP credentials**

   Navigate to [**Integrations → OpenTelemetry**](https://app.last9.io/integrations?integration=OpenTelemetry) in your Last9 dashboard. Copy:

   - **OTLP Endpoint** (e.g., `https://otlp.last9.io` or `https://otlp-aps1.last9.io:443`)
   - **Authorization header** value (e.g., `Basic <base64-token>`)

2. **Add environment variables to your shell profile**

   Append the following to `~/.zshrc`, `~/.bashrc`, or equivalent:

**HTTP (recommended)**

   ```bash
   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/protobuf
   export OTEL_SERVICE_NAME=goose
   export OTEL_RESOURCE_ATTRIBUTES="deployment.environment=local"

   ```

**gRPC**

   ```bash
   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=grpc
   export OTEL_SERVICE_NAME=goose

   ```

3. **Reload your shell**

   ```bash
   source ~/.zshrc
   ```

4. **Run goose**

   ```bash
   goose session
   ```

   Or non-interactively:

   ```bash
   goose run -t "explain this file"
   ```

5. **Verify data is arriving**

   - **Traces** — open **Traces** in Last9, filter by `service.name = goose`. Look for `reply`, `complete`, `stream_response_from_provider` span names
   - **Metrics** — open **Metrics**, search for `goose_session_tokens` or `goose_session_duration_ms`
   - **Logs** — open **Logs**, filter by `service.name = goose`. Session events include `total_tokens`, `duration_ms`, `exit_type`

## 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`:

```yaml
otel_exporter_otlp_endpoint: "https://<your-last9-otlp-endpoint>"
otel_exporter_otlp_timeout: 30
```

Environment 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:

```promql
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:

```bash
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_ENDPOINT` in the same shell where you run `goose`. Restart the shell after editing `~/.zshrc`.
  - Verify `OTEL_SDK_DISABLED` is not set to `true`.

- **401 / authentication errors**

  - Header format must be `Authorization=Basic <token>` (key=value, not HTTP colon syntax)
  - Regenerate the token from [**Integrations → OpenTelemetry**](https://app.last9.io/integrations?integration=OpenTelemetry) if it has expired

- **Service name appears as `unknown_service`**

  - Set `OTEL_SERVICE_NAME=goose` explicitly. goose's resource builder defaults to `goose` but env vars take precedence.

- **High trace volume**

  - Set `OTEL_TRACES_SAMPLER=parentbased_traceidratio` and `OTEL_TRACES_SAMPLER_ARG=0.1` to sample 10% of traces

- **goose anonymous telemetry vs OpenTelemetry export**
  - These are separate. `GOOSE_TELEMETRY_ENABLED` controls goose's built-in anonymous usage data collection. The `OTEL_*` vars control the OpenTelemetry export to your collector. You can run both, neither, or just one.

Please get in touch with us on [Discord](https://discord.com/invite/Q3p2EEucx9) or [Email](mailto:support@last9.io) if you have any questions.
