Set Up OpenTelemetry Tracing
Turn on ArmorIQ tracing for a Python or TypeScript agent with no tracing code, then confirm the first trace in the dashboard.
This guide is for developers who already use the ArmorIQ SDK, or who are adding it to an agent. After you finish, each agent run sends one trace to ArmorIQ. A trace is the record of one run. It holds spans, and each span is one timed step, such as a policy decision, a model call, or a tool call. You write no span code and no flush code.
This guide uses the current releases: Python SDK armoriq-sdk 0.8.17 and TypeScript SDK @armoriq/sdk 0.8.23. Older SDKs use a legacy recorder that is not described here. To move from one, read Migrate from the legacy recorder.
What you need
- An organization-scoped ArmorIQ API key.
- Python 3.10 to 3.13, or Node.js 18.19 or later (or 20.6 or later). The TypeScript LangChain and Strands adapters need Node.js 20 or later.
- The ArmorIQ SDK:
armoriq-sdk0.8.17 for Python, or@armoriq/sdk0.8.23 for TypeScript.
python -m pip install "armoriq-sdk==0.8.17"npm install @armoriq/sdk@0.8.23Use ArmorIQ as you normally do
Tracing is on by default. You do not add observability options, a tracer, or a flush call. This example uses the LangChain adapter. The Strands and Google ADK adapters work the same way. See Framework support.
import os
from armoriq_sdk import ArmorIQClient
from armoriq_sdk.integrations.langchain import ArmorIQLangChain
# Once per process
armoriq = ArmorIQLangChain(
armoriq_client=ArmorIQClient(api_key=os.environ["ARMORIQ_API_KEY"]),
mode="sdk",
)
# Per request
handler = armoriq.for_user("alice@example.com", goal=user_message)
agent_executor.invoke(
{"input": user_message},
config={"callbacks": [handler]},
)import { ArmorIQClient } from '@armoriq/sdk';
import { ArmorIQLangChain } from '@armoriq/sdk/dist/integrations/langchain';
// Once per process
const armoriq = new ArmorIQLangChain({
client: new ArmorIQClient({ apiKey: process.env.ARMORIQ_API_KEY! }),
mode: 'sdk',
});
// Per request
const handler = await armoriq.forUser('alice@example.com', { goal: userMessage });
await agentExecutor.invoke(
{ input: userMessage },
{ callbacks: [handler] },
);That is all. The adapter does this for you:
| What happens | When |
|---|---|
| The SDK creates the trace and its root span | At the start of the agent run |
| The SDK adds spans for the plan, each policy decision, each model call, and each tool call | While the agent runs |
| The SDK ends the trace one time | When the run succeeds, fails, is cancelled, or times out |
| The SDK waits a short, fixed time for spans to send | At the end of the run (up to 3 seconds in Python, 1.5 seconds in TypeScript) |
The SDK makes sure the trace ends one time only, even if the framework sends more than one end event. Telemetry never changes the result of the agent. If sending fails, the agent still returns its normal result.
If you do not use a framework adapter
If you call the session API yourself, you already open and close the session. That same close ends the trace. You still add no span code and no flush code.
from armoriq_sdk import ArmorIQClient, SessionOptions
client = ArmorIQClient(api_key=os.environ["ARMORIQ_API_KEY"], agent_id="support-agent")
with client.start_session(SessionOptions(mode="sdk")) as session:
... # your start_plan, check, and report callsconst session = client.startSession({ mode: 'sdk' });
try {
// your startPlan, check, and report calls
} finally {
await session.close();
}The Python with block ends the trace with status error if the block raises, and ok if it does not. In TypeScript, call close() when the session ends. A session that you never close does not export its root span.
Direct calls to the openai and anthropic packages are traced too, while a session is active. See Framework support.
Check the first trace
- Run the agent once.
- Open Observability in the ArmorIQ dashboard. The page is
/dashboard/observability. - Find your session. Open the trace to see the plan, the policy decisions, and the tool work.
The dashboard polls every 30 seconds, so the trace can appear a short time after the run ends. If nothing appears, use Troubleshooting.
What the SDK does by itself
- It sends to ArmorIQ. By default the SDK sends traces to
POST /v1/traceson your ArmorIQ backend. This is the OTLP route. OTLP (OpenTelemetry Protocol) is the standard way that OpenTelemetry tools send trace data over HTTP. The SDK signs in with your API key. - It asks your organization what to capture. Before it records data, the SDK reads the capture policy for your organization. Your administrators set that policy. See Organization controls. If the policy is not available, the SDK records nothing.
- It uses its own tracer provider. A tracer provider is the object that creates spans and hands them to an exporter. The SDK builds a private one. It does not use or change the provider that your application may already have. To send traces somewhere else, or to use your own provider, see Choose who exports your traces.
Turn tracing off for one session
session = client.start_session(SessionOptions(observability_enabled=False))const session = client.startSession({ observability: { enabled: false } });To turn tracing off for a whole process, set ARMORIQ_OBSERVABILITY=off in the environment. The values 0, false, off, no, and disabled all work. Turning tracing off does not change any policy decision.
Next steps
Observability Overview
Follow agent sessions from policy evaluation through tool execution, model usage, and errors, with OpenTelemetry traces that you control.
TypeScript SDK Observability
Trace policy decisions, model calls, and tool work with the ArmorIQ TypeScript SDK. Set the export, capture ceiling, and per-session switch.