What You’ll Learn
- Discover which attribute keys exist on your application’s spans
- Find the spans worth promoting into a golden dataset
- Map span attributes onto dataset fields
- Add the selected spans as dataset items
Prerequisites
- An application that is already receiving traces
- A Fiddler API key from Settings > Credentials
- Python 3.10 or later
- Fiddler Evals SDK:
pip install fiddler-evals
If you prefer a notebook, open the fully worked example in Google Colab or download it from GitHub.
Start in the UI
The Explorer is the fastest way to build a golden dataset, and the recommended one for most cases. Select the spans you want and choose Add to Dataset. A three-step dialog walks you through picking a dataset, mapping fields, and reviewing the result before anything is written.
The Add to Dataset dialog's Map Fields step
Span fields are picked from a list, so you cannot mistype an attribute key — the most common way the SDK path fails.
Use the SDK instead when you need the workflow to be repeatable: curating on a schedule, promoting spans from CI, or parameterizing selection across applications.
The rest of this page covers that path.
How It Works
Spans and dataset items have different shapes. A span is a flat bag of OpenTelemetry attributes; a dataset item has four named buckets —inputs, expected_outputs, metadata, and extras.
Adding spans to a dataset is therefore a projection, and you supply the projection as a field mapping.
Attribute keys are stored exactly as your instrumentation sent them;
semantic mappings resolve framework-specific naming server-side without renaming what is stored.
The workflow has four steps:
1
Select Spans
Query for the spans you want, and collect their
trace_id and span_id pairs.2
Discover Their Attributes
Ask which attribute keys those spans carry, and how often.
3
Define a Field Mapping
Map each dataset field to the span attribute that populates it.
4
Add the Items
Fiddler resolves each span, applies the mapping, and writes one dataset item per span.
Step 1: Select the Spans to Promote
Pick the spans first, then discover what’s on them. Doing it the other way around scans your whole window and can surface attribute keys that aren’t present on the spans you actually promote — map one of those and you get a dataset of blank items. Connect, then choose a time window:add_items_from_spans() takes explicit (trace_id, span_id) pairs, so fetch some spans.
Use the POST /v3/spans/query endpoint, which returns spans newest-first.
The Evals SDK does not yet include a span-query method,
so this helper wraps the REST endpoint directly.
page_size maxes out at 200, matching the per-call span limit on add_items_from_spans(), so one page maps cleanly to one call.
To promote more than 200 spans you must advance offset yourself and call add_items_from_spans() once per page.
Narrow the Selection
filter is a structured tree over span fields. Field names are namespaced:
search is a case-insensitive substring match over span content, AND-ed with filter.
It matches the content attributes Fiddler full-text indexes, such as gen_ai.llm.input.user.
A filter tree is limited to 3 levels of nesting and 10 rules total.
A search query must be 3–64 characters.
Span::duration is in nanoseconds.
Keep the filter in a variable — Step 2 reuses it so discovery describes exactly this selection:
Expected output
filter_=None to select every span in the window.
Step 2: Discover the Attributes on Those Spans
Now that the selection is fixed, ask what those spans carry.get_span_fields() returns every attribute key with a coverage count, plus any evaluator outputs recorded on them.
Passing active_filter scopes discovery to exactly the spans you selected, so the keys you see are the keys you can map.
Expected output
count is what makes this useful: an attribute present on 33 of 47 spans is a poor choice for a required input field, because the spans missing it produce an empty string rather than an error.
get_span_fields() scans at most 10,000 matching spans.
Above that it sets sampled=True and the counts describe a sample rather than the full set.
Narrow the time range or the filter when you need exact coverage.Step 3: Define a Field Mapping
AFieldMapping maps dataset field name to span attribute key, bucket by bucket.
Every bucket is optional and defaults to empty.
The mapping is not stored anywhere — pass it on every call, or keep it in version control alongside your evaluation code.
inputsis what your task replays. Your task function receives this bucket as itsinputsargument, soinputs['user_query']is how it reads the captured query.expected_outputsis the reference to compare against. Promoting the production response here captures “what we shipped last time,” which is what makes the dataset a regression baseline.metadataandextrascarry context you want to slice results by, but that the task does not consume.
Step 4: Add the Items
Expected output
start_time and end_time must cover the spans you reference — Fiddler uses them to bound the lookup, and a span outside the window is treated as missing.
The call is all-or-nothing.
If any span cannot be resolved, Fiddler writes nothing and returns 422 with a SpanNotFound entry per unresolved span.
That makes retries safe: a failed call leaves the dataset untouched, so you can fix the references and call again without creating duplicates.
Limits
To add more than 200 spans, page through your span query and call
add_items_from_spans() once per batch.
Each call is independent, so a batch that fails does not roll back batches that already succeeded.
The per-call span limit and the per-dataset item limit can vary by deployment.
Check with your Fiddler administrator if your instance behaves differently.
Next Steps
- Run an experiment against the golden dataset you just built
- Capture traces during experiments to debug what your task did on each item
- Span and Resource Attributes — the full catalog of filterable fields
- Query spans REST reference
- Bulk add spans to dataset REST reference
DatasetSDK reference