Exporting OTel Traces to Fiddler
Overview
This guide covers the client-side export scenario: your application has already generated OpenTelemetry traces, you manage their storage and processing, and you need to ship them to Fiddler. You are responsible for:- Attribute mapping — translating your OTel span attributes to Fiddler’s schema
- Protobuf serialization — building
ResourceSpans → ScopeSpans → Spanstructures - Export — POSTing the compressed payload to Fiddler’s
v1/tracesendpoint
When to use this approachUse client-side export when you have:
- Traces stored in a data warehouse, JSONL files, or a logging pipeline that you want to replay into Fiddler
- A custom export pipeline that processes spans before sending (e.g., filtering, enrichment, or ID regeneration)
- Batch backfill of historical trace data
Prerequisites
- A Fiddler account with a GenAI application created — you will need its Application UUID
- A valid Fiddler API token (from Settings > Credentials)
- Python packages:
The v1/traces Endpoint
Send traces as a gzip-compressed protobufExportTraceServiceRequest payload:
| Property | Value |
|---|---|
| URL | https://<your-fiddler-instance>/v1/traces |
| Method | POST |
| Content-Type | application/x-protobuf |
| Content-Encoding | gzip |
| Authorization | Bearer <your-api-token> |
| fiddler-application-id | <your-application-uuid> |
Protobuf Structure
Fiddler expects the standard OTLP hierarchy:application.id must be set at the Resource level (not on individual spans):
AnyValue Typing
EachKeyValue in the protobuf structure carries its value in an AnyValue message. AnyValue is a oneof — exactly one typed field must be set. Using the correct field ensures Fiddler classifies the data with the right type (e.g., numeric fields enable aggregation, charting, and alerting).
| Python type | AnyValue field | Fiddler storage type | Example |
|---|---|---|---|
str | string_value | String | AnyValue(string_value="gpt-4o") |
int | int_value | Numeric (stored as float) | AnyValue(int_value=150) |
float | double_value | Numeric (stored as float) | AnyValue(double_value=0.95) |
bool | bool_value | String | AnyValue(bool_value=True) |
Helper: Python value to AnyValue
Helper: Python value to AnyValue
AnyValue fields), see Span and Resource Attributes — Quick Overview.
Attribute Mapping Reference
Span Structure Fields
The following fields control the span’s structural properties and are not sent as span attributes. Map them to the corresponding protobufSpan fields instead:
| Your field | Protobuf Span field |
|---|---|
trace_id | trace_id (bytes, 16 bytes / 32-char hex) |
span_id | span_id (bytes, 8 bytes / 16-char hex) |
parent_span_id | parent_span_id (bytes, same format) |
span_name / name | name |
span_kind | kind (SpanKind enum) |
status_code | status.code (StatusCode enum) |
start_time | start_time_unix_nano |
end_time | end_time_unix_nano |
Required Span Attributes
Every span sent to Fiddler must include this attribute:| Attribute | Description |
|---|---|
fiddler.span.type | Span type: llm, tool, chain, or agent |
application.id is required at the Resource level (see above).
Span Type: Deriving from gen_ai.operation.name
If your spans follow the GenAI semantic conventions and carrygen_ai.operation.name, map it to fiddler.span.type as follows:
gen_ai.operation.name | fiddler.span.type |
|---|---|
chat | llm |
execute_tool | tool |
invoke_agent | chain |
| (any other value or absent) | chain (default) |
LLM Semantic Convention Mappings
| Your OTel attribute | Fiddler attribute | Notes |
|---|---|---|
gen_ai.input.messages | gen_ai.llm.input.user + gen_ai.llm.context | See message parsing below |
gen_ai.output.messages | gen_ai.llm.output | |
gen_ai.system_instructions | gen_ai.llm.input.system | |
gen_ai.response.model | gen_ai.request.model | Fiddler normalises to the request-side attribute |
gen_ai.usage.input_tokens | gen_ai.usage.input_tokens | Pass through unchanged |
gen_ai.usage.output_tokens | gen_ai.usage.output_tokens | Pass through unchanged |
gen_ai.usage.total_tokens | gen_ai.usage.total_tokens | Pass through unchanged |
gen_ai.system | gen_ai.system | LLM provider identifier (e.g. openai) |
gen_ai.request.model | gen_ai.request.model | Pass through unchanged |
Tool Semantic Convention Mappings
| Your OTel attribute | Fiddler attribute |
|---|---|
gen_ai.tool.call.arguments | gen_ai.tool.input |
gen_ai.tool.call.result | gen_ai.tool.output |
gen_ai.tool.name | gen_ai.tool.name |
Agent and Conversation Attributes
| Your OTel attribute | Fiddler attribute | Notes |
|---|---|---|
gen_ai.agent.name | gen_ai.agent.name | Optional |
gen_ai.agent.id | gen_ai.agent.id | Optional |
gen_ai.conversation.id | gen_ai.conversation.id | Optional — used for multi-turn conversation grouping |
Set agent attributes on every span. If
gen_ai.agent.name or gen_ai.agent.id are provided, set both on every span within the trace. Fiddler uses these attributes to attribute spans to the correct agent — spans missing these fields will be unattributed even if other spans in the same trace carry them.Legacy / Underscore Field Names
If your traces use older underscore-style field names, map them to the Fiddler dotted equivalents before serialization:| Legacy field | Fiddler attribute |
|---|---|
model_name | gen_ai.request.model |
model_provider | gen_ai.system |
tool_name | gen_ai.tool.name |
tool_input | gen_ai.tool.input |
tool_output | gen_ai.tool.output |
llm_input_system | gen_ai.llm.input.system |
llm_input_user | gen_ai.llm.input.user |
llm_output | gen_ai.llm.output |
llm_context | gen_ai.llm.context |
Custom User Attributes
To attach business-level metadata to spans, prefix your keys withfiddler.span.user.:
Parsing gen_ai.input.messages
Thegen_ai.input.messages attribute is a JSON array of chat-style message objects. Fiddler expects it split into two separate attributes:
| Output attribute | Content |
|---|---|
gen_ai.llm.input.user | Text content of the last message with role: user |
gen_ai.llm.context | All other messages (conversation history), formatted as [role]: content |
| Attribute | Value |
|---|---|
gen_ai.llm.input.user | "And Germany?" |
gen_ai.llm.context | "[system]: You are a helpful assistant.\n\n[user]: What is the capital of France?\n\n[assistant]: Paris." |
user message is found, all messages are placed in gen_ai.llm.context and gen_ai.llm.input.user is omitted.
Span Kind and Status Mappings
Span kind (SpanKind enum):
| String value | Protobuf value |
|---|---|
INTERNAL | SpanKind.INTERNAL (default) |
SERVER | SpanKind.SERVER |
CLIENT | SpanKind.CLIENT |
PRODUCER | SpanKind.PRODUCER |
CONSUMER | SpanKind.CONSUMER |
StatusCode enum):
| String value | Protobuf value |
|---|---|
OK | StatusCode.OK (default) |
ERROR | StatusCode.ERROR |
UNSET | StatusCode.UNSET |
Minimal End-to-End Example
Related Documentation
- OpenTelemetry Integration — live agent instrumentation via the OTel SDK
- OpenTelemetry Quick Start — step-by-step setup guide
- Agentic AI Overview — compare all integration options
- Span and Resource Attributes — attribute typing, custom attributes, and how they flow into metrics and alerts