Span attributes and events
Braintrust maps GenAI attributes and events, OpenInference attributes, and explicitbraintrust.* attributes to span fields.
GenAI attributes
Braintrust implements the OpenTelemetry GenAI semantic conventions. When you send traces with these attributes, they are automatically mapped to Braintrust fields.
On Braintrust-hosted deployments,
gen_ai.evaluation.name and gen_ai.evaluation.score.value map to scores.<name>. The name must be nonempty and the score must be a finite number from 0 to 1, inclusive. Numeric strings are accepted. Invalid values are not mapped to scores.
GenAI events
Braintrust also extracts messages and scores from GenAI span events. These events follow the OpenTelemetry GenAI semantic conventions for events:
The message events listed above are processed in the order they appear in the span. When they produce a nonempty input or output message list, that list takes precedence over the corresponding attribute-derived field.
Each event is also stored as a separate log row associated with the span. Mapping a GenAI event to span fields does not remove the event record.
OpenInference attributes
On Braintrust-hosted deployments, spans withopeninference.span.kind are mapped using OpenInference semantic conventions. These include traces from OpenInference instrumentors for LangChain, LangGraph, LlamaIndex, DSPy, and the OpenAI Agents SDK.
Collections use flattened, indexed attributes, such as llm.input_messages.0.message.role and llm.input_messages.0.message.content.
Span fields
When converting input messages, Braintrust prepends a system prompt from
llm.invocation_parameters if no system or developer message is present. If media cannot be represented as chat messages, Braintrust preserves the original OpenInference messages in input or output instead.
Metadata
Unmapped attributes remain in
metadata. Mapped attributes follow the attribute preservation settings.
Token usage
Token metrics are extracted only fromLLM and EMBEDDING spans to avoid counting aggregate usage on chain or agent spans twice. prompt_tokens includes cached tokens.
Scores
Braintrust maps span-scoped annotations and evaluations to scores on the span carrying the attributes:
Each entry must have a nonempty name and a finite score from 0 to 1, inclusive. Numeric strings are accepted. Missing, nonnumeric, or out-of-range values are not mapped to
scores. Names, labels, and explanations remain in metadata.
Trace- and session-scoped feedback, such as trace.annotations.* or session.evaluations.*, remains in metadata and is not mapped to span scores.
Braintrust attributes
You can also use thebraintrust namespace to set fields in Braintrust directly:
Fields mapped from
braintrust.* attributes are removed from metadata and stored in the corresponding Braintrust fields. Nonempty input or output arrays whose elements have valid chat roles are recognized as LLM message arrays.
Attribute example
This example sets GenAI and Braintrust attributes using flattened names and JSON-encoded values:Python
Why are some attributes missing from metadata?
Why are some attributes missing from metadata?
For Braintrust-hosted organizations, source attributes such as
ai.prompt, gen_ai.input.messages, and llm.input_messages are removed from metadata once Braintrust has mapped them to a structured field (input, output, metrics, etc.). The data itself can be found on the structured field it was mapped into.Self-hosted deployments behave the same way when the STRIP_OTEL_ATTRIBUTES_FROM_METADATA environment variable is set on the api-ts service.To keep the raw attributes on metadata for a specific span, set the braintrust.otel.preserve_attributes attribute to true on that span.For details, see Strip OTel attributes from metadata.Log records
Each OTLP record becomes a separate row withspan_attributes.type set to log:
Log attributes do not undergo the GenAI mapping used for trace spans. For example, a
gen_ai.usage.input_tokens attribute on a log remains in metadata rather than becoming a token metric.
A record with valid trace and span IDs shares its owning span’s span_id and trace’s root_span_id, while retaining its own unique row id. A record with a trace ID only joins that trace with a generated span ID. A record without a trace ID receives its own span and root IDs.
OpenTelemetry span events received through /otel/v1/traces, including GenAI events, are also stored as separate log rows. Each event row shares its span’s span_id and root_span_id and has its own row id. The event name is stored in output, and its attributes are stored in metadata. Recognized GenAI events can also populate fields on the owning span, as described in GenAI events.
Log levels and exceptions
On Braintrust-hosted deployments, the severity number maps tospan_attributes.log_level:
If the severity number is absent,
0, or outside these ranges, Braintrust does not derive a log level. The original severity number and text remain in context.otel.log.
On Braintrust-hosted deployments, the top-level error field is populated from nonempty exception attributes: exception.stacktrace, exception.type, or exception.message. Severity and message body alone do not populate it. Use span_attributes.log_level to find error-level messages, and error to find records carrying exception details.
The canonical log-level mapping and exception-only
error behavior require data plane v2.15.0 or later. On earlier versions, inspect the original severity fields in context.otel.log. Error-level severity can populate error even without exception attributes.