Observability

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-sdk 0.8.17 for Python, or @armoriq/sdk 0.8.23 for TypeScript.
python -m pip install "armoriq-sdk==0.8.17"
npm install @armoriq/sdk@0.8.23

Use 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 happensWhen
The SDK creates the trace and its root spanAt the start of the agent run
The SDK adds spans for the plan, each policy decision, each model call, and each tool callWhile the agent runs
The SDK ends the trace one timeWhen the run succeeds, fails, is cancelled, or times out
The SDK waits a short, fixed time for spans to sendAt 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 calls
const 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

  1. Run the agent once.
  2. Open Observability in the ArmorIQ dashboard. The page is /dashboard/observability.
  3. 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/traces on 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

On this page