Dash0 acquires Polar Signals

Last updated: September 6, 2026

Sample Traces

Reduce trace volume with configurable sampling rules, evaluated after all spans of a trace arrive.

Sampling reduces the volume of traces Dash0 stores while keeping the ones that matter. You define the rules, so you decide which traces to keep. A common setup keeps every error and slow trace and samples routine traces down to a target percentage, but that is one option among many. Spans are held briefly and evaluated together, so a keep-or-drop decision reflects the whole trace rather than any single span. This is tail sampling, and it can reduce trace volume by 90% or more without losing the traces you troubleshoot from.

Sampling applies to spans. Metrics you derive with signal-to-metrics conversion are produced at ingestion, so you keep those numbers even though the stored traces are sampled down. RED metrics are likewise calculated before sampling, so the request, error, and duration views in Dash0 reflect all of your traffic rather than only the sampled traces.

Dash0 Add sampling rule form with a Probabilistic condition combined with a Conditional condition whose Editor is set to Filter, showing an Add filter control

Add a Sampling Rule

  1. From the pipeline, open the Sampling stage for Spans and click Add sampling rule.
  2. Enter a Display name, for example My Sampling Rule.
  3. Under Conditions, choose a Type and fill in its inputs. The condition types are described below.
  4. Click Add condition to add another condition, or choose the All of… type to require several at once.
  5. Make sure Enabled is on, then click Save.

As you build the rule, the What this rule does panel restates it in plain language so you can confirm the behavior before saving.

Warning

Sampling is off for a dataset until it has at least one enabled sampling rule, and all traces pass through. As soon as one rule is enabled, a trace is kept only if a rule matches it, and traces that match no rule are dropped when their decision window closes. Your first rule therefore turns sampling on for the whole dataset. Make sure that rule, or a companion rule, keeps the traces you rely on, for example every error trace.

Condition Types

The Type dropdown offers four condition types.

Dash0 Add sampling rule form with the condition Type dropdown open, showing the four options Probabilistic, Conditional, Error, and All of…

Probabilistic

Probabilistic conditions keep a fixed percentage of traces using a deterministic trace-ID hash, so the decision is consistent for every span of a trace. Use them for a baseline sampling rate. Set the Sampling rate to the percentage of traces to keep, between 0 and 100.

Conditional

Conditional conditions keep traces whose spans match a content-based condition. Use them to retain errors, latency outliers, and business-critical flows. Choose how to define the condition with the Editor toggle:

  • Filter — build the condition with the same filter controls used elsewhere in Dash0. Click Add filter to add clauses.
  • OTTL — write the condition in the OpenTelemetry Transformation Language. Reference span attributes as attributes["..."], resource attributes as resource.attributes["..."], and span fields directly, for example attributes["http.status_code"] >= 500 to keep server-error traces or resource.attributes["k8s.cluster.name"] == "production" to keep traces from the production cluster.

Dash0 Add sampling rule form with a Conditional condition whose Editor is set to OTTL, showing the expression attributes["http.status_code"] >= 500

Error

Error conditions keep traces that contain an error. They need no further input.

All of…

All of… conditions require several conditions at once. Nest other condition types inside them, and a trace is kept only when all of the nested conditions match. For example, nest a Conditional rule that matches the production cluster with a Probabilistic rule set to 50% to keep half of your production traces.

Dash0 Add sampling rule form with an All of… condition containing a nested Probabilistic condition and a nested Conditional condition

A typical rule set combines these: Conditional and Error conditions keep the errors and business-critical traces, and a Probabilistic condition reduces the remaining routine traffic to a baseline percentage.

Note

Every span of a trace shares one keep-or-drop decision, so a trace is kept or dropped as a whole. Spans are buffered briefly while that decision is reached, and a trace is kept as soon as its conditions are satisfied.

Warning

Traces dropped by sampling cannot be recovered. Start with a conservative rate and confirm your error and latency rules keep the traces you rely on before lowering the baseline.

Sampling on the Edge

When you run SignalControl Edge, tail sampling happens inside your own network, on Kubernetes or without Kubernetes, so the dropped traces never leave your network and you save egress cost as well as storage. Because a single keep-or-drop decision covers a whole trace, ensure all spans of a trace are routed to the same dataset when sampling on the edge.

The rest of this section covers the standalone edge deployment: authoring rules through the API, and the dash0sampling processor and reservoir configuration.

Authoring Sampling Rules via the API

Send API requests to your region's API endpoint from the endpoint table, with an Authorization: Bearer <token> header. Creating sampling rules requires a token with the admin role. See Dash0 API for the general conventions, and the setup steps for a complete curl example.

Rules are created with POST /api/sampling-rules?dataset=<dataset>. A rule has a kind of Dash0Sampling, a metadata.name, and a spec with enabled, an optional display.name shown in the UI, one conditions tree, and an optional rateLimit.

The condition kinds map to the four UI types (ottl is the Conditional type's OTTL editor, and and is All of…):

  • probabilistic (Probabilistic): Keep a fixed fraction via a deterministic trace-ID hash. spec.rate is 0.0–1.0. Decided locally in the collector, with no coordination.
  • ottl (Conditional): Keep traces matching an OTTL boolean expression in spec.ottl. Reference span fields with span. and resource attributes with resource.attributes[...].
  • error (Error): Keep traces with an error span. spec is empty.
  • and (All of…): Require all nested conditions. spec.conditions is a non-empty list of the kinds above.

A rule may contain at most 32 ottl and error conditions across its tree. Probabilistic conditions are decided locally and do not count. The API does not reject a larger rule; Dash0 rejects it when loading the rules for your organization, and that rule stops matching. Keep every rule well within the limit. There is no fixed limit on the number of rules per dataset. See the limits table.

Keep every error trace:

json
12345678910111213141516
{
"kind": "Dash0Sampling",
"metadata": {
"name": "keep-errors"
},
"spec": {
"enabled": true,
"display": {
"name": "Keep error traces"
},
"conditions": {
"kind": "error",
"spec": {}
}
}
}

Keep 50% of traces from the production cluster, combining an OTTL condition with a probabilistic one:

json
12345678910111213141516171819202122232425262728293031
{
"kind": "Dash0Sampling",
"metadata": {
"name": "production-baseline"
},
"spec": {
"enabled": true,
"display": {
"name": "Production baseline 50%"
},
"conditions": {
"kind": "and",
"spec": {
"conditions": [
{
"kind": "ottl",
"spec": {
"ottl": "resource.attributes[\"k8s.cluster.name\"] == \"production\""
}
},
{
"kind": "probabilistic",
"spec": {
"rate": 0.5
}
}
]
}
}
}
}

Keep every slow checkout trace, but no more than 1000 per minute:

json
123456789101112131415161718192021
{
"kind": "Dash0Sampling",
"metadata": {
"name": "slow-checkout"
},
"spec": {
"enabled": true,
"display": {
"name": "Slow checkout traces"
},
"conditions": {
"kind": "ottl",
"spec": {
"ottl": "span.name == \"POST /checkout\" and span.duration > 500ms"
}
},
"rateLimit": {
"rate": 1000
}
}
}

rateLimit is optional but recommended on any rule that can match a burst. rateLimit.rate caps traces kept per minute for the rule, so an outage that trips an error rule does not flood ingest. Very low limits (16 or below) are not guaranteed, and a probabilistic-only rule cannot set one.

Sampling Processor Configuration

Every field on dash0sampling:

YAML keyDefaultDescription
decision_maker_endpointrequiredgRPC host:port of the edge proxy, or the Dash0 sampling upstream in direct mode.
decision_maker_headersnoneHeaders on every gRPC call. Required in single mode: carry Authorization: Bearer <token> and Dash0-Dataset: <dataset>. Must be absent in multi mode.
decision_maker_insecurefalseDisable TLS. Use true only for a plaintext local edge proxy.
organization_modesinglesingle looks rules up by dash0.dataset only (one org, implied by the token). multi also keys on dash0.org.technical.id. Standalone edge uses single.
default_datasetdefaultDataset used when a span carries no dash0.dataset. Single mode only.
reservoirrequiredThe span buffer. See the reservoir fields below.
enable_batchingfalseBatch satisfaction reports to the upstream instead of sending each immediately.
max_batch_size500Max reports per batch. Only when enable_batching is true.
max_batch_wait200msMax wait before flushing a partial batch. Only when enable_batching is true.
decision_channel_max_size10000Buffer for incoming decisions. Raise if you see decision-processing lag.
eviction_channel_size1000Buffer for spans leaving the reservoir toward the exporter.
fallback_sample_ratio0.01Probabilistic keep ratio (0.0–1.0) used when the upstream is unreachable or has not delivered rules yet. 0.0 blocks until rules arrive; 1.0 keeps everything.
fallback_min_connected_ratio1.0Fall back to probabilistic when the connected fraction of upstream instances drops below this. 1.0 falls back if any instance is disconnected; 0.0 only when fully disconnected.
fallback_until_rules_receivedtrueUse the fallback ratio during startup until the first rules arrive, instead of blocking.
metric_recordernoneOptional dash0metricrecorder ID for sampling volume counters. Leave unset unless you specifically want the sampling _in/_out counters.
debugfalseVerbose per-decision logging. High volume; debugging only.

The Reservoir

The reservoir buffers spans while their trace waits for a decision. Pick a type by retention need and throughput:

reservoir.typeBest forTrade-off
memoryShort retention (5–15s), lowest latencyBounded by max_memory_bytes
serialized_memoryHigh throughput, moderate retentionBest balance for most workloads
disk (default)Long retention (60s+), large volumesNeeds data_dir on a fast SSD/NVMe

disk is what the processor uses when type is unset, and it refuses to start without a data_dir. The reference configuration sets serialized_memory explicitly, which needs no storage and suits most workloads. Choose disk deliberately when you need long retention or volumes that exceed memory, and give it a dedicated fast volume.

Reservoir fields:

YAML keyDefaultApplies toDescription
typediskallmemory, serialized_memory, or disk.
buffer_duration60sallHow long spans are held awaiting a decision. Must cover the expected decision latency. Too short drops spans early; too long raises memory. Typical 30–60s.
max_memory_bytes104857600 (100 MB)memory, serialized_memoryMemory cap; oldest traces are evicted when exceeded.
estimated_bytes_per_span800memoryPer-span size estimate used for the memory calculation.
data_dirrequired for diskdiskDirectory for shard files. Use dedicated, fast storage.
max_disk_bytes0 (unlimited)diskTotal disk cap across shards. Default 0 means unlimited (age-based eviction only); set >0 to cap, e.g. 1073741824 (1 GiB).
shard_count16; CPU count (memory)allParallelism for writes. Defaults to 16 for every type except memory, which uses the CPU count. Raise if you see "ingest channel full".
rotation_interval5sdiskHow often active files are sealed and become eligible for eviction.
writer_buffer_size262144 (256 KB)diskPer-shard write buffer.
ingest_channel_size100allPer-shard ingest buffer.
eviction_scan_send_timeout1sallHow long eviction waits on a slow consumer before dropping a matched trace.

Sizing rule of thumb: required storage ≈ spans/sec × bytes/span × buffer_duration, across the fleet. At 800 bytes per span, 100k spans/s over a 10s window is about 800 MB; split it across your collector instances.

Further Reading