AI agent instrumentation

📘

Private preview feature (Invite only)

This feature is enabled per tenant by Observe by Snowflake and is not generally available. To participate, contact your Observe by Snowflake representative. You may access and use this preview feature solely for internal evaluation purposes. Previews are provided as-is. Your use of this preview is subject to the Snowflake Preview Terms located at https://www.snowflake.com/en/legal.

Send OpenTelemetry GenAI traces and metrics from your agent to Observe by Snowflake. When export is working, a conversation shows up under AI Agents, filtered by the service name you set here.

The SDK writes one span per model call, embedding, tool call, retrieval, agent run, and workflow run, plus duration and token histograms. It writes through the standard OpenTelemetry API, so the data goes wherever your app's exporter sends it: Observe by Snowflake, or any other OTLP backend.

The SDK is open source, with one repository per language:

Neither SDK registers providers, opens network connections, or starts background work on its own; your OpenTelemetry setup does that.

Step 1. Point OpenTelemetry to Observe by Snowflake

Skip this step when the app already exports OpenTelemetry. Add the GenAI instrumentation to that setup in step 3.

When the app doesn't export yet, set these variables. Replace the <customer_id> and <ingest_token> placeholders with your real values.

OTEL_EXPORTER_OTLP_ENDPOINT=https://<customer_id>.collect.observeinc.com/v2/otel
OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer <ingest_token>
OTEL_SERVICE_NAME=my-agent

Step 2. Install the SDK

Install the SDK for JavaScript or Python.

Install the SDK for JavaScript

JavaScript requires Node.js 22 or later.

pnpm add @snowflake/observe-otel-genai @opentelemetry/[email protected] @opentelemetry/[email protected] @opentelemetry/[email protected]

Keep the OpenTelemetry versions as shown. Without them, the install picks up OpenTelemetry's next major release, which the SDK does not support yet.

This command installs the following packages into the current project and writes them into package.json and the lockfile:

PackageDescription
@snowflake/observe-otel-genaiThe SDK itself. It emits GenAI spans (agent, chat, tool, and so on) with the gen_ai.* attributes that AI Agents reads. It does not start OpenTelemetry or send data anywhere on its own.
@opentelemetry/apiThe tracing and metrics interface the SDK calls into.
@opentelemetry/sdk-nodeThe Node SDK that turns tracing on: it registers the tracer and meter providers and starts exporting. If the app already sets up OpenTelemetry, skip this package and use that setup in step 3.
@opentelemetry/instrumentationThe base library the framework instrumentations in step 3 plug into. By itself it records nothing.

Install the SDK for Python

Python requires Python 3.11 or later.

The Observe packages replace the upstream OpenTelemetry GenAI packages and install to the same paths, so the two cannot share an environment. Uninstall the upstream packages first:

pip uninstall -y opentelemetry-util-genai
pip freeze | grep opentelemetry-instrumentation-genai | xargs pip uninstall -y

Then install the package for your framework from the table in step 3. For example, for the OpenAI SDK:

pip install observe-instrumentation-genai-openai

Each framework package pulls in observe-util-genai, the shared layer they all use. Install only the framework packages you use. Do not run opentelemetry-bootstrap -a install: it can install the upstream packages again.

If the app does not set up OpenTelemetry yet, also install the OpenTelemetry SDK and the OTLP/HTTP exporter, so that opentelemetry-instrument in step 3 can export the data:

pip install opentelemetry-distro opentelemetry-exporter-otlp-proto-http

Skip this when the app already sets up OpenTelemetry in code.

Step 3. Turn instrumentation on before the agent runs

Load the instrumentation once, at process startup, before the agent framework is imported. A framework that is imported first is not patched.

Find your framework

Each framework links to its full setup guide in the JavaScript and Python repositories.

FrameworkJavaScriptPython
OpenAI SDK
JavaScript · Python
OpenAIInstrumentation. Also covers OpenAI-compatible endpoints.observe-instrumentation-genai-openai. Also covers OpenAI-compatible endpoints such as Snowflake Cortex, Azure OpenAI, Gemini, xAI, DeepSeek, Groq, and Mistral.
OpenAI Agents SDK
JavaScript · Python
OpenAIAgentsInstrumentation. Register OpenAIInstrumentation too, or model calls are missing.observe-instrumentation-genai-openai-agents records workflow, agent, and tool spans. Add observe-instrumentation-genai-openai for chat spans and token counts. Other model clients, such as LiteLLM, are not recorded.
LangChain/
LangGraph
JavaScript · Python
LangChainInstrumentation. Under ESM, also call manuallyInstrument.observe-instrumentation-genai-langchain. LangGraph node context needs LangGraph 0.3.18 or later. Do not also turn on the OpenAI instrumentation for ChatOpenAI, or each call is counted twice.
Claude Agent SDK
JavaScript · Python
ClaudeAgentSdkInstrumentation. Needs the ESM loader hook. Set includePartialMessages: true for exact token counts.observe-instrumentation-genai-claude-agent-sdk. Call instrument() before from claude_agent_sdk import query. Set include_partial_messages=True for exact token counts.
Vercel AI SDK
JavaScript
VercelAiSdkInstrumentation, or registerTelemetry(genaiTelemetryIntegration(client)). AI SDK v7 only.—
Anthropic SDK
JavaScript
No auto-instrumentation. Wrap the client with wrapAnthropic.—
Anything else
JavaScript · Python
Record calls yourself with Client (startGeneration, invokeAgent, tools, workflows).Install observe-util-genai and record calls yourself with TelemetryHandler (inference, invoke_local_agent, tool, workflow, and so on).

Pick a content capture mode

By default, both SDKs record the model name, token counts, timing, and errors. Prompt text, completions, and tool payloads stay off the span, so a conversation in AI Agents has no prompt to read.

Turn capture on when you want those prompts. This sends conversation text to Observe by Snowflake, and it often holds personal data.

JavaScript sets the mode on the Client with contentCaptureMode:

ModeWhat lands on the span
metadata_only (default)No content.
no_tool_contentPrompts and completions. Tool arguments and tool results are omitted.
fullPrompts, completions, tool arguments, and tool results. Use this for tool-call evals.
allow_listNo content, and only the attributes on a fixed, reviewed list.

Python sets the mode with the OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT environment variable:

ValueWhat is recorded
NO_CONTENT (default)No content.
SPAN_ONLYPrompts and completions on the span. AI Agents reads the span.
EVENT_ONLYPrompts and completions as log events only.
SPAN_AND_EVENTPrompts and completions on the span and as log events.
ALLOW_LISTNo content, and only the attributes on a fixed, reviewed list.

Turn on instrumentation for JavaScript

Put startup in a preload file and launch the app with it:

node --import ./preload.mjs app.mjs

preload.mjs starts the Node SDK, creates a Client with your content capture mode, then registers the instrumentation for your framework. Create the Client after the Node SDK starts, or it records spans but no metrics. This example instruments the OpenAI SDK:

import { register } from "node:module";
import { NodeSDK } from "@opentelemetry/sdk-node";
import { registerInstrumentations } from "@opentelemetry/instrumentation";
import { Client } from "@snowflake/observe-otel-genai";
import { OpenAIInstrumentation } from "@snowflake/observe-otel-genai/openai/instrumentation";

// Lets the instrumentation patch ES modules. Skip it for LangChain, which uses manuallyInstrument instead.
register("@opentelemetry/instrumentation/hook.mjs", import.meta.url);

new NodeSDK().start();

const client = new Client({ contentCaptureMode: "no_tool_content" });
registerInstrumentations({
  instrumentations: [new OpenAIInstrumentation({ client })],
});

For another framework, follow its link in the table above.

For a framework the SDK does not cover, record each call yourself:

import { Client } from "@snowflake/observe-otel-genai";

const client = new Client({ contentCaptureMode: "no_tool_content" });

const generation = client.startGeneration({
  model: { provider: "openai", name: "gpt-4o" },
  agentName: "my-agent",
});
// Call the model, then record the result with generation.setResult(...) and generation.end().
// Agent, tool, and workflow spans use client.invokeAgent, client.startToolExecution,
// and client.invokeWorkflow the same way.

Turn on instrumentation for Python

Set the content capture mode first:

export OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=SPAN_ONLY

Then turn the instrumentation on in one of two ways.

Without code changes. Run the app under opentelemetry-instrument. It reads the variables from step 1, sets up OpenTelemetry, and turns on every installed instrumentation before your code runs:

opentelemetry-instrument python app.py

In code. Call the package's instrumentor at startup, before the framework is imported. The app's own code then sets up OpenTelemetry, as in each package's manual example:

from observeinc.instrumentation.genai.openai import OpenAIInstrumentor

OpenAIInstrumentor().instrument()

from openai import OpenAI

The Claude Agent SDK is picky about order: call ClaudeAgentSDKInstrumentor().instrument() first, and only then from claude_agent_sdk import query.

For a framework the SDK does not cover, record each call yourself:

from observeinc.util.genai.handler import TelemetryHandler

handler = TelemetryHandler()

with handler.inference("openai", request_model="gpt-4o") as invocation:
    invocation.input_messages = [...]
    # Call the model, then record the result.
    invocation.output_messages = [...]
# Agent, tool, and workflow spans use handler.invoke_local_agent, handler.tool,
# and handler.workflow the same way.

Step 4. Confirm a conversation arrived

Perform the following tasks to confirm that your conversations arrive in Observe by Snowflake:

  1. Run the agent once. Ask it something that calls a tool, if you instrumented tools.
  2. In Observe by Snowflake, click AI Agents.
  3. In the filter bar, set service_name to the OTEL_SERVICE_NAME from step 1.
  4. Open the conversation. A model span should show token counts. With content capture on, the same span shows the prompt.

If the list is empty, check the endpoint, the bearer token, and that step 3 ran before the framework import. A process that imports LangChain and then starts the SDK exports ordinary spans and no GenAI attributes.

Frequently asked questions

I am seeing dropped spans or missing attributes

This may occur when there are too many prompts / completions in a given span. Increase the default attribute limit (128) through the environment variable OTEL_ATTRIBUTE_COUNT_LIMIT. Note however, that this can still result in dropped spans or attributes if the limit is exceeded, or the Observe by Snowflake ingest payload limit is breached.

How is token usage for traces and conversations calculated?

Observe by Snowflake calculates token usage in model calling spans only. Token usage reported at the agent calling level is not considered, as some vendors double count it against the span level usage.




Did this page help you?