0
# Samplers
1
2
Samplers control which traces are collected and recorded by making sampling decisions for each span. OpenTelemetry SDK Trace Base provides several built-in sampling strategies including always-on, always-off, ratio-based, and parent-aware samplers.
3
4
## Capabilities
5
6
### Core Sampler Interface
7
8
All samplers implement the base Sampler interface for consistent sampling decisions.
9
10
```typescript { .api }
11
/**
12
* Interface representing a sampler for controlling trace collection
13
*/
14
interface Sampler {
15
/**
16
* Checks whether span needs to be created and tracked
17
* @param context - Parent Context which may contain a span
18
* @param traceId - Trace ID of the span to be created
19
* @param spanName - Name of the span to be created
20
* @param spanKind - Kind of the span to be created
21
* @param attributes - Initial set of attributes for the span
22
* @param links - Collection of links associated with the span
23
* @returns SamplingResult with decision and optional attributes
24
*/
25
shouldSample(
26
context: Context,
27
traceId: string,
28
spanName: string,
29
spanKind: SpanKind,
30
attributes: Attributes,
31
links: Link[]
32
): SamplingResult;
33
34
/**
35
* Returns the sampler name or short description with configuration
36
*/
37
toString(): string;
38
}
39
40
/**
41
* Sampling result containing decision and additional attributes
42
*/
43
interface SamplingResult {
44
/** Sampling decision determining how the span will be handled */
45
decision: SamplingDecision;
46
/** Immutable list of attributes to add to the span */
47
attributes?: Readonly<Attributes>;
48
/** TraceState to associate with the span through SpanContext */
49
traceState?: TraceState;
50
}
51
52
/**
53
* Sampling decision that determines how a span will be recorded and collected
54
*/
55
enum SamplingDecision {
56
/** Span.isRecording() === false, span will not be recorded */
57
NOT_RECORD,
58
/** Span.isRecording() === true, but Sampled flag not set */
59
RECORD,
60
/** Span.isRecording() === true AND Sampled flag set */
61
RECORD_AND_SAMPLED
62
}
63
```
64
65
### AlwaysOnSampler
66
67
Sampler that always samples all traces, useful for development and debugging.
68
69
```typescript { .api }
70
/**
71
* Sampler that samples all traces
72
*/
73
class AlwaysOnSampler implements Sampler {
74
/**
75
* Always returns RECORD_AND_SAMPLED decision
76
*/
77
shouldSample(
78
context: Context,
79
traceId: string,
80
spanName: string,
81
spanKind: SpanKind,
82
attributes: Attributes,
83
links: Link[]
84
): SamplingResult;
85
86
/**
87
* Returns "AlwaysOnSampler"
88
*/
89
toString(): string;
90
}
91
```
92
93
**Usage Examples:**
94
95
```typescript
96
import { BasicTracerProvider, AlwaysOnSampler } from '@opentelemetry/sdk-trace-base';
97
98
// Enable sampling for all traces
99
const provider = new BasicTracerProvider({
100
sampler: new AlwaysOnSampler()
101
});
102
103
// Useful for development environments
104
const devProvider = new BasicTracerProvider({
105
sampler: new AlwaysOnSampler(),
106
resource: new Resource({
107
'service.name': 'dev-service',
108
'deployment.environment': 'development'
109
})
110
});
111
```
112
113
### AlwaysOffSampler
114
115
Sampler that never samples traces, useful for disabling tracing or testing scenarios.
116
117
```typescript { .api }
118
/**
119
* Sampler that samples no traces
120
*/
121
class AlwaysOffSampler implements Sampler {
122
/**
123
* Always returns NOT_RECORD decision
124
*/
125
shouldSample(
126
context: Context,
127
traceId: string,
128
spanName: string,
129
spanKind: SpanKind,
130
attributes: Attributes,
131
links: Link[]
132
): SamplingResult;
133
134
/**
135
* Returns "AlwaysOffSampler"
136
*/
137
toString(): string;
138
}
139
```
140
141
**Usage Examples:**
142
143
```typescript
144
import { BasicTracerProvider, AlwaysOffSampler } from '@opentelemetry/sdk-trace-base';
145
146
// Disable all tracing
147
const provider = new BasicTracerProvider({
148
sampler: new AlwaysOffSampler()
149
});
150
151
// Conditional sampling based on environment
152
const sampler = process.env.NODE_ENV === 'test'
153
? new AlwaysOffSampler()
154
: new AlwaysOnSampler();
155
156
const provider = new BasicTracerProvider({ sampler });
157
```
158
159
### TraceIdRatioBasedSampler
160
161
Sampler that samples a deterministic fraction of traces based on trace ID, ensuring consistent sampling decisions across services.
162
163
```typescript { .api }
164
/**
165
* Sampler that samples a deterministic fraction of traces based on trace ID
166
*/
167
class TraceIdRatioBasedSampler implements Sampler {
168
/**
169
* @param ratio - Sampling ratio between 0.0 and 1.0 (default: 0)
170
*/
171
constructor(ratio?: number);
172
173
/**
174
* Makes sampling decision based on trace ID hash
175
* Same trace ID always produces the same decision
176
*/
177
shouldSample(
178
context: Context,
179
traceId: string,
180
spanName: string,
181
spanKind: SpanKind,
182
attributes: Attributes,
183
links: Link[]
184
): SamplingResult;
185
186
/**
187
* Returns "TraceIdRatioBased{ratio}"
188
*/
189
toString(): string;
190
}
191
```
192
193
**Behavior Details:**
194
- Ratio is normalized to be between 0.0 and 1.0
195
- Uses deterministic hash of trace ID for consistent decisions
196
- Same trace ID will always produce the same sampling decision across all services
197
- Ratio of 0.0 = never sample, 1.0 = always sample
198
199
**Usage Examples:**
200
201
```typescript
202
import { BasicTracerProvider, TraceIdRatioBasedSampler } from '@opentelemetry/sdk-trace-base';
203
204
// Sample 10% of traces
205
const provider = new BasicTracerProvider({
206
sampler: new TraceIdRatioBasedSampler(0.1)
207
});
208
209
// Sample 50% of traces
210
const provider = new BasicTracerProvider({
211
sampler: new TraceIdRatioBasedSampler(0.5)
212
});
213
214
// Environment-based sampling rate
215
const samplingRate = parseFloat(process.env.TRACE_SAMPLING_RATE || '0.1');
216
const provider = new BasicTracerProvider({
217
sampler: new TraceIdRatioBasedSampler(samplingRate)
218
});
219
220
// No sampling (equivalent to AlwaysOffSampler)
221
const noSampleProvider = new BasicTracerProvider({
222
sampler: new TraceIdRatioBasedSampler(0.0)
223
});
224
```
225
226
### ParentBasedSampler
227
228
Composite sampler that respects parent span's sampling decision when available, otherwise delegates to a root sampler. This ensures sampling consistency across distributed traces.
229
230
```typescript { .api }
231
/**
232
* Sampler that respects parent span sampling decisions with fallback samplers
233
*/
234
class ParentBasedSampler implements Sampler {
235
constructor(config: ParentBasedSamplerConfig);
236
237
/**
238
* Makes sampling decision based on parent context or delegates to appropriate sampler
239
*/
240
shouldSample(
241
context: Context,
242
traceId: string,
243
spanName: string,
244
spanKind: SpanKind,
245
attributes: Attributes,
246
links: Link[]
247
): SamplingResult;
248
249
/**
250
* Returns string representation with root sampler info
251
*/
252
toString(): string;
253
}
254
255
/**
256
* Configuration for ParentBasedSampler with different samplers for different scenarios
257
*/
258
interface ParentBasedSamplerConfig {
259
/** Required: Sampler to use when there is no parent span */
260
root: Sampler;
261
262
/** Sampler for remote parent that was sampled (default: AlwaysOnSampler) */
263
remoteParentSampled?: Sampler;
264
265
/** Sampler for remote parent that was not sampled (default: AlwaysOffSampler) */
266
remoteParentNotSampled?: Sampler;
267
268
/** Sampler for local parent that was sampled (default: AlwaysOnSampler) */
269
localParentSampled?: Sampler;
270
271
/** Sampler for local parent that was not sampled (default: AlwaysOffSampler) */
272
localParentNotSampled?: Sampler;
273
}
274
```
275
276
**Sampling Logic:**
277
1. If parent span exists and was sampled → delegate to appropriate sampled sampler
278
2. If parent span exists and was not sampled → delegate to appropriate not-sampled sampler
279
3. If no parent span exists → delegate to root sampler
280
4. Local vs remote parent determined by trace flags
281
282
**Usage Examples:**
283
284
```typescript
285
import {
286
BasicTracerProvider,
287
ParentBasedSampler,
288
TraceIdRatioBasedSampler,
289
AlwaysOnSampler,
290
AlwaysOffSampler
291
} from '@opentelemetry/sdk-trace-base';
292
293
// Basic parent-based sampling with ratio-based root
294
const provider = new BasicTracerProvider({
295
sampler: new ParentBasedSampler({
296
root: new TraceIdRatioBasedSampler(0.1) // 10% of new traces
297
})
298
});
299
300
// Advanced parent-based configuration
301
const provider = new BasicTracerProvider({
302
sampler: new ParentBasedSampler({
303
root: new TraceIdRatioBasedSampler(0.05), // 5% of new traces
304
remoteParentSampled: new AlwaysOnSampler(), // Always continue sampled remote traces
305
remoteParentNotSampled: new AlwaysOffSampler(), // Never sample unsampled remote traces
306
localParentSampled: new AlwaysOnSampler(), // Always continue sampled local traces
307
localParentNotSampled: new TraceIdRatioBasedSampler(0.01) // 1% chance to sample unsampled local
308
})
309
});
310
311
// Production-ready configuration
312
const provider = new BasicTracerProvider({
313
sampler: new ParentBasedSampler({
314
root: new TraceIdRatioBasedSampler(0.1), // Sample 10% of root traces
315
// Use defaults for parent-based decisions (respects parent sampling)
316
})
317
});
318
```
319
320
### Environment Configuration
321
322
Samplers can be configured through environment variables for runtime control.
323
324
**Environment Variables:**
325
- `OTEL_TRACES_SAMPLER` - Sampler type
326
- `OTEL_TRACES_SAMPLER_ARG` - Sampler argument (ratio for ratio-based samplers)
327
328
**Supported Sampler Values:**
329
- `always_off` → `AlwaysOffSampler`
330
- `always_on` → `AlwaysOnSampler`
331
- `traceidratio` → `TraceIdRatioBasedSampler` (requires `OTEL_TRACES_SAMPLER_ARG`)
332
- `parentbased_always_off` → `ParentBasedSampler` with `AlwaysOffSampler` root
333
- `parentbased_always_on` → `ParentBasedSampler` with `AlwaysOnSampler` root
334
- `parentbased_traceidratio` → `ParentBasedSampler` with `TraceIdRatioBasedSampler` root
335
336
**Usage Examples:**
337
338
```bash
339
# Set environment variables
340
export OTEL_TRACES_SAMPLER=traceidratio
341
export OTEL_TRACES_SAMPLER_ARG=0.1
342
343
# Or parent-based with ratio
344
export OTEL_TRACES_SAMPLER=parentbased_traceidratio
345
export OTEL_TRACES_SAMPLER_ARG=0.05
346
```
347
348
```typescript
349
// Configuration will be loaded from environment variables
350
const provider = new BasicTracerProvider({
351
// Sampler will be built from OTEL_TRACES_SAMPLER env var
352
// Other configuration can override env vars
353
resource: new Resource({
354
'service.name': 'my-service'
355
})
356
});
357
```
358
359
### Custom Sampler Implementation
360
361
You can implement custom samplers by implementing the Sampler interface.
362
363
**Usage Examples:**
364
365
```typescript
366
import { Sampler, SamplingResult, SamplingDecision } from '@opentelemetry/sdk-trace-base';
367
368
// Custom sampler that samples based on operation name
369
class OperationBasedSampler implements Sampler {
370
constructor(private sampledOperations: Set<string>) {}
371
372
shouldSample(
373
context: Context,
374
traceId: string,
375
spanName: string,
376
spanKind: SpanKind,
377
attributes: Attributes,
378
links: Link[]
379
): SamplingResult {
380
const decision = this.sampledOperations.has(spanName)
381
? SamplingDecision.RECORD_AND_SAMPLED
382
: SamplingDecision.NOT_RECORD;
383
384
return { decision };
385
}
386
387
toString(): string {
388
return `OperationBasedSampler{${Array.from(this.sampledOperations).join(',')}}`;
389
}
390
}
391
392
// Use custom sampler
393
const provider = new BasicTracerProvider({
394
sampler: new OperationBasedSampler(new Set([
395
'user-login',
396
'payment-process',
397
'critical-operation'
398
]))
399
});
400
```