Skip to main content
The Aspect CLI exports a trace for every invocation: the task, each Bazel build or test it runs, the failed actions, and every test and test attempt. It sends them over OTLP, together with the CLI’s logs and metrics on test results, the action cache and its own start-up time, to any backend that accepts OpenTelemetry. The metrics and Bazel’s exact timings on action, test and test_attempt spans require Aspect CLI v2026.46.21 or later.

Send to a collector

Set the standard OpenTelemetry environment variables:
In CI, set them from a secret. The Telemetry feature registers an exporter from the endpoint variables; set discover_endpoints = False to stop it. The headers, timeout and resource attributes still apply to every OTLP exporter, including those registered in config.axl. Everything exported carries the resource attributes service.name=aspect-cli and service.version.

Honeycomb

Use https://api.eu1.honeycomb.io:443 for an EU team. Traces land in the aspect-cli dataset and metrics in the one x-honeycomb-dataset names.

Datadog

Enable the OTLP receiver on the Datadog Agent running on the CI machine:
datadog.yaml
Then point the CLI at the Agent:
An OpenTelemetry Collector with the Datadog exporter works the same way.

Configure exporters in config.axl

For more than one collector, a signal routed to its own collector, extra resource attributes, or credentials read at run time, register exporters in .aspect/config.axl:
.aspect/config.axl
ctx.telemetry.exporters.add takes: A feature’s implementation can call the same function through its FeatureContext, for example to register an exporter only on one CI host. For a single invocation, pass the endpoint as a flag. It repeats, and each one uses gRPC with every signal:

What is exported

One trace per invocation:
action, test and test_attempt take their start and end times from Bazel. A cached test did no work in this build, so its test_attempt and test are zero-length spans at the moment the build reported the result, with cached set. A test with only some attempts cached spans the attempts that ran. Match a test_attempt to its test by label. Bazel reports only failed actions to the CLI. To get an action span for every action, add --build_event_publish_all_actions to your .bazelrc. On a large build that is a lot of spans. startup_ms on root is the time from the CLI starting until the task begins, not counting the launcher. The startup.<step> spans, together with eval, execute.configs and execute.features, show where that time went. Span events on build_tool record each target’s result (target_completed), the parsed command line (options_parsed) and every external download (fetch). Logs are the CLI’s own log lines, not Bazel’s output.
Spans carry Bazel command lines and flags, as Bazel and the CLI received them. Give your tracing backend the same access controls as your CI logs.

Metrics

None carries a target label, so the number of series stays bounded however large the repository. Metrics use delta temporality and are exported every 30 seconds and when the CLI exits. Set OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE or OTEL_METRIC_EXPORT_INTERVAL to change either.

Debug locally

ASPECT_DEBUG=1 prints the CLI’s log lines and trace events to stderr, including the exporters it registered:
It also prints how long the CLI took to start the task, step by step:
To write them, including the start-up line, to a file instead, register a file exporter. It appends; format is compact or jsonl:
.aspect/config.axl
The CLI flushes its exporters as it exits, waiting up to 5 seconds for each signal. Set ASPECT_TELEMETRY_SHUTDOWN_TIMEOUT_MS to change that.