> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bronto.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Telemetry

> Send traces of the bronto CLI's own runs to any OTLP backend, and continue a caller's trace through TRACEPARENT.

The bronto CLI can trace its own runs with OpenTelemetry. This is off by default, and nothing is
sent anywhere unless you configure an exporter with the standard `OTEL_*` environment
variables. The only setting specific to the CLI is `BRONTO_TELEMETRY_CAPTURE`, which controls
[how much of the command line is recorded](#whats-recorded).

## Turn it on

Point `bronto` at an OTLP endpoint:

```sh theme={"dark"}
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
bronto search 'status >= 500' -d prod/checkout-service --since 1h
```

Each run produces:

* A root span named after the command, such as `bronto search` or `bronto monitors list`.
  It records `bronto.command` (the same command path), `process.executable.name`,
  `process.pid` and `process.exit.code`, and on failure `error.type`, which holds the
  [error code](/cli/reference/exit-codes) (for example `auth_invalid_key`). It also records the
  flags and arguments, sanitized as described in [What's recorded](#whats-recorded).
* A client span for each HTTP request to the Bronto API, retries included, as children of the
  root span. Each is named after the method and the API route, such as
  `GET /monitors/{monitorId}`, and records the route as `url.template`. A path that doesn't
  match a known route, such as one passed to [`bronto api`](/cli/extend/api), gets just the
  method (`GET`), so IDs never end up in span names.

These names follow the OpenTelemetry
[HTTP span conventions](https://opentelemetry.io/docs/specs/semconv/http/http-spans/). The root
span departs from the [CLI conventions](https://opentelemetry.io/docs/specs/semconv/cli/cli-spans/),
which name it after the executable alone (`bronto`). That would give every command the same
span name, so trace lists couldn't tell `bronto search` from `bronto monitors list`. The set
of commands is fixed, so the names stay low-cardinality.

Spans are flushed when the command exits. If the backend can't be reached, the exit is
delayed by at most 3 seconds, and the command's exit code and output don't change.

To send the CLI's traces to Bronto itself, use your region's ingestion endpoint and an
ingestion API key. See [Send Traces to Bronto](https://docs.bronto.io/tracing/send-traces):

```sh theme={"dark"}
export OTEL_EXPORTER_OTLP_ENDPOINT=https://ingestion.eu.bronto.io
export OTEL_EXPORTER_OTLP_HEADERS="x-bronto-api-key=$BRONTO_INGEST_KEY"
```

## Continue a trace

When `TRACEPARENT` is set, the root span of `bronto` becomes a child of that trace. `TRACESTATE` and
`BAGGAGE` are read too. This is the
[environment-variable carrier](https://opentelemetry.io/docs/specs/otel/context/env-carriers/)
convention that CI integrations and tools like
[otel-cli](https://github.com/equinix-labs/otel-cli) use, so a `bronto` call inside a traced
pipeline step shows up inside that step's trace:

```sh theme={"dark"}
# Inside a step whose tracer exported TRACEPARENT
bronto send -d deploys -m "deployed $GIT_SHA"
```

The trace context is passed on even when export is off. With `TRACEPARENT` set, requests
to the Bronto API carry a W3C `traceparent` header, and
[exec plugins](/cli/extend/plugins) get `TRACEPARENT`, `TRACESTATE` and `BAGGAGE` in their
environment. When `bronto` is exporting, those values point at its own spans, so a
plugin's spans nest under the `bronto` command that ran it.

## Settings

`bronto` reads these:

| Variable | Effect |
| - | - |
| `OTEL_EXPORTER_OTLP_ENDPOINT`, `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | Setting either one turns on OTLP export. |
| `OTEL_TRACES_EXPORTER` | Comma-separated list of `otlp`, `console` or `none`. `console` writes spans to stderr (not stdout, which carries the command's output). `none` turns export off. When this is unset, `otlp` is used if an endpoint is set. |
| `OTEL_EXPORTER_OTLP_PROTOCOL`, `OTEL_EXPORTER_OTLP_TRACES_PROTOCOL` | `http/protobuf` (default) or `grpc`. |
| `OTEL_SDK_DISABLED` | `true` turns tracing off, whatever else is set. |
| `OTEL_SERVICE_NAME` | Overrides `service.name`, which defaults to `bronto-cli`. |
| `OTEL_RESOURCE_ATTRIBUTES` | Extra resource attributes, such as `deployment.environment.name=ci`. |
| `OTEL_TRACES_SAMPLER`, `OTEL_TRACES_SAMPLER_ARG` | Sampler. The default, `parentbased_always_on`, follows the sampled flag in `TRACEPARENT`. |
| `BRONTO_TELEMETRY_CAPTURE` | How much of the command line the root span records: `default`, `none` or `all`. See [What's recorded](#whats-recorded). |
| `OTEL_LOG_LEVEL` | Export and configuration errors are silent by default, so they don't mix into stderr output that scripts parse. Set this to any value other than `none` to print them. |
| `TRACEPARENT`, `TRACESTATE`, `BAGGAGE` | The trace context to continue. |

The OTLP exporters also honor the rest of the standard exporter settings, such as
`OTEL_EXPORTER_OTLP_HEADERS`, `OTEL_EXPORTER_OTLP_TIMEOUT`, `OTEL_EXPORTER_OTLP_COMPRESSION`
and `OTEL_EXPORTER_OTLP_CERTIFICATE`, plus their `_TRACES_` variants.

## What's recorded

Command lines can hold queries, payloads and keys, so the root span records them only in
sanitized form. `BRONTO_TELEMETRY_CAPTURE` picks the level:

* **`default`**: `bronto.flags` lists the flags that were set, by name. Values go into
  `bronto.flag.<name>` and positional arguments into `bronto.args` as follows:

  | Kind | Examples | Recorded as |
  | - | - | - |
  | Bounded, numeric, names and IDs | `--since`, `--limit`, `--output`, `--dataset`, `--profile`, a resource id | as given |
  | Queries | the search query, `--where`, `--from-expr` | literals replaced by `?`: `status >= ? AND user.email = ?`. A query that `bronto` can't tokenize becomes `REDACTED`. |
  | `key=value` pairs | `--field`, `--tag`, `--eq` and the other filter flags | `key=?` |
  | URLs and API paths | `--base-url`, the path of `bronto api` | without credentials, query values `REDACTED` |
  | Free text, expressions and local paths | `--message`, `--jq`, `--select`, `--input`, the question for `bronto ask` | flag name only; positional arguments become `REDACTED` |

* **`none`**: only the command path, not even flag names.

* **`all`**: every value as given, plus the whole argument list as
  [`process.command_args`](https://opentelemetry.io/docs/specs/semconv/registry/attributes/process/).
  Use it to debug in an environment you control: queries, payloads and messages are exported
  verbatim.

At every level, including `all`, the value of `--api-key` is never recorded. An
unrecognized value records nothing, like `none`, and is reported when `OTEL_LOG_LEVEL` is
set. For [exec plugins](/cli/extend/plugins), whose flags `bronto` doesn't know, the arguments
are recorded only with `all`.

HTTP client spans record the request URL as `url.full`, with every query-string value
replaced by `REDACTED`, at every level. Only traces are exported. The bronto CLI doesn't emit
OpenTelemetry metrics or logs.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.