How do I trace a TypeScript AI agent running in a Docker container?
Rius traces a TypeScript agent in a Docker container when you call init() once at startup, set your settings as container environment variables, and call client.shutdown() when the container stops. The TypeScript SDK registers no process-exit hook, so spans still queued when the process ends are lost unless you flush them. Each container start shows up in Rius as its own instance of one agent.
How it works
- One
init()per process. Call it as early as possible in your entry file. A second globalinit()logs a warning and returns the existing client, so do not call it per request. - Integrations attach asynchronously.
init()returns immediately and enables every installed integration it finds. Awaitclient.readybefore your first model call so the integration is in place. It resolves with the names that attached and never rejects. - Spans export in batches. Spans queue in memory and a background timer sends them in batches. The network never sits on your agent’s hot path, and exporter errors never reach your code.
- Nothing flushes for you. The TypeScript SDK installs no exit hook and no signal handlers. An unhandled
SIGTERMor aSIGKILLsends no finalstoppedping, so the instance shows asgone. That is how Rius tells a crash from a clean exit. - Each container start is a new instance. Keep the service name constant across replicas and deploys. Three containers show as three instances of one agent.
Set it up
- Install the SDK in your image. Add the package for each library your agent calls, such as OpenAI. The SDK only patches libraries whose packages are installed. Full options are on Installation and configuration.
npm install @glassflow-ai/rius @opentelemetry/api
npm install @arizeai/openinference-instrumentation-openai-
Pass settings as container environment variables, so the image holds no secret. Most options have a
RIUS_*variable, and an explicit argument in code wins over the variable.RIUS_API_KEY: your API key, sent as an Authorization Bearer header. Without it, span exports are rejected and dropped, and no heartbeat is sent.RIUS_SERVICE_NAME: a constant name for the agent, such asmy-agent.RIUS_SERVICE_VERSION: your release or image tag, so you can tell builds apart.RIUS_ENDPOINT: only if you change the default,https://ingest.eu.console.rius-glassflow.com.
-
Initialize once, wait for the integrations, and shut down on
SIGTERM:
import { init } from '@glassflow-ai/rius'
const client = init({ serviceName: 'my-agent' }) // apiKey comes from RIUS_API_KEY
await client.ready
process.on('SIGTERM', async () => {
await client.shutdown() // drains pending spans and sends the final stopped ping
process.exit(0)
})-
For a short-lived container, such as a batch job or a one-off task, call
await client.flush()before the process exits. It returnsfalsewhen the most recent export failed, for example on a bad API key, so you can log it. Do not callflush()inside request handlers, because it blocks until the export completes. -
Keep the heartbeat on for a long-running container. If you set
RIUS_HEARTBEAT_INTERVAL, keep it at 15 seconds or below, because an instance is markedstaleafter 30 seconds without a ping. Do not setRIUS_SESSION_IDin a server that handles many users, because it applies one session to every span.
Delivery rules, retries and batching variables are covered on Reliability.
What you get
- Spans for the model calls of the integrations you installed, shown in the trace list. Where a call carries a model and token counts, Rius computes a list-price cost estimate in US dollars.
- An instance in
runningorreadyfor each container on the Agents page, grouped under one agent name, with theservice.versionyou set so you can compare builds. - A clean exit marker when
shutdown()runs, andgonewhen a container is killed without it. - The last spans of a run, because the queue drains before the process ends.
The Integrations page lists which TypeScript libraries are supported and how each one attaches.
When something else fits
- If your container runs a serverless-style runtime that freezes the process between calls, flush at the end of every invocation and set
RIUS_HEARTBEAT=false, as Reliability describes. - If your agent calls a library with no TypeScript integration, trace those calls with manual generations instead of relying on auto-instrumentation.
- If the container runs Python, the SDK flushes on a clean interpreter exit, but
docker stopsends SIGTERM, which skips it. Callclient.shutdown()from your own SIGTERM handler there too.