Choose Who Exports Your Traces
Decide whether ArmorIQ or your application owns the OpenTelemetry tracer provider, and set the destination for your traces.
This page is for developers and platform engineers who already run OpenTelemetry, or who want to send ArmorIQ traces to another tool. You learn the three export choices, who owns the tracer provider in each one, and how to configure them.
Terms used on this page
- A span is one timed step in an agent run, for example one tool call. A trace is all the spans of one run.
- A TracerProvider is the OpenTelemetry object that creates spans and passes them to an exporter.
- An exporter sends finished spans to a destination.
- OTLP (OpenTelemetry Protocol) is the standard format and HTTP route that OpenTelemetry tools use to exchange traces. The SDK sends OTLP over HTTP with protobuf encoding (
http/protobuf). It supports no other OTLP encoding. - An OpenTelemetry Collector is a service that you run. It receives spans, processes them, and forwards them to one or more destinations. See Deploy an OpenTelemetry Collector.
The three choices
One SDK runtime has exactly one export choice. You set it with the exporter option.
exporter | Who owns the TracerProvider | Where spans go | Data limit |
|---|---|---|---|
armoriq (default) | ArmorIQ (a private provider inside the SDK) | POST /v1/traces on your ArmorIQ backend, with your API key | The organization capture policy |
external | ArmorIQ (a private provider inside the SDK) | The OTLP endpoint that you set, for example a Collector | The organization capture policy. Prompt and tool content leave only if the organization also allows external content. |
provider | Your application | Wherever your own provider sends them | Metadata only, always |
If you set an unknown value in the exporter option, the SDK uses armoriq.
ArmorIQ-owned provider
With armoriq and external, the SDK builds a private tracer provider with its own batch exporter. The provider stays isolated from your application:
- The SDK never registers its provider as the global OpenTelemetry provider.
- The SDK never changes, replaces, or shuts down a provider that your application created.
- In TypeScript, ArmorIQ spans start from an empty trace context. The trace context of your own web request does not leak into the ArmorIQ trace.
- When the session or client closes, the SDK flushes its own provider, and shuts it down when the last user of that provider closes. A close is bounded in time. It never blocks your agent for long.
Use these choices when you want ArmorIQ to manage export and keep your own OpenTelemetry setup unchanged.
Application-owned provider
With provider, you pass your own tracer provider. The SDK only asks it for a tracer named armoriq_sdk. Then:
- The SDK adds no span processor and no exporter to your provider.
- The SDK never flushes, shuts down, or changes your provider. You control destination, sampling, and batching.
- ArmorIQ capture is limited to
metadata. The SDK cannot re-check the organization policy on spans that wait in a queue that it does not own. So it never records prompts, completions, tool arguments, or tool results in this mode. To capture content, usearmoriqorexternal. - In TypeScript, the root span of a session becomes a child of the active span in your application.
Provider mode needs a provider. If you set exporter to provider and give no provider, the SDK exports nothing. See Troubleshooting.
Configure the export
import os
from armoriq_sdk import ArmorIQClient, ObservabilityOptions
# 1. ArmorIQ OTLP (default). No options needed.
client = ArmorIQClient(api_key=os.environ["ARMORIQ_API_KEY"])
# 2. Your own OTLP endpoint, for example a Collector.
client = ArmorIQClient(
api_key=os.environ["ARMORIQ_API_KEY"],
observability=ObservabilityOptions(
exporter="external",
endpoint="https://collector.example.com/v1/traces",
headers={"authorization": f"Bearer {os.environ['COLLECTOR_TOKEN']}"},
),
)
# 3. Your own tracer provider.
client = ArmorIQClient(
api_key=os.environ["ARMORIQ_API_KEY"],
observability=ObservabilityOptions(
exporter="provider",
tracer_provider=my_tracer_provider,
),
)import { ArmorIQClient } from '@armoriq/sdk';
// 1. ArmorIQ OTLP (default). No options needed.
const client = new ArmorIQClient({ apiKey: process.env.ARMORIQ_API_KEY! });
// 2. Your own OTLP endpoint, for example a Collector.
const external = new ArmorIQClient({
apiKey: process.env.ARMORIQ_API_KEY!,
observability: {
exporter: 'external',
endpoint: 'https://collector.example.com/v1/traces',
headers: { Authorization: `Bearer ${process.env.COLLECTOR_TOKEN}` },
},
});
// 3. Your own tracer provider.
const session = client.startSession({
observability: { exporter: 'provider', tracerProvider: myTracerProvider },
});You can use the standard OpenTelemetry environment variables instead of code. Keep tokens in a secret store and inject them as environment variables. Do not write them in source files.
export ARMORIQ_OTEL_EXPORTER=external
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://collector.example.com/v1/traces
export OTEL_EXPORTER_OTLP_TRACES_HEADERS="authorization=Bearer%20${COLLECTOR_TOKEN}"Header values use URL encoding, so a space is %20. Do not set a content-type header. The SDK always sends application/x-protobuf.
Rules for the endpoint
- Use
https:for any host that is not on your own machine. The SDK acceptshttp:only forlocalhost,127.0.0.1, and::1. A plainhttp:request would send your headers and permitted content in clear text. - Do not put a user name, password, query string, or fragment in the URL.
- The SDK uses the first endpoint setting that it finds. It does not try the next one when the first is invalid. If that setting is not valid, the SDK exports nothing.
- If you set no endpoint, the SDK exports nothing. It does not fall back to
localhost. It does not fall back to ArmorIQ. - After an export fails, the SDK does not switch to another destination.
Settings reference
| Setting | Python | TypeScript |
|---|---|---|
| Pick the exporter | ObservabilityOptions(exporter=...). The variable ARMORIQ_OTEL_EXPORTER overrides the option. | observability.exporter. The option wins over ARMORIQ_OTEL_EXPORTER. If you set neither and an endpoint setting exists, the SDK chooses external. |
| Endpoint order (first one set is used) | endpoint option, ARMORIQ_OTEL_ENDPOINT, OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, then OTEL_EXPORTER_OTLP_ENDPOINT | endpoint option, baseEndpoint option, OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, OTEL_EXPORTER_OTLP_ENDPOINT, then ARMORIQ_OTEL_ENDPOINT |
| Base endpoint form | OTEL_EXPORTER_OTLP_ENDPOINT. The SDK adds /v1/traces. | baseEndpoint option or OTEL_EXPORTER_OTLP_ENDPOINT. The SDK adds /v1/traces. |
| Headers | OTEL_EXPORTER_OTLP_HEADERS, then OTEL_EXPORTER_OTLP_TRACES_HEADERS, then the headers option. Later items win. | Same order |
| Timeout | timeout_millis, OTEL_EXPORTER_OTLP_TRACES_TIMEOUT, OTEL_EXPORTER_OTLP_TIMEOUT, ARMORIQ_OTEL_EXPORT_TIMEOUT_MS. Default 10 seconds. The SDK keeps the value between 0.1 and 30 seconds. | timeoutMillis, OTEL_EXPORTER_OTLP_TRACES_TIMEOUT, OTEL_EXPORTER_OTLP_TIMEOUT. Default 10 seconds. A value that is not a positive whole number turns external export off. |
| Custom CA and client certificate | OTEL_EXPORTER_OTLP_CERTIFICATE, OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE, OTEL_EXPORTER_OTLP_CLIENT_KEY (and the _TRACES_ forms). external only. | Not supported. Terminate TLS settings in a Collector. |
| Service name | service_name option or OTEL_SERVICE_NAME. The client uses agent_id when you set neither. | serviceName option or OTEL_SERVICE_NAME. The default is armoriq-sdk. |
| Local data ceiling | capture_mode option or ARMORIQ_OTEL_CAPTURE_MODE. The variable overrides the option. | captureMode option or ARMORIQ_OTEL_CAPTURE_MODE. The option wins. |
| Turn tracing off | observability_enabled=False on the session, ObservabilityOptions(enabled=False), or ARMORIQ_OBSERVABILITY | observability.enabled = false, ARMORIQ_OBSERVABILITY, OTEL_SDK_DISABLED=true, or OTEL_TRACES_EXPORTER=none |
The TypeScript SDK does not support gRPC, OTLP/JSON, request compression, HTTP proxy settings, or mTLS in its own exporter. If you need one of these, send to a Collector and set it there.
What every export choice still obeys
- The organization policy is the upper limit. The SDK reads your organization capture policy with your API key. A local setting can only lower the data that you capture. It can never raise it. See Organization controls.
- External export waits for the policy. With
external, the TypeScript SDK waits up to 1.4 seconds for the policy before the first trace of a session. If the policy does not arrive in time, external export stays off for that session. The agent runs as normal. - Failures never change the agent result. A slow or broken destination can drop spans. It never changes what your agent returns.
- No API key leaves ArmorIQ. The
externalchoice sends only the headers that you configure. It does not send your ArmorIQ API key to the destination.
Which choice should I use?
- Use
armoriqif you only need ArmorIQ dashboards. This is the default. - Use
externalwith a Collector if you want to send traces to ArmorIQ and to another tool. The Collector can send the same spans to both. See Deploy an OpenTelemetry Collector. - Use
provideronly if your application must own the export pipeline. You accept the metadata-only limit.
Next steps
Python SDK Observability
Trace policy decisions, model calls, and tool work with the ArmorIQ Python SDK. Set the export, capture ceiling, and per-session switch.
Deploy an OpenTelemetry Collector
Run a Collector that receives ArmorIQ traces, batches them, retries failures, and forwards them over TLS to ArmorIQ and to other tools, without writing a secret in a file.