Try it free

Get started with OpenInference and AI Observability

  • Latest Dynatrace
  • Getting started guide
  • 5-min read
  • Published Jun 01, 2026

OpenInference is an open standard for AI observability developed by Arize AI. It defines its own semantic conventions (llm.model_name, llm.token_count.*, and others) which differ from the gen_ai.* attributes that Dynatrace AI Observability natively understands.

This guide shows you how to instrument your AI application with OpenInference, and then normalize the OpenInference attributes to the gen_ai.* format using one of two approaches: An OTel Collector with a transform processor, or Dynatrace OpenPipeline.

Who is this for?

This getting started guide is for:

  • AI engineering teams building agent- and LLM-powered applications and services.
  • Site Reliability Engineers responsible for monitoring AI workloads in production.
  • Platform engineers integrating OpenTelemetry (OTel) data from AI apps into Dynatrace.

What will you learn?

By following this guide, you'll learn:

  • How to instrument an AI application with OpenInference.
  • How to normalize OpenInference attributes to gen_ai.* using an OTel Collector or Dynatrace OpenPipeline.
  • How to view model name, token usage, and message content in the Dynatrace AI Observability app.

Before you begin

Prerequisites

To follow this guide, you need:

  • A running AI application, or use the sample app.
  • Dynatrace SaaS with a Dynatrace Platform Subscription (DPS) license that has Traces powered by Grail enabled.
  • OTLP ingestion enabled, see OpenTelemetry and Dynatrace.
  • A Dynatrace API token with the openTelemetryTrace.ingest scope, see Dynatrace API - Tokens and authentication.
  • An OpenAI-compatible API key and endpoint.
  • Docker (required for the OTel Collector option only).

Prior knowledge

It's helpful to have some basic knowledge of:

  • Python.
  • OTel concepts like SDKs, spans, exporters, and Collectors.
  • Dynatrace permissions and data ingestion.

About OpenInference and AI observability

OpenInference captures and transmits AI model or agent KPIs as OpenTelemetry spans but uses its own semantic conventions rather than the gen_ai.* standard. Because Dynatrace AI Observability requires gen_ai.* attributes, you need an intermediate normalization step.

Two equivalent approaches are available: the OTel Collector, or OpenPipeline, as described in the table below. Both approaches produce identical results in AI Observability AI Observability.

OTel CollectorOpenPipeline

Where transforms run

In the Collector process, locally

Server-side, in your Dynatrace tenant

Requires Docker?

Yes

No

Requires Dynatrace configuration?

No

Yes; one-time deployment

Good for

Full pipeline control; no Dynatrace configuration needed

Simpler operations; no Collector to manage

The table below shows the gen_ai.* attributes produced after normalization:

Source attributegen_ai.* attributeNotes

openinference.span.kind

gen_ai.operation.kind

  • CHAIN becomes workflow
  • TOOL becomes tool
  • AGENT becomes agent
  • RETRIEVER becomes retrieval
  • GUARDRAIL becomes guardrail
  • All other values become task

llm.model_name

gen_ai.request.model

LLM spans

embedding.model_name

gen_ai.request.model

Embedding spans

reranker.model_name

gen_ai.request.model

Reranker spans

gen_ai.request.model

gen_ai.response.model

Mirrored; OpenInference has no separate response model field

llm.provider (or llm.system)

gen_ai.provider.name

llm.system is used only when llm.provider is absent

—

gen_ai.system

Set to azure.ai.openai when provider is azure

—

gen_ai.operation.name

Hardcoded chat for LLM spans, embeddings for embedding spans

llm.token_count.prompt

gen_ai.usage.input_tokens

llm.token_count.completion

gen_ai.usage.output_tokens

llm.token_count.prompt_details.cache_read

gen_ai.prompt_caching

  • Set to read when the value is greater than 0.
  • Set towrite when only cache_write is greater than 0.

Guard prevents false positives (Azure emits 0 on every span).

llm.temperature

gen_ai.request.temperature

llm.max_tokens

gen_ai.request.max_tokens

llm.top_p

gen_ai.request.top_p

llm.finish_reason

gen_ai.response.finish_reasons

Renamed directly; source attribute removed

llm.input_messages.0.message.content

gen_ai.system_instructions

Only when llm.input_messages.0.message.role == "system"

agent.name

gen_ai.agent.name

tool.name

gen_ai.tool.name

tool.description

gen_ai.tool.description

validator_name

gen_ai.guardrail.name

validator_name has no OTel namespace; renamed for queryability

embedding.vector_length

gen_ai.embeddings.dimension.count

input.value

gen_ai.input.messages

Interim fallback; source removed

output.value

gen_ai.output.messages

Interim fallback; source removed

—

ai.observability.source

Hardcoded openinference on all spans

Get started with OpenInference and Dynatrace

This section describes how to start ingesting OpenInference attributes into Dynatrace, which can then be normalized into gen_ai.* attributes.

1. Create a Dynatrace access token

  1. In Dynatrace, select Ctrl+K and search for Access tokens.
  2. Select Generate new token.
  3. Give the token a name and add the openTelemetryTrace.ingest scope.
  4. Select Generate token and copy the token value.

For more information, see Access tokens and permissions.

2. Set environment variables

The sample app and scripts read credentials from environment variables. Create a .env file in your project directory:

DT_ENDPOINT=https://<your-environment-id>.live.dynatrace.com
DT_API_TOKEN=dt0c01.<token-value>
OPENAI_API_KEY=<your-openai-api-key>
OPENAI_API_BASE=https://your-endpoint.openai.azure.com/
MODEL=gpt-5.5
OPENAI_API_VERSION=2024-07-01-preview

DT_ENDPOINT is your base environment URL, not the /api/v2/otlp path. For more information, see Dynatrace OTLP endpoints.

3. Install dependencies

pip install -r requirements.txt

The key packages are openinference-instrumentation-openai and opentelemetry-sdk.

4. Instrument your application

Use the OpenInference auto-instrumentation for OpenAI. The instrumentation patches the OpenAI client and records spans with OpenInference semantic conventions automatically.

from openinference.instrumentation.openai import OpenAIInstrumentor
from opentelemetry.sdk.resources import Resource, SERVICE_NAME
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
import openai
import os
# Configure the tracer provider
service_name = os.getenv("OTEL_SERVICE_NAME", "openinferenceapp")
tracer_provider = TracerProvider(
resource=Resource.create(
{
SERVICE_NAME: service_name,
}
)
)
# Configure the OTLP exporter—endpoint and auth depend on your chosen option (see below)
exporter = OTLPSpanExporter(
endpoint=os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"],
headers={"Authorization": f"Api-Token {os.environ['DT_API_TOKEN']}"},
)
tracer_provider.add_span_processor(BatchSpanProcessor(exporter))
# Instrument the OpenAI client
OpenAIInstrumentor().instrument(tracer_provider=tracer_provider)
client = openai.OpenAI(api_key=os.environ["OPENAI_API_KEY"])
response = client.chat.completions.create(
model=os.environ.get("MODEL", "gpt-5.5"),
messages=[{"role": "user", "content": "Write a haiku about observability."}],
)
print(response.choices[0].message.content)

Normalize your OpenInference attributes

Once you've set up your app to export data to Dynatrace, you can normalize your attributes to the gen_ai.* format in one of two ways, see the sections below.

  • OTel Collector with transform processor
  • Dynatrace OpenPipeline

OTel Collector with transform processor

The OTel Collector intercepts spans and applies all attribute mappings before forwarding to Dynatrace. You don't need to configure Dynatrace:

  • The Collector authenticates with Dynatrace using DT_ENDPOINT and DT_API_TOKEN.
  • The app only sends spans to http://localhost:4318 and doesn't need Dynatrace credentials.

To use the OTel Collector:

  1. Start the OTel Collector.

    Use the Dynatrace OTel Collector image with the otel-collector-config.yaml from the sample repository:

    • macOS

      source .env
      docker run -d \
      --name otel-collector \
      -p 4318:4318 \
      -v $(pwd)/otel-collector-config.yaml:/etc/otelcol/otel-collector-config.yaml:ro \
      -e DT_ENDPOINT=$DT_ENDPOINT \
      -e DT_API_TOKEN=$DT_API_TOKEN \
      ghcr.io/dynatrace/dynatrace-otel-collector/dynatrace-otel-collector:0.48.0 \
      --config=/etc/otelcol/otel-collector-config.yaml
    • Windows CMD

      set DT_ENDPOINT=https://abc12345.live.dynatrace.com
      set DT_API_TOKEN=dt0c01.*****
      docker run -d ^
      --name otel-collector ^
      -p 4318:4318 ^
      -v %cd%/otel-collector-config.yaml:/etc/otelcol/otel-collector-config.yaml:ro ^
      -e DT_ENDPOINT=%DT_ENDPOINT% ^
      -e DT_API_TOKEN=%DT_API_TOKEN% ^
      ghcr.io/dynatrace/dynatrace-otel-collector/dynatrace-otel-collector:0.48.0 ^
      --config=/etc/otelcol/otel-collector-config.yaml

    The Collector:

    1. Listens on port 4318 for incoming OTLP/HTTP spans from the app.

    2. Applies the transform/openinference processor to rename and map attributes.

    3. Forwards processed spans to $DT_ENDPOINT/api/v2/otlp authenticated with the API token.

  2. Run the app

    1. Point the app to the local Collector. The Collector handles the Dynatrace authentication.

      source .env
      OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
      OTEL_EXPORTER_OTLP_HEADERS=""
      python3 app.py
    2. To tail the Collector logs:

      docker logs -f otel-collector
    3. To stop the Collector:

      docker stop otel-collector && docker rm otel-collector

Dynatrace OpenPipeline

OpenPipeline is a server-side processing pipeline in Dynatrace that applies the same attribute mappings before Dynatrace stores them. The app sends spans directly to Dynatrace, no Collector needed.

1. Deploy the OpenPipeline configuration

This is a one-time setup per environment.

  1. In Dynatrace, select Ctrl+K and search for OpenPipeline.

  2. Select Spans.

  3. Select Add pipeline and name it openinference-ai-spans.

  4. Add processors that match the definitions in openpipeline-openinference.yaml from the sample repository.

  5. Go to the Routing tab and add an entry.

    • Matcher: isNotNull(openinference.span.kind)
    • Pipeline: openinference-ai-spans

    Use isNotNull(openinference.span.kind) as the routing matcher. OpenPipeline routing evaluates span attributes only, not OTLP scope-level fields, so otel.scope.name is not accessible at routing time. The openinference.span.kind attribute is set on every span by all OpenInference instrumentors.

2. Run the app

Point the app directly to the Dynatrace OTLP endpoint. OpenPipeline intercepts and transforms spans before Dynatrace stores them.

source .env
OTEL_EXPORTER_OTLP_ENDPOINT=$DT_ENDPOINT/api/v2/otlp \
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Api-Token $DT_API_TOKEN" \
python3 app.py

Observe in Dynatrace

Once you've normalized the OpenInference attributes to the gen_ai.* format, you can observe your spans in Dynatrace.

  1. In Dynatrace, select Ctrl+K and search for AI Observability.
  2. Your request appears in the Explorer tab as a span with the model name, token usage, and message content.
  3. Open a span to inspect the full conversation and gen_ai.* attributes.

You can also view spans in Distributed Tracing Distributed Tracing.

Congratulations!

Now that you've set up your AI app to send observability data to Dynatrace, you can:

  • Explore Distributed Tracing Distributed Tracing and the AI Observability app to visualize your AI workloads.
  • Check out the sample applications for more examples.
  • Point the OTLP endpoint to your Collector or ActiveGate endpoint for more advanced setups.
  • For troubleshooting, see the openinference examples README.
Related tags
AI Observability