How Do Exemplars Link Metrics to Traces in OpenTelemetry?
See how a single sampled measurement, stamped with a trace identifier, turns a flat line on a dashboard into a doorway that opens onto the exact request behind it, and learn how to set it up, read it, and keep it honest.
A doctor takes your temperature and sees 39 degrees. That number tells the doctor you have a fever, but it says nothing about the cause. To find the cause, the doctor opens your medical file, which holds the detailed story. Now imagine that every temperature reading on the chart had a small sticker on it saying “see file number 4471”. With one glance you could jump from the number to the story behind it.
Metrics in software are like that temperature chart. They summarise thousands of requests into a handful of numbers and tell you something is wrong, such as a spike in response time, but not why. Traces are the medical files, holding the full story of individual requests. Exemplars are the little stickers that connect the two. This guide explains what an exemplar is, how OpenTelemetry creates one, how it travels to your tools, and what can quietly go wrong along the way.
1Metrics Tell You What, Traces Tell You Why
The gap between a dashboard and an investigation.
When something goes wrong in a production system, engineers usually begin with a dashboard. A chart shows that the ninety-ninth percentile of response time has jumped from 300 milliseconds to 2 seconds. This is valuable, because it tells you that a problem exists, how big it is, and when it started. But it cannot tell you which requests were slow, which service was responsible, or what those requests had in common.
To answer those questions, engineers switch to a tracing tool and start searching. They guess a time range, filter by a service name, sort by duration, and hope that the slow trace they find is related to the spike they saw on the chart. This hunt takes time, and the connection between the chart and the trace is a guess, not a fact. Under pressure during an incident, every minute of guessing is expensive.
Think of a smoke alarm and a security camera. The alarm tells you there is smoke somewhere in the building. The camera footage shows what caused it. If the alarm’s message included a note saying “see camera 7, at 3:42 pm”, you would skip the search and go straight to the footage. An exemplar is that note.
An exemplar attaches a real example, with a link to its trace, to a summarised metric. The summary tells you something is wrong, and the example shows you one concrete case of it.
2Quick Recap: Metrics and Traces
The building blocks you need before exemplars make sense.
Metric
A numeric summary of behaviour over time, such as the count of requests or the distribution of response times.
Data Point
One reported value of a metric for one set of attributes over one time window. It is the summary that leaves the SDK.
Histogram
A metric that counts how many measurements fall into each value range, called a bucket. It is the usual way to track latency.
Trace
The complete record of one request as it travels through services, made of timed steps called spans.
Trace ID and Span ID
Unique identifiers that name one trace and one span within it. They are the addresses that exemplars point to.
Context
The in-process container that holds the currently active span, so that code can tell which request it is working on.
Why the two signals do not meet by default
Metrics and traces are produced by separate parts of the SDK and stored in separate systems. A metric data point is the result of squashing thousands of measurements together, and in that squashing, any information about individual requests disappears. The data point for “requests slower than one second: 40” does not remember which forty requests they were.
That loss is deliberate. It is what makes metrics cheap. But it creates exactly the gap described in Chapter 1, and exemplars are the standard way OpenTelemetry bridges it without giving up the savings.
Whenever you meet a new telemetry feature, ask which information it keeps and which it throws away. Exemplars exist because summaries throw away individual identity, and a few of those identities are worth rescuing.
3So, What Exactly Is an Exemplar?
A sample measurement that remembers where it came from.
In the OpenTelemetry data model, an exemplar is a recorded example of an input measurement that was folded into a metric data point. Instead of only keeping the totals, the SDK keeps a small number of real measurements, each one tagged with enough detail to find the request that produced it. Exemplars are attached directly to the data point they illustrate and travel with it to the backend.
Value
The actual measured number, for example a response time of 3.4 seconds. It is the original measurement, not an average.
Timestamp
The moment the measurement was taken, which lets tools place the exemplar precisely on a time axis.
Trace ID and Span ID
The identifiers of the trace and span that were active when the measurement was recorded. They make the link possible.
Filtered Attributes
Attributes present on the original measurement but not kept on the metric series itself. They preserve extra context without creating extra series.
| Question | Answered by the metric data point | Answered by the exemplar |
|---|---|---|
| How many requests were slow? | Yes, from the bucket counts | No |
| How slow was a specific example? | No, only a range | Yes, the exact value |
| Which request was it? | No | Yes, through the trace and span identifiers |
| What extra context did that request carry? | No, dropped by aggregation | Yes, through filtered attributes |
A restaurant publishes its average rating, which is a metric. Next to it, the site shows one featured review with a link to the full review page. The featured review is an exemplar: a real example that backs up the number and lets you read the whole story.
4Why Not Just Add the Trace ID as a Metric Attribute?
The question every newcomer asks, and the reason exemplars exist.
At first glance there is a simpler idea. Why not put the trace identifier on the metric itself as an attribute, so every data point knows its trace? The answer is cardinality. Each unique combination of metric attributes creates a separate time series, and every request has a unique trace identifier. A system with a million requests per hour would create a million series per hour, each holding a single measurement. Memory, storage, and query costs would explode, and the entire point of metrics, which is to be a cheap summary, would be destroyed.
Exemplars avoid that trap by keeping the trace identifier outside the series identity. The series is defined only by the normal low-cardinality attributes, such as route and status class. The exemplar rides along as extra payload on a data point, and only a handful are kept for each data point, no matter how many requests were recorded.
Exemplar approach
- Series count stays small and predictable
- Only a few examples are stored per data point
- Gives a direct jump from a chart to a real trace
- Can keep extra context in filtered attributes
- Costs are bounded by the reservoir size
Trace ID as an attribute
- Creates one series per request
- Memory in the SDK grows without limit
- Backend storage and indexing costs explode
- Queries become slow and expensive
- SDK overflow limits start discarding data
Imagine a library. The catalogue lists books by subject, which is compact and useful. Giving every single reader a separate catalogue drawer would turn the library into chaos. Instead, the catalogue stays tidy, and a few sample cards are clipped to the front of each drawer pointing to particular shelves. The clipped cards are exemplars.
Putting a trace identifier, user identifier, or request identifier on a metric as an ordinary attribute. It works in a small test, and then slowly ruins a production budget. Use exemplars for that need instead.
5The Journey of an Exemplar Inside the SDK
From one measurement to a stamped sample on a data point.
flowchart LR
A["Code records a measurement"] --> B["Aggregation updates the data point"]
A --> C{"Exemplar filter says yes?"}
C -->|No| D["Measurement used only for the aggregate"]
C -->|Yes| E["Exemplar reservoir offered the measurement"]
E --> F["Reservoir keeps or replaces a sample"]
F --> G["Collection time: reservoir returns exemplars"]
G --> H["Exemplars attached to the data point and exported"]
A measurement is recorded
Your code records a value on a histogram or counter, for example the duration of a request that has just completed, while a span for that request is still active.
The aggregate is always updated
Regardless of exemplars, the value is added to the metric’s running summary. This part never depends on exemplar settings.
The exemplar filter decides eligibility
A filter looks at the measurement and its context and decides whether the value is allowed to become an exemplar candidate at all.
The reservoir chooses what to keep
Eligible measurements are offered to a small fixed-size container called the reservoir, which keeps some and discards others according to its own rule.
The identifiers are captured
When a measurement is kept, the SDK reads the active span from the context and stores its trace identifier and span identifier alongside the value and time.
The exemplars leave with the data point
At the next collection, the reservoir hands over its kept samples, and they are exported together with the data point they belong to.
The trace and span identifiers come from whatever span is active in the context at the moment of recording. If no span is active, there is nothing to link to, and the exemplar either cannot be created or carries no trace information.
What happens when the measurement has no span
Plenty of measurements are recorded outside any request: a scheduled cleanup job, a background thread that refreshes a cache, or a startup routine. With the trace-based filter, such measurements are simply not eligible, because there is no sampled span in the context. Nothing breaks and no error is raised. The aggregate still counts the value, and the data point simply has fewer or no exemplars. This is a feature, not a flaw, since an exemplar with no trace behind it would be a link to nowhere.
It also means that the quality of your exemplars depends on how consistently your code records metrics inside the request path. If one team records latency inside the handler and another records it later in a callback after the span has ended, the first team gets working links and the second does not, even though both use the same SDK and the same settings.
6Exemplar Filters: Who Gets to Be a Candidate
The first gate in the pipeline, and the most important setting.
Not every measurement should become an exemplar. The exemplar filter is a rule that decides which measurements are eligible. It is the first gate, and its setting has a large effect on both cost and usefulness. The specification defines three standard filters, and SDKs usually let you choose among them with configuration or an environment variable.
Always off
No measurement becomes an exemplar. This turns the feature off completely and removes its small overhead.
Always on
Every measurement is eligible, even if there is no active span or the span is not being recorded. It gives maximum candidates but may produce exemplars that link to nothing.
Trace based
Only measurements taken while a sampled span is active are eligible. This is the standard default and ensures that the linked trace is actually being recorded.
Why trace based is the sensible default
An exemplar is only useful if clicking it leads to a trace. A trace exists in your backend only if its span was sampled. The trace-based filter ties the two together at the moment of recording: it admits a measurement only when the current span is sampled, which makes it likely that the link will lead somewhere. This is the reason exemplars and sampling are so closely related, a topic we return to in Chapter 12.
| Filter | Measurements considered | Link usually works? | Typical use |
|---|---|---|---|
| Always off | None | Not applicable | Disable exemplars to save overhead |
| Always on | All | Not guaranteed | Testing, or when all traces are kept |
| Trace based | Only those within a sampled span | Likely | Normal production default |
The name and exact behaviour of the filter setting differ between language SDKs and versions. Many SDKs read an environment variable for it, but you should confirm the accepted values and the default in the documentation for the version you run.
7Exemplar Reservoirs: Which Few Samples Survive
A tiny container with a strict rule about who stays.
Even after the filter, a busy service may record thousands of eligible measurements per collection interval, and it is impossible to keep them all. The reservoir is the component that decides which few to keep. Each time series has its own reservoir, and the reservoir has a fixed capacity, so the memory used for exemplars is bounded no matter how heavy the traffic is.
Fixed-size random
Keeps a small number of samples chosen at random from everything offered. A classic technique called reservoir sampling makes every offered measurement equally likely to be kept, without needing to know the total in advance.
Aligned to histogram buckets
Keeps one sample for each histogram bucket, so each value range has its own representative example. This is the natural fit for explicit-bucket histograms.
Custom
SDKs may allow you to supply your own logic, for example to prefer the largest value in the interval, though most teams stay with the defaults.
Imagine a photographer at a long parade who is allowed to keep only five photos. With a random reservoir, every photo taken has an equal chance of being among the five at the end. With a bucket-aligned reservoir, the photographer keeps one photo each from the marching bands, the floats, the horses, the dancers, and the clowns, so every kind of participant is represented.
The defaults
SDKs choose a sensible reservoir for each kind of metric. Histograms with explicit buckets commonly use the bucket-aligned kind, so that every bucket can offer its own example. Other metrics use the fixed-size random kind with a small capacity. The details are SDK specific, so treat the principle as the lesson: capacity is small, and the rule for who stays is simple.
Reservoirs reset between collections
The samples held by a reservoir belong to a specific collection interval. After they are exported, the reservoir starts afresh, so the exemplars on a data point describe measurements from that period rather than from the whole life of the process. This keeps exemplars fresh and relevant to the time range you are looking at on a chart.
Because reservoirs have fixed capacity, the cost of exemplars is predictable. Doubling your traffic does not double your exemplar storage, which is what makes them practical at scale.
How big should the reservoir be
A larger reservoir keeps more examples per interval, which raises the chance that a rare bucket has at least one, but it also increases the data sent with every export. For most services the defaults are a sensible balance. Raise the capacity only when you have evidence that important buckets are regularly empty and you can afford the extra bytes. Lowering it makes sense when exemplars are rarely clicked and bandwidth to the backend is tight.
Think of it as a camera roll with a fixed number of exposures. Fewer exposures mean you must choose carefully, and more exposures mean more film to carry and develop. No setting makes the roll unlimited, and that fixed ceiling is exactly what keeps the feature cheap.
8A Worked Example With Real Numbers
One minute of a checkout service, seen through a latency histogram.
Suppose a checkout service records the duration of each request in a histogram with buckets at 100 milliseconds, 250 milliseconds, 500 milliseconds, one second, and everything above one second. In one minute it handles ten thousand requests. The service samples ten percent of its traces, and the exemplar filter is the trace-based one. The histogram uses a bucket-aligned reservoir, so each bucket may hold one exemplar.
| Bucket | Requests counted | Example exemplar value | Linked to |
|---|---|---|---|
| Up to 100 ms | 8,200 | 62 ms | A sampled trace of a fast request |
| 100 to 250 ms | 1,500 | 180 ms | A sampled trace of a normal request |
| 250 to 500 ms | 250 | 410 ms | A sampled trace of a slowish request |
| 500 ms to 1 s | 40 | 870 ms | A sampled trace of a slow request |
| Above 1 s | 10 | 3.4 s | A sampled trace of a very slow request, if any were sampled |
The surprise in the last row
The top bucket holds only ten requests, and the trace-based filter admits only those whose trace was sampled. With a ten percent sampling rate, the chance that none of the ten was sampled is about 0.9 multiplied by itself ten times, which is roughly thirty-five percent. So there is only about a sixty-five percent chance that the slowest bucket has an exemplar at all. The rarest and most interesting requests are exactly the ones most likely to be missing a link.
This is not a flaw in exemplars. It is a direct consequence of combining rare events with low sampling. It tells you that if you care about finding the worst requests, your sampling strategy must favour them, for instance by keeping all slow or failed traces, a point we develop later.
A school keeps one sample essay from each grade band. If it only photocopies one in ten essays at random, the band containing the ten failing essays may end up with no sample at all, even though that band is the one the principal most wants to read.
Real systems vary in their reservoir sizes, bucket layouts, and sampling rates. Use this example to understand the mechanics, not to predict the exact content of your own data.
9Which Metric Types Carry Exemplars
Exemplars attach to metrics that summarise individual measurements.
The data model allows exemplars on several kinds of data points. They make the most sense on metrics where individual measurements are combined into a summary, because those are the cases where you want to see a representative example. Where the metric already is a single raw reading, there is less to illustrate.
Histogram
The classic home of exemplars. Each bucket can point to a real request, so you can open a trace for a request that landed in a slow bucket.
Exponential Histogram
The compact logarithmic histogram also carries exemplars, giving the same jump from a latency shape to a real request.
Sum or Counter
Counters of errors or retries can carry an exemplar, so a rising error count links to a real failing request.
Gauge
The data model allows exemplars on gauge data points, though they are less commonly used because a gauge is already a direct reading.
Asynchronous instruments are a special case
Observable instruments report values from a callback at collection time rather than at the moment something happens in a request. Because there is usually no active request span during that callback, there is no meaningful trace to link to. Exemplars are therefore mostly a feature of synchronous instruments, recorded inside the code path of a real request.
| Instrument | Recorded during a request? | Exemplar likely to be linkable? |
|---|---|---|
| Histogram | Yes | Yes |
| Counter | Yes | Yes |
| Up-down counter | Yes | Yes, but rarely valuable |
| Observable gauge | No, callback at collection time | Rarely, no active request |
| Observable counter | No, callback at collection time | Rarely, no active request |
If you adopt exemplars on only one metric, choose the request duration histogram of your busiest service. Latency is where the question “show me one of the slow ones” arises most often.
10On the Wire: OTLP and the Collector
How exemplars travel from the SDK to your tools.
Exemplars are part of the OpenTelemetry Protocol, usually called OTLP. Each metric data point in the protocol has a place for a list of exemplars, and each exemplar has fields for the value, the time, the filtered attributes, the trace identifier, and the span identifier. When an SDK exports metrics using OTLP, the exemplars simply ride along inside each data point, and a receiver that understands them can read them back out.
flowchart LR
A["Application SDK with exemplars"] --> B["OTLP export"]
B --> C["Collector receiver"]
C --> D["Processors"]
D --> E["Metrics exporter"]
E --> F["Metrics backend stores exemplars"]
A --> G["Trace export"]
G --> H["Collector then trace backend"]
F -.->|"Trace ID link"| H
Metrics and traces are still stored apart
An important point that surprises beginners is that exemplars do not move traces into the metrics system. The metrics backend only receives the identifiers and a few values. The traces themselves go to a tracing backend through the trace pipeline. The link between the two works because both backends know the same trace identifier, and a viewing tool can use that identifier to open the right trace.
What the Collector does with exemplars
The OpenTelemetry Collector passes exemplars through by default as part of the metric data. Some exporters convert them into the format of the target system. For example, exporters that feed Prometheus-style systems can translate exemplars into the exemplar format of that ecosystem. Some processors that reshape or aggregate metrics may drop or alter exemplars, because merging data points can make individual samples meaningless. Whenever you add a processor that modifies metrics, check whether exemplars survive it.
Confirm the SDK exports exemplars
Check that the exemplar filter is not set to always off and that metrics are exported through OTLP.
Inspect the Collector pipeline
List every processor between the receiver and the exporter, and note which ones reshape, aggregate, or filter metrics.
Check the exporter format
Make sure the exporter you use knows how to write exemplars in the target format, and that any needed option is switched on.
Check the backend
Verify that the backend stores exemplars at all, because some require a specific setting before they keep them.
Exemplars can be lost at the SDK, at a processor, at an exporter, or at the backend. When they do not appear in your tool, test each stage in order rather than assuming the first one is at fault.
11Backends and Dashboards: Clicking From a Chart to a Trace
Where the link becomes something an engineer can actually click.
The final piece of the story is the visualisation tool. A common arrangement uses a Prometheus-compatible store for metrics, a tracing backend for traces, and a dashboard tool that talks to both. On a latency chart, the dashboard draws small markers over the line, each representing an exemplar. Hovering over a marker shows its value and time, and clicking it opens the linked trace in the tracing backend.
sequenceDiagram
participant E as Engineer
participant D as Dashboard
participant M as Metrics store
participant T as Trace store
E->>D: Open latency chart for the last hour
D->>M: Query latency series with exemplars
M-->>D: Series plus exemplar markers
E->>D: Click a marker above the spike
D->>T: Open trace using the exemplar trace ID
T-->>D: Full trace of that slow request
D-->>E: Waterfall view showing where time was spent
What the backend must support
Not every metrics store keeps exemplars. Prometheus, for example, can store them, but it needs the feature to be enabled, and it keeps them in a bounded in-memory buffer rather than forever. It also limits how much text an exemplar’s attached labels may hold, which affects how many filtered attributes survive. Other backends and vendor platforms have their own rules. Before you rely on exemplars, read the documentation of your metrics store to learn whether it stores them, for how long, and with what limits.
What the dashboard must support
The dashboard tool needs to know how to draw exemplars and which tracing backend to open when you click one. In practice this means configuring a link from the metrics data source to the tracing data source, usually by telling the tool which field holds the trace identifier. Once configured, the experience is smooth. Until configured, the exemplars are stored but invisible.
| Layer | What it must do for exemplars | Common gap |
|---|---|---|
| SDK | Create exemplars from sampled requests | Filter turned off or no active span |
| Collector | Pass exemplars through and convert formats | A processor that drops them |
| Metrics store | Accept and keep exemplars | Feature not enabled, or small retention |
| Trace store | Hold the linked traces long enough | Trace retention shorter than metric retention |
| Dashboard | Draw markers and open traces on click | Data source link not configured |
After setting everything up, deliberately make a slow request in a test environment and follow its exemplar from the chart to the trace. That single test exposes most configuration mistakes.
Why dashboards show them as dots
An exemplar belongs to one moment in time and has its own value, so dashboards draw it as a single marker at that time and height rather than as part of the line. This is helpful, because the marker sits visually on top of the spike you are investigating. A cluster of markers high above the line tells you that several slow requests were captured in that period, and picking the highest one usually leads to the most informative trace.
Remember that the markers are examples, not a count. Ten markers do not mean ten slow requests happened. They mean that ten examples were kept, and the real number of slow requests is shown by the metric itself.
12Exemplars and Sampling: The Dangling Link Problem
A link is only as good as the trace it points to.
Because an exemplar contains a trace identifier, it can easily point to a trace that no longer exists, or never reached the backend. This is called a dangling link. You click the marker and the tracing tool answers that it cannot find the trace. The causes are almost always about sampling and retention.
The trace was not sampled
With the always-on filter, exemplars can be created for requests whose spans were never recorded. The identifier is real, but there is no trace behind it.
Tail sampling dropped it
The SDK’s filter sees only the early sampling decision. If a later stage, such as a Collector doing tail-based sampling, discards the trace, the exemplar still points to it.
Retention mismatch
Metrics are often kept for months while traces are kept for days. An old exemplar then points to a trace that has already expired.
Delayed or failed export
The metric may arrive before its trace, or the trace export may fail, leaving a temporary or permanent gap.
The head and tail sampling interaction
With head-based sampling, the decision is made when the trace starts, and the trace-based exemplar filter sees exactly that decision, so the linked trace is very likely to exist. With tail-based sampling, the final decision comes later, so the SDK cannot know whether a trace will survive. Exemplars created for traces that are later dropped become dangling links. Teams that use tail sampling often accept a small share of such links, or arrange for their sampling policies to keep the slow and failing traces, which are the ones most likely to be chosen as exemplars anyway.
Align retention
Keep traces for at least as long as you expect people to follow exemplars, or accept that older exemplars will not resolve.
Prefer the trace-based filter
Use it so that exemplars are only created for requests whose spans were recorded at the moment of measurement.
Keep the interesting traces
If you use tail sampling, add policies that keep slow and failed traces, so the rarest buckets are more likely to resolve.
Tell your users
Document that a missing trace is a known possibility, so engineers do not waste time wondering whether the tooling is broken.
Exemplars give you a likely path to a trace, not a guaranteed one. Setting that expectation early keeps trust in the feature high.
13Filtered Attributes: Context Without Cardinality
A quiet bonus feature that many teams overlook.
When you record a measurement, you can attach attributes to it, such as the route, the customer tier, or the region. Metrics usually keep only some of these attributes, because every extra attribute multiplies the number of series. A configuration object called a view lets operators choose which attributes a metric retains and which it discards. The discarded attributes seem to disappear.
Exemplars rescue some of that lost context. The attributes that were present on the original measurement but removed from the metric’s series are kept on the exemplar as filtered attributes. That means a chart that shows latency grouped only by route can still hand you, through an exemplar, the customer tier or the region of one concrete slow request, without creating a series for every tier and region.
A hospital’s yearly report counts patients per ward, which is compact. If every counted patient carried a tiny note listing age, city, and doctor, the report would balloon. But clipping one sample note to each ward’s total lets a reader glance at a real case and see details the total hides.
| Attribute | Kept on the metric series? | Visible on the exemplar? |
|---|---|---|
| Route | Yes, low variety | Not needed, already on the series |
| Status class | Yes, low variety | Not needed, already on the series |
| Customer tier | No, removed by a view | Yes, as a filtered attribute |
| Region | No, removed by a view | Yes, as a filtered attribute |
Be careful what you leave in
Because filtered attributes travel to your metrics backend, they inherit the privacy and size concerns of any exported data. Backends may limit how much attached text an exemplar can hold, and sensitive values should never be placed in attributes that might be copied onto exemplars. We return to this in the security chapter.
Use a view to keep metric attributes low in variety, and let exemplars carry the richer context for the few examples you keep. You get small metrics and detailed examples together.
14Advantages and Trade-offs
An honest balance sheet before you rely on them.
Advantages
- Direct jump from a chart anomaly to a real trace
- Small and predictable cost, bounded by the reservoir size
- No growth in the number of metric series
- Filtered attributes preserve valuable context
- Works across languages because it is part of the standard
- Speeds up incident investigation
Disadvantages / Trade-offs
- Needs both tracing and metrics to be set up well
- Only a few samples exist per data point, so some buckets may have none
- Links can dangle because of sampling or retention gaps
- Depends on support in every layer of the pipeline
- Exemplars are a biased sample, not a statistical one
- Can carry sensitive text if attributes are careless
| Approach to linking metrics and traces | Cost | Precision of the link |
|---|---|---|
| Exemplars | Low and bounded | Exact trace for a few sample requests |
| Trace ID as a metric attribute | Very high | Exact, but at ruinous cost |
| Searching traces by time and service | No extra data cost | Guesswork that depends on the engineer |
| Metrics generated from spans | Moderate | Consistent with traces, but no link to individual requests |
When they are worth it
Exemplars repay their small effort when your teams already use both metrics and traces, when incidents often start from a latency or error chart, and when engineers lose time hunting for representative traces. They add little if you do not trace at all, or if your traffic is so small that you can simply search all the traces.
Exemplars are like bookmarks left by an earlier reader in a very long book. They do not replace reading the book, and some chapters have no bookmark, but when you are in a hurry, a bookmark on the right page saves a great deal of searching.
The cost in numbers
An exemplar is small. Its fixed parts are a value of about eight bytes, a timestamp of about eight bytes, a trace identifier of sixteen bytes, and a span identifier of eight bytes, which together come to roughly forty bytes before any filtered attributes. If each data point carries five exemplars, that is about two hundred bytes of extra payload per data point. A service reporting a thousand series every export interval therefore sends around two hundred kilobytes of additional data in that interval, which is modest compared with the span data it already produces.
The real cost is rarely the bytes. It is the effort of enabling support in every layer, and the attention needed to keep traces around long enough for the links to work. Teams that budget for that effort, rather than for bandwidth, are the ones that get lasting value from the feature.
15Security and Privacy Considerations
A small feature that crosses two data stores deserves a short safety review.
Trace identifiers themselves are random numbers and not sensitive, but the places they lead to can be. A trace may contain query text, customer identifiers, internal hostnames, or error messages with private details. An exemplar makes those traces one click away from anyone who can view the metrics dashboard. If access to metrics is broader than access to traces, exemplars can quietly widen who can reach sensitive data.
Match access levels
Ensure that people who can click an exemplar are allowed to read the trace it opens. The trace store should enforce its own permissions rather than trusting the dashboard.
Control filtered attributes
Review which attributes can end up on exemplars. Keep personal data, tokens, and secrets out of measurement attributes entirely.
Encrypt the path
Use encrypted connections for OTLP and for queries between the dashboard, metrics store, and trace store.
Respect retention rules
If policy requires deleting traces after a period, make sure exemplars do not preserve identifiers or attributes that outlive that rule.
Problem
Measurements are recorded with attributes that contain email addresses, account numbers, or other personal data, and a view removes them from the metric, assuming they are gone.
Why It’s Harmful
Removed attributes can still be preserved on exemplars as filtered attributes and shipped to the metrics backend, where they may be stored and displayed to a wide audience.
Correct Approach
Never attach personal or secret values to measurements at all, and use opaque internal identifiers when context is needed.
16Real-World Uses of Exemplars
Where teams find the biggest payoff.
The following examples describe patterns widely used across the industry. In every case the story begins with a chart and ends with a concrete trace.
Latency spike investigation
An on-call engineer sees the ninety-ninth percentile jump. Instead of searching, they click an exemplar in the slow bucket, open the trace, and see that a single downstream call to a database took three seconds. The investigation shrinks from half an hour to two minutes.
Error rate alerts
An alert fires because the error counter is rising. The alert message links to the chart, and an exemplar on the error series points to a real failing request, showing the exact exception and the service where it started.
Service level objective burn
A team watching an objective about fast responses sees the budget draining. Exemplars attached to the slow buckets give a quick sample of what the offending requests have in common, such as a particular endpoint or customer tier.
Release verification
After a deployment, a latency chart looks slightly worse. Exemplars from the new version’s slow requests show a newly introduced extra call, which the team removes before the change reaches all users.
Queue and batch diagnostics
A histogram of time spent waiting in a queue links, through an exemplar, to a trace that reveals exactly which consumer was starved, helping capacity planning.
Noisy neighbour detection
A shared database shows occasional slow queries. Exemplars on the query duration histogram link to traces from different calling services, revealing that one batch job from another team is saturating the database at the top of every hour.
Customer complaint triage
Support reports that a customer saw a slow page at a certain time. An engineer looks at the latency chart for that window and opens an exemplar from the slow bucket, which gives a realistic example of what the customer experienced, even when the exact request was not sampled.
Teaching and onboarding
New engineers learn how a system behaves by clicking from familiar charts into real traces, which builds an intuition about request paths far faster than reading architecture diagrams alone.
Each success story starts from something the team already watches daily, a chart or an alert. Exemplars work best when they are added to the views people already trust, not offered as a separate tool.
17Design Patterns and Anti-patterns
Habits that keep exemplars useful, and traps to avoid.
flowchart TD
A["Do you collect both metrics and traces?"] -->|No| B["Set up the missing signal first"]
A -->|Yes| C{"Do incidents start from charts and alerts?"}
C -->|No| D["Exemplars are optional"]
C -->|Yes| E{"Do your backends store and link exemplars?"}
E -->|No| F["Enable support or choose compatible backends"]
E -->|Yes| G["Use trace-based filter on latency and error metrics"]
Patterns that work
Start with the latency histogram
Enable exemplars first on the request duration histogram of your busiest service, then expand once the value is proven.
Trace-based filter by default
Keep the default so exemplars are created only for requests whose spans were recorded.
Align retention
Choose trace retention that covers the time window people actually investigate.
Keep the interesting traces
Use sampling rules that favour slow and failed requests, so the rare buckets resolve to real traces.
Low-cardinality series, rich exemplars
Keep metric attributes few and put extra context only on exemplars.
Anti-patterns to avoid
Problem
Teams treat exemplars as a random, unbiased sample of requests and use them to estimate how common a behaviour is.
Why It’s Harmful
Exemplars are kept by filters, reservoirs, and sampling rules, and rare buckets are often under- or over-represented. Conclusions about frequency will be wrong.
Correct Approach
Use the metric counts to learn how often something happens, and use exemplars only to look at real examples.
Problem
The always-on filter is used in production while traces are heavily sampled, so most exemplars point to traces that do not exist.
Why It’s Harmful
Engineers click markers, find nothing, and quickly learn to distrust the feature. Time is wasted and the investment is lost.
Correct Approach
Use the trace-based filter so that exemplars follow the sampling decision made when the measurement was recorded.
Problem
Exemplars are switched on in the SDK, but nobody checks the Collector, the metrics store, or the dashboard, and no exemplar ever appears.
Why It’s Harmful
The feature seems broken, and teams give up before finding that a single processor or an unset option in one layer was dropping them.
Correct Approach
Verify every layer once, from SDK to dashboard, with a deliberately slow test request.
18Testing and Troubleshooting Exemplars
A short checklist for the question “why can I not see any exemplars?”
Exemplars fail quietly. The metric still arrives, the chart still draws, and nothing reports an error. The only symptom is the absence of markers. Because the feature spans five layers, the most efficient approach is a fixed checklist that walks from the application to the screen and stops at the first place where exemplars are missing.
Is a sampled span active?
Confirm the measurement is recorded inside a request that has an active, sampled span. Background tasks and unsampled requests will not produce linkable exemplars.
Is the filter allowing candidates?
Check that the exemplar filter is not off and that the SDK version supports exemplars for the instrument you are using.
Are exemplars in the exported data?
Look at the exported metrics, for example through a debug output in the Collector, and confirm that data points contain exemplars with trace and span identifiers.
Does the pipeline preserve them?
Check each processor and the exporter for options that drop or convert exemplars.
Does the backend store them?
Confirm that the metrics store has exemplar storage enabled and that its limits are not rejecting yours.
Does the dashboard link to traces?
Verify that the metrics data source is linked to the tracing data source and that the trace identifier field is mapped.
| Symptom | Likely cause |
|---|---|
| No exemplars in exported data | Filter off, no active span, or unsupported instrument |
| Exemplars exported but missing in the store | Collector processor or exporter dropping them, or storage disabled |
| Markers appear but clicking does nothing | Dashboard link to the trace store not configured |
| Clicking says trace not found | Trace not sampled, dropped later, or expired |
| Exemplars only on some buckets | Reservoir size and sampling leave rare buckets empty |
Send a deliberately slow synthetic request on a schedule and alert if no exemplar for it appears on the chart. This catches silent regressions after upgrades or configuration changes.
19Frequently Asked Questions
Short answers to the questions people ask most often.
An exemplar is a real sample measurement attached to a metric data point, carrying the trace and span identifiers of the request that produced it, so you can jump from a summary number to a concrete trace.
No. Exemplars are extra payload on an existing data point, not part of the series identity, so they do not increase the number of series. That is the main reason to prefer them over trace identifiers as ordinary attributes.
The data model allows them on sums, histograms, exponential histograms, and gauges. In practice they are most valuable on histograms and counters recorded during real requests.
The standard default is the trace-based filter, which only considers measurements recorded while a sampled span is active. This makes it likely that the linked trace exists in your backend.
Only a few, set by the reservoir capacity. Bucket-aligned reservoirs for explicit histograms can hold up to one per bucket, while fixed-size random reservoirs hold a small configured number.
A bucket gets an exemplar only if at least one eligible measurement fell into it during the interval. Rare buckets combined with low sampling often have none, which is expected behaviour.
The trace may have been dropped by a later sampling stage, may not have been exported, or may have expired because trace retention is shorter than metric retention. Aligning retention and favouring slow and failed traces reduces this.
They can, but the SDK cannot know the final decision when it creates the exemplar. Some exemplars will point to traces that tail sampling later drops, so teams usually keep slow and failed traces and accept a small share of dangling links.
They can, through filtered attributes and through the traces they link to. Keep personal data out of measurement attributes and make sure the people who can see exemplars are allowed to open the traces.
No. Exemplars are a filtered, biased handful of examples. Use the metric counts for frequency and the exemplars for looking at what one real case looks like.
20Summary and Key Takeaways
Exemplars solve a very practical problem: a metric tells you that something is wrong, but it forgets which requests were responsible. By keeping a handful of real measurements, each stamped with the trace and span identifiers of the request that produced it, OpenTelemetry lets a chart point straight at a trace. The cost stays small because the number of exemplars per data point is capped by a reservoir, and the number of series does not grow at all.
To make the link work, every layer must cooperate. The SDK needs a filter that admits measurements from sampled spans, a reservoir that picks a few of them, and an active span at the moment of recording. The pipeline must carry the exemplars through, the metrics store must keep them, the trace store must still hold the traces, and the dashboard must know how to connect the two. When the pieces line up, an engineer goes from a latency spike to the exact slow request in a single click. When any piece is missing, the failure is silent, which is why a smoke test and a short checklist are worth having. Like the sticker on the temperature chart, an exemplar is small, but it points to the whole story.
Key Takeaways
- Exemplars link summaries to examples — each one is a real measurement with a value, a time, trace and span identifiers, and optional filtered attributes, attached to a metric data point.
- They avoid the cardinality trap — the trace identifier stays outside the series identity, so the number of series does not grow, unlike putting trace identifiers on metrics as attributes.
- Filter and reservoir control the cost — the filter decides which measurements are eligible, with the trace-based filter as the usual default, and the reservoir keeps only a few samples per interval.
- A sampled span must be active — links are created from the active span at recording time, so background work and unsampled requests rarely produce usable exemplars.
- Every layer must support them — SDK, Collector processors and exporters, the metrics store, the trace store, and the dashboard all need to preserve or display exemplars.
- Links can dangle — tail sampling, short trace retention, and failed exports can leave exemplars pointing to traces that no longer exist, so align retention and keep slow and failed traces.
- Use them as examples, not statistics — rely on metric counts for how often something happens, keep sensitive values out of attributes, and use exemplars to see what one real case looks like.