4. Sampling

Sampling may be employed to reduce the data collected and reported out of process. When a span isn’t sampled, it adds no overhead (noop).

Sampling is an up-front decision, meaning that the decision to report data is made at the first operation in a trace, and that decision is propagated downstream.

By default, there’s a global sampler that applies a single rate to all traced operations. Tracer.Builder.sampler is how you indicate this, and it defaults to trace every request.

4.1 Declarative sampling

Some need to sample based on the type or annotations of a java method.

Most users will use a framework interceptor which automates this sort of policy. Here’s how they might work internally.

// derives a sample rate from an annotation on a java method
DeclarativeSampler<Traced> sampler = DeclarativeSampler.create(Traced::sampleRate);

@Around("@annotation(traced)")
public Object traceThing(ProceedingJoinPoint pjp, Traced traced) throws Throwable {
  Span span = tracing.tracer().newTrace(sampler.sample(traced))...
  try {
    return pjp.proceed();
  } finally {
    span.finish();
  }
}

4.2 Custom sampling

You may want to apply different policies depending on what the operation is. For example, you might not want to trace requests to static resources such as images, or you might want to trace all requests to a new api.

Most users will use a framework interceptor which automates this sort of policy. Here’s how they might work internally.

Span newTrace(Request input) {
  SamplingFlags flags = SamplingFlags.NONE;
  if (input.url().startsWith("/experimental")) {
    flags = SamplingFlags.SAMPLED;
  } else if (input.url().startsWith("/static")) {
    flags = SamplingFlags.NOT_SAMPLED;
  }
  return tracer.newTrace(flags);
}

Note: the above is the basis for the built-in http sampler

4.3 Sampling in Spring Cloud Sleuth

Spring Cloud Sleuth by default sets all spans to non-exportable. That means that you will see traces in logs, but not in any remote store. For testing the default is often enough, and it probably is all you need if you are only using the logs (e.g. with an ELK aggregator). If you are exporting span data to Zipkin, there is also an Sampler.ALWAYS_SAMPLE that exports everything and a ProbabilityBasedSampler that samples a fixed fraction of spans.

[Note]Note

The ProbabilityBasedSampler is the default if you are using spring-cloud-sleuth-zipkin. You can configure the exports using spring.sleuth.sampler.probability. The passed value needs to be a double from 0.0 to 1.0.

A sampler can be installed just by creating a bean definition, e.g:

@Bean
public Sampler defaultSampler() {
	return Sampler.ALWAYS_SAMPLE;
}
[Tip]Tip

You can set the HTTP header X-B3-Flags to 1 or when doing messaging you can set spanFlags header to 1. Then the current span will be forced to be exportable regardless of the sampling decision.