Sampling
Sampling
Trace data is often produced in large volumes, it is not only expensive to collect and store but also expensive to transmit.
In order to strike a balance between observability and expenses, traces are sampled. Sampling is the process by which a decision is made on whether to process/export a span or not.
Samplers
OpenCensus provides these types of samplers
A sampler’s decision affects Span.TraceOptions’ sampling bit by setting or clearing it if the sampler returns True or False respectively.
There are 2 ways of setting a sampler to use:
Global sampler
The global sampler is a sampler that’s set via the global TraceConfig
package main
import "go.opencensus.io/trace"
func main() {
// Having already created your sampler "theSampler"
trace.ApplyConfig(trace.Config{DefaultSampler: theSampler})
}
package io.opencensus.tutorials.tracing.sampling;
import io.opencensus.trace.config.TraceConfig;
public class App {
public static void main(String[] args) {
// Get the global TraceConfig
TraceConfig globalTraceConfig = Tracing.getTraceConfig();
// Now update the global TraceConfig
globalTraceConfig.updateActiveTraceParams(
traceConfig.getActiveTraceParams().toBuilder.setSampler(theSampler));
}
}
#include "opencensus/trace/sampler.h"
#include "opencensus/trace/trace_config.h"
#include "opencensus/trace/trace_params.h"
int main(int argc, char** argv) {
opencensus::trace::ProbabilitySampler theSampler(theProbability);
const struct opencensus::trace::TraceParams globalConfig = {
.sampler=theSampler,
};
opencensus::trace::TraceConfig::SetCurrentTraceParams(globalConfig);
}
Per span sampler aka “Span scoped”
This sampler is set when starting a span, via the constructor
import "go.opencensus.io/trace"
func doWork() {
// Having already created your sampler "theSampler" and "ctx"
ctx, span := trace.StartSpan(ctx, "DoWork", trace.WithSampler(theSampler))
}
package io.opencensus.tutorials.tracing.sampling;
import io.opencensus.trace.common.Scope;
void doWork() {
// Having already defined "theSampler" and "tracer"
try (Scope ss = tracer.spanBuilder("DoWork").setSampler(theSampler).startScopedSpan()){
}
}
void doWork() {
// Having already defined "theSampler"
opencensus::trace::Span theSpan = \
opencensus::trace::Span::StartSpan("DoWork", nullptr, {&theSampler});
}
Rules
- A sampling decision from a ParentSpan is ALWAYS inherited by all its regardless of the trace configuration. This ensures continuity of traces – for example, if a parent were sampled but one of its children were not, we’d then lose parts of the trace, and vice versa if the parent weren’t sampled yet one of its children were, we wouldn’t know where the span began
References
Resource | URL |
---|---|
TraceConfig in specs | specs/trace/TraceConfig |
Per-Span sampler in specs | specs/trace/Sampling |
GoDoc: ApplyConfig | trace.ApplyConfig |
JavaDoc: TraceConfig | io.opencensus.trace.config.TraceConfig |
C++: TraceConfig | opencensus::trace::TraceConfig |