# Gemini CLI

> Send Google Gemini CLI telemetry — traces, metrics, and logs — to Last9 via OpenTelemetry.

Source: https://last9.io/docs/integrations/gemini-cli/

[Gemini CLI](https://github.com/google-gemini/gemini-cli) is Google's open-source AI coding agent for the terminal. It emits structured OpenTelemetry data for every session: user prompts, tool calls, model API requests, agent runs, file operations, and token usage. Routing this to Last9 lets you measure adoption, model latency, cost, and tool reliability — within your existing observability stack.

Gemini CLI exports all three OpenTelemetry signal types:

- **Traces** — spans for tool dispatch, API requests, agent runs (enable with `GEMINI_TELEMETRY_TRACES_ENABLED=true`)
- **Metrics** — counters and histograms across session, tool, API, token, file, agent, and process domains
- **Logs** — structured events for prompts, API requests/responses, slash commands, file operations

## What gets exported

### Metrics

| Metric                             | Type      | Description                 |
| ---------------------------------- | --------- | --------------------------- |
| `gemini_cli.session.count`         | counter   | Sessions started            |
| `gemini_cli.tool.call.count`       | counter   | Tool invocations            |
| `gemini_cli.tool.call.latency`     | histogram | Tool latency (ms)           |
| `gemini_cli.api.request.count`     | counter   | Model API calls             |
| `gemini_cli.api.request.latency`   | histogram | Model API latency (ms)      |
| `gemini_cli.token.usage`           | counter   | Tokens used (in/out/cached) |
| `gemini_cli.file.operation.count`  | counter   | File ops (read/write/edit)  |
| `gemini_cli.lines.changed`         | counter   | Lines added/removed         |
| `gemini_cli.agent.run.count`       | counter   | Sub-agent invocations       |
| `gemini_cli.agent.duration`        | histogram | Sub-agent duration          |
| `gemini_cli.startup.duration`      | histogram | CLI startup time            |
| `gemini_cli.memory.usage`          | gauge     | Process memory              |
| `gemini_cli.cpu.usage`             | gauge     | Process CPU                 |
| `gen_ai.client.token.usage`        | counter   | GenAI semconv               |
| `gen_ai.client.operation.duration` | histogram | GenAI semconv               |

### Log events

`gemini_cli.config`, `gemini_cli.user_prompt`, `gemini_cli.tool_call`, `gemini_cli.api_request`, `gemini_cli.api_response`, `gemini_cli.api_error`, `gemini_cli.slash_command`, `gemini_cli.chat_compression`, `gemini_cli.conversation_finished`, `gemini_cli.agent.start`, `gemini_cli.agent.finish`, `gemini_cli.model_routing`, `gemini_cli.file_operation`, `gen_ai.client.inference.operation.details`

### Spans

`llm_call` (with `gen_ai.request.model`, `gen_ai.operation.name`, `gen_ai.usage.input_tokens`, `gen_ai.usage.output_tokens`, `gen_ai.conversation.id`)

## Prerequisites

1. **Last9 account** — Sign up at [app.last9.io](https://app.last9.io)
2. **Gemini CLI installed** — `npm install -g @google/gemini-cli`
3. **OTLP credentials** — Get your endpoint and auth header from [**Integrations → OpenTelemetry**](https://app.last9.io/integrations?integration=OpenTelemetry)

## Setup

Gemini CLI uses `GEMINI_TELEMETRY_*` env vars for the endpoint configuration, but the underlying OpenTelemetry JS SDK reads standard `OTEL_EXPORTER_OTLP_HEADERS` for authentication headers — so direct export to Last9 works.

1. **Get your Last9 OTLP credentials**

   Navigate to [**Integrations → OpenTelemetry**](https://app.last9.io/integrations?integration=OpenTelemetry). 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**

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

   ```bash
   # Gemini CLI telemetry switches
   export GEMINI_TELEMETRY_ENABLED=true
   export GEMINI_TELEMETRY_TARGET=local
   export GEMINI_TELEMETRY_OTLP_ENDPOINT="https://<your-last9-otlp-endpoint>"
   export GEMINI_TELEMETRY_OTLP_PROTOCOL=http
   export GEMINI_TELEMETRY_TRACES_ENABLED=true

   # Standard OTel env — picked up by the SDK for auth headers
   export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic <your-last9-auth-token>"
   ```

3. **Reload your shell**

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

4. **Run Gemini CLI**

   ```bash
   gemini -p "explain this repo"
   ```

5. **Verify data is arriving**

   - **Traces** — open **Traces** in Last9, filter by `service.name = gemini-cli`. Span `llm_call` should appear.
   - **Metrics** — open **Metrics**, search for `gemini_cli_session_count_total`, `gemini_cli_api_request_count_total`, or `gemini_cli_token_usage_total`
   - **Logs** — open **Logs**, filter by `service.name = gemini-cli`. Look for `gemini_cli.user_prompt`, `gemini_cli.api_request`.

## Configuration reference

### Gemini CLI-specific env vars

| Variable                          | Default                 | Description                                           |
| --------------------------------- | ----------------------- | ----------------------------------------------------- |
| `GEMINI_TELEMETRY_ENABLED`        | `false`                 | Master toggle                                         |
| `GEMINI_TELEMETRY_TARGET`         | `local`                 | `local` (OTLP) or `gcp` (Google Cloud)                |
| `GEMINI_TELEMETRY_OTLP_ENDPOINT`  | `http://localhost:4317` | OTLP endpoint (base URL — `/v1/traces` etc. appended) |
| `GEMINI_TELEMETRY_OTLP_PROTOCOL`  | `grpc`                  | `grpc` or `http`                                      |
| `GEMINI_TELEMETRY_TRACES_ENABLED` | `false`                 | Opt-in span export                                    |
| `GEMINI_TELEMETRY_LOG_PROMPTS`    | `true`                  | Include prompt text in logs                           |

### Standard OTel env vars (used for auth headers)

| Variable                             | Purpose                                                                     |
| ------------------------------------ | --------------------------------------------------------------------------- |
| `OTEL_EXPORTER_OTLP_HEADERS`         | `key=value` comma-separated auth headers. Use `Authorization=Basic <token>` |
| `OTEL_EXPORTER_OTLP_TRACES_HEADERS`  | Traces-only override                                                        |
| `OTEL_EXPORTER_OTLP_METRICS_HEADERS` | Metrics-only override                                                       |
| `OTEL_EXPORTER_OTLP_LOGS_HEADERS`    | Logs-only override                                                          |

Configure via `~/.gemini/settings.json` instead of env if you prefer:

```json
{
  "telemetry": {
    "enabled": true,
    "target": "local",
    "otlpEndpoint": "https://<your-last9-otlp-endpoint>",
    "otlpProtocol": "http",
    "traces": true,
    "logPrompts": true
  }
}
```

Environment variables still need to provide `OTEL_EXPORTER_OTLP_HEADERS` for auth — the Gemini CLI settings file doesn't have an OTLP headers field.

## Local Collector (optional)

If you want batching, retries, fan-out to multiple backends, or to inject auth headers without modifying user shells, run a local OTel Collector:

```bash
docker run -d \
  --name gemini-cli-otel-collector \
  -e LAST9_OTLP_ENDPOINT="https://<your-last9-otlp-endpoint>" \
  -e LAST9_OTLP_AUTH="Basic <your-last9-auth-token>" \
  -p 4317:4317 -p 4318:4318 \
  -v "$(pwd)/otel-collector-config.yaml:/etc/otel/config.yaml:ro" \
  otel/opentelemetry-collector-contrib:0.144.0 \
  --config=/etc/otel/config.yaml
```

Then point Gemini CLI at the collector:

```bash
export GEMINI_TELEMETRY_OTLP_ENDPOINT=http://localhost:4317
export GEMINI_TELEMETRY_OTLP_PROTOCOL=grpc
unset OTEL_EXPORTER_OTLP_HEADERS   # collector handles auth
```

See the [reference example](https://github.com/last9/opentelemetry-examples/tree/main/gemini-cli) for a complete collector config.

## Troubleshooting

- **No data in Last9** — confirm `echo $GEMINI_TELEMETRY_ENABLED` returns `true` in the shell that ran `gemini`. Restart shell after editing `~/.zshrc`.
- **Authentication errors** — verify `OTEL_EXPORTER_OTLP_HEADERS` is `Authorization=Basic <token>` (note the `=`, not HTTP colon syntax).
- **Traces missing** — set `GEMINI_TELEMETRY_TRACES_ENABLED=true`. Span export is opt-in.
- **Metric names** — Gemini CLI metrics use dots in source (`gemini_cli.session.count`) but appear in Last9 with underscores (`gemini_cli_session_count_total`).

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