Class ExemplarSampler

java.lang.Object
io.prometheus.metrics.core.exemplars.ExemplarSampler

public class ExemplarSampler extends Object
The ExemplarSampler selects Spans as exemplars.

There are two types of Exemplars: Regular exemplars are sampled implicitly if a supported tracing library is detected. Custom exemplars are provided explicitly in code, for example if a developer wants to make sure an Exemplar is created for a specific code path.

Spans will be marked as being an Exemplar by calling SpanContext.markCurrentSpanAsExemplar(). The tracer implementation should set a Span attribute to mark the current Span as an Exemplar. This attribute can be used by a trace sampling algorithm to make sure traces with Exemplars are sampled.

The ExemplarSample is rate-limited, so only a small fraction of Spans will be marked as Exemplars in an application with a large number of requests.

See ExemplarSamplerConfig for configuration options.

  • Field Details

    • config

      private final ExemplarSamplerConfig config
    • exemplars

      private final Exemplar[] exemplars
    • customExemplars

      private final Exemplar[] customExemplars
    • acceptingNewExemplars

      private final AtomicBoolean acceptingNewExemplars
    • acceptingNewCustomExemplars

      private final AtomicBoolean acceptingNewCustomExemplars
    • spanContext

      private final SpanContext spanContext
  • Constructor Details

    • ExemplarSampler

      public ExemplarSampler(ExemplarSamplerConfig config)
    • ExemplarSampler

      public ExemplarSampler(ExemplarSamplerConfig config, SpanContext spanContext)
      Constructor with an additional {code spanContext} argument. This is useful for testing, but may also be useful in some production scenarios. If spanContext != null that spanContext is used and SpanContextSupplier is not used. If spanContext == null SpanContextSupplier.getSpanContext() is called to find a span context.
  • Method Details

    • collect

      public Exemplars collect()
    • reset

      public void reset()
    • observe

      public void observe(double value)
    • observeWithExemplar

      public void observeWithExemplar(double value, Labels labels)
    • doObserve

      private long doObserve(double value)
    • doObserveSingleExemplar

      private long doObserveSingleExemplar(double value)
    • doObserveSingleExemplar

      private long doObserveSingleExemplar(double amount, Labels labels)
    • doObserveWithUpperBounds

      private long doObserveWithUpperBounds(double value, double[] classicUpperBounds)
    • doObserveWithoutUpperBounds

      private long doObserveWithoutUpperBounds(double value)
    • doObserveWithExemplar

      private long doObserveWithExemplar(double amount, Labels labels)
    • doObserveWithExemplarWithUpperBounds

      private long doObserveWithExemplarWithUpperBounds(double value, Labels labels, double[] classicUpperBounds)
    • doObserveWithExemplarWithoutUpperBounds

      private long doObserveWithExemplarWithoutUpperBounds(double amount, Labels labels)
    • rateLimitedObserve

      private void rateLimitedObserve(AtomicBoolean accepting, double value, LongSupplier observeFunc)
      Observing requires a system call to System.currentTimeMillis(), and it requires iterating over the existing exemplars to check if one of the existing exemplars can be replaced.

      To avoid performance issues, we rate limit observing exemplars to ExemplarSamplerConfig.getSampleIntervalMillis() milliseconds.

    • durationUntilNextExemplarExpires

      private long durationUntilNextExemplarExpires(long now)
    • updateCustomExemplar

      private long updateCustomExemplar(int index, double value, Labels labels, long now)
    • updateExemplar

      private long updateExemplar(int index, double value, long now)
    • doSampleExemplar

      private Labels doSampleExemplar()
    • getSpanContextFromInitializer

      private static SpanContext getSpanContextFromInitializer()