OpenInference is an open standard for AI observability developed by Arize AI.
OpenInference defines semantic conventions such as llm.model_name and llm.token_count.*, which differ from the gen_ai.* attributes that
AI Observability natively understands. Supported instrumentors can also emit OpenTelemetry GenAI semantic-convention attributes alongside OpenInference attributes.
Learn how to instrument your AI application with OpenInference, enable native gen_ai.* attributes where available, and normalize remaining OpenInference attributes with an OTel Collector.
This getting started guide is for:
By following this guide, you'll learn:
gen_ai.* by using native GenAI semantic-convention support or an OTel Collector.
AI Observability.To follow this guide, you need:
A running AI application, or use one of the OpenInference sample apps:
Dynatrace SaaS with a Dynatrace Platform Subscription (DPS) license that has Traces powered by Grail enabled.
OTLP ingestion enabled, see OpenTelemetry and Dynatrace.
A platform token with the openpipeline:traces:ingest scope, or a Classic access token with the Ingest OpenTelemetry traces (openTelemetryTrace.ingest) scope.
Any credentials required by your selected sample.
For the OTel Collector option: Docker, and an OTel Collector distribution that bundles the genainormalizer processor. Either of the following works:
Choose the sample that matches your provider or framework. Each README contains the provider-specific prerequisites, instrumentation, and processing configuration.
| Technology | OpenInference instrumentor | Data preparation in the sample |
|---|---|---|
| Native | |
| OTel Collector normalization and provider-specific message transforms | |
| OTel Collector normalization | |
| OTel Collector normalization, with a provider-specific output-message transform | |
| Native | |
| OTel Collector normalization | |
| OTel Collector normalization | |
| OTel Collector normalization | |
| OTel Collector normalization |
It's helpful to have some basic knowledge of:
OpenInference captures and transmits AI model or agentic-workflow KPIs as OpenTelemetry spans. Its instrumentors emit OpenInference attributes and can, depending on the instrumentor, also emit OpenTelemetry gen_ai.* attributes.
Dynatrace AI Observability requires gen_ai.* attributes. Enable native GenAI semantic-convention emission when the instrumentor supports it. Otherwise, normalize the OpenInference attributes with an OTel Collector.
For more information, see Use OpenTelemetry GenAI semantic conventions when available and Normalize your OpenInference attributes.
This section describes how to start ingesting OpenInference attributes into Dynatrace, which can then be normalized into gen_ai.* attributes.
To authenticate, create one of the following:
Access Tokens.Required scopes:
openpipeline:traces:ingestopenTelemetryTrace.ingest)For more information, see Tokens and permissions.
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.comDT_API_TOKEN=dt0XXX.<your-token-value>OPENAI_API_KEY=<your-openai-api-key>OPENAI_API_BASE=https://your-endpoint.openai.azure.com/MODEL=gpt-5.5OPENAI_API_VERSION=2024-07-01-previewOPENINFERENCE_ENABLE_GENAI_SEMCONV=true
Set DT_API_TOKEN to your platform token or Classic access token.
DT_ENDPOINT is your base environment URL, not the /api/v2/otlp path.
For more information, see Dynatrace OTLP endpoints.
pip install -r requirements.txt
The key packages are openinference-instrumentation-openai and opentelemetry-sdk.
Use the OpenInference auto-instrumentation for OpenAI. The instrumentation patches the OpenAI client and records spans with OpenInference semantic conventions automatically. Each example's README identifies its instrumentor package, dependencies, application entry point, and OTel Collector configuration. Follow that README because providers and frameworks don't all emit the same attributes or use the same configuration filenames.
from openinference.instrumentation.openai import OpenAIInstrumentorfrom opentelemetry.sdk.resources import Resource, SERVICE_NAMEfrom opentelemetry.sdk.trace import TracerProviderfrom opentelemetry.sdk.trace.export import BatchSpanProcessorfrom opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporterimport openaiimport os# Configure the tracer providerservice_name = os.getenv("OTEL_SERVICE_NAME", "openinferenceapp")tracer_provider = TracerProvider(resource=Resource.create({SERVICE_NAME: service_name,}))# Configure the OTLP exporter with the appropriate endpoint and credentials (see the option you've chosen below)exporter = OTLPSpanExporter(endpoint=os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"],headers={"Authorization": f"Bearer {os.environ['DT_API_TOKEN']}"},)tracer_provider.add_span_processor(BatchSpanProcessor(exporter))# Instrument the OpenAI clientOpenAIInstrumentor().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)
The required scope is openpipeline:traces:ingest.
OpenInference Python instrumentors that use TraceConfig capture content by default. Prompts and completions can contain sensitive data, so review the content that your application sends before exporting spans to Dynatrace.
Use TraceConfig to suppress content programmatically with hide_inputs, hide_outputs, hide_input_messages, and hide_output_messages. You can set the equivalent environment variables to true: OPENINFERENCE_HIDE_INPUTS, OPENINFERENCE_HIDE_OUTPUTS, OPENINFERENCE_HIDE_INPUT_MESSAGES, and OPENINFERENCE_HIDE_OUTPUT_MESSAGES.
If you intentionally want message content sent to Dynatrace, ensure that the applicable controls are false or unset. These controls can't restore data that the instrumentation didn't capture.
Set the following environment variable when using an instrumentor that supports OpenTelemetry GenAI semantic conventions:
OPENINFERENCE_ENABLE_GENAI_SEMCONV=true
OPENINFERENCE_ENABLE_GENAI_SEMCONV emits gen_ai.* attributes alongside OpenInference attributes. The OpenAI and Cohere examples use this setting. Other instrumentors might not emit complete gen_ai.* coverage, so coverage varies by provider and framework. For those instrumentors, normalize attributes to gen_ai.* with the OTel Collector genainormalizer and transform processors, as described below.
If your instrumentor doesn't emit every attribute that Dynatrace needs as gen_ai.*, normalize the remaining OpenInference attributes with an OTel Collector that includes the genainormalizer processor.
genainormalizer processor The OTel Collector intercepts spans and normalizes OpenInference attributes to gen_ai.* with the genainormalizer processor before forwarding them to Dynatrace.
No Dynatrace configuration is needed, and you can use any OTel Collector distribution that bundles the genainormalizer processor, for example:
ghcr.io/dynatrace/dynatrace-otel-collector/dynatrace-otel-collector:0.53.1ghcr.io/dynatrace/dynatrace-bindplane-otel-collector:1.1.2The OTel Collector:
4318 for incoming OTLP/HTTP spans from the app.
The app only sends spans to http://localhost:4318 and doesn't need Dynatrace credentials.genainormalizer processor (source: openinference, remove_originals: true) to map OpenInference attributes to gen_ai.* and reconstruct message history.
When the instrumentor emits sufficient indexed per-message attributes, the genainormalizer processor reconstructs the full gen_ai.input.messages / gen_ai.output.messages.transform/response_model processor to mirror gen_ai.request.model to gen_ai.response.model.DT_ENDPOINT and DT_API_TOKEN. It forwards processed spans to $DT_ENDPOINT/api/v2/otlp authenticated with your platform token or Classic access token.The following steps describe how to normalize attributes with the OTel Collector.
Run your chosen OTel Collector image with the configuration file supplied by your sample. The OpenAI sample uses otel-collector-config.yaml. The Amazon Bedrock and Cohere samples use otelcol-config.yaml. The remaining listed samples use otel-collector-config.yaml.
These examples use the Dynatrace Collector distro.
To use the Dynatrace Bindplane OTel Collector instead, set COLLECTOR_IMAGE to ghcr.io/dynatrace/dynatrace-bindplane-otel-collector:1.1.2.
macOS/Linux:
source .envCOLLECTOR_IMAGE=ghcr.io/dynatrace/dynatrace-otel-collector/dynatrace-otel-collector:0.53.1docker run -d \--name otel-collector \-p 4318:4318 \-v $(pwd)/otel-collector-config.yaml:/etc/otel/config.yaml:ro \-e DT_ENDPOINT=$DT_ENDPOINT \-e DT_API_TOKEN=$DT_API_TOKEN \$COLLECTOR_IMAGE \--config=/etc/otel/config.yaml
Windows CMD:
set DT_ENDPOINT=https://abc12345.live.dynatrace.comset DT_API_TOKEN=dt0XXX.<your-token-value>set COLLECTOR_IMAGE=ghcr.io/dynatrace/dynatrace-otel-collector/dynatrace-otel-collector:0.53.1docker run -d ^--name otel-collector ^-p 4318:4318 ^-v %cd%/otel-collector-config.yaml:/etc/otel/config.yaml:ro ^-e DT_ENDPOINT=%DT_ENDPOINT% ^-e DT_API_TOKEN=%DT_API_TOKEN% ^%COLLECTOR_IMAGE% ^--config=/etc/otel/config.yaml
Point the app to the local OTel Collector.
source .envOTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318OTEL_EXPORTER_OTLP_HEADERS=""python3 app.py
Useful commands:
# Tail OTel Collector logsdocker logs -f otel-collector# Stop the OTel Collectordocker stop otel-collector && docker rm otel-collector
The table below summarizes the mappings in the sample OTel Collector configurations. The genainormalizer processor performs the core mappings. The sample transform processors add optional fields, as described in Known limitations.
| Source attribute | gen_ai.* attribute | Notes |
|---|---|---|
|
|
|
|
| LLM spans |
|
| Embedding spans |
|
| Reranker spans |
|
| Mirrored; OpenInference has no separate response model field |
|
| If |
|
|
|
— |
| Set to |
— |
| Hardcoded |
|
| |
|
| |
|
|
Guard prevents false positives (Azure emits |
|
| |
|
| |
|
| |
|
| Renamed directly; source attribute removed |
|
| Only when |
|
| |
|
| |
|
| |
|
| The Anthropic sample OTel Collector renames this unnamespaced attribute for queryability |
|
| |
|
| Reconstructed into full message history JSON including roles, content, and tool calls when sufficient indexed attributes are available. Source attributes removed. |
|
| Reconstructed into full message history JSON including roles, content, and tool calls when sufficient indexed attributes are available. Source attributes removed. |
OpenInference supports GUARDRAIL as a span kind but doesn't define a standardized rich guardrail attribute set. The genainormalizer processor copies this value to gen_ai.operation.name unchanged. The Anthropic sample OTel Collector renames an emitted validator_name source attribute to gen_ai.guardrail.name. Provider- or framework-specific guardrail data can be unavailable, and downstream transforms can't reconstruct data that instrumentation discarded.
Attribute coverage and message reconstruction depend on the instrumentor and the attributes it emits. The genainormalizer processor maps the supported OpenInference attributes it receives, but some optional fields can require custom transforms:
gen_ai.request.temperature, gen_ai.request.top_p, gen_ai.request.max_tokensgen_ai.response.finish_reasonsgen_ai.prompt_caching and gen_ai.cache.typegen_ai.system (however, it does set gen_ai.provider.name)To add these fields, extend the sample's OTel Collector configuration by adding statements to its transform processor. Use the filename supplied by that sample, such as otel-collector-config.yaml for OpenAI or otelcol-config.yaml for Amazon Bedrock. These mappings are candidates for upstream contribution to the genainormalizer processor.
Transforms can map data that instrumentation emits, but can't reconstruct source-specific data that an instrumentor doesn't emit or has discarded.
Once your spans contain the required gen_ai.* attributes, you can observe them in Dynatrace.
Ctrl+K and search for AI Observability.gen_ai.* attributes.You can also view spans in Distributed Tracing.
Now that you've set up your AI app to send observability data to Dynatrace, you can:
AI Observability to visualize your AI workloads.