001package io.prometheus.metrics.core.exemplars;
002
003import io.prometheus.metrics.annotations.StableApi;
004import io.prometheus.metrics.model.snapshots.Labels;
005import java.util.concurrent.atomic.AtomicReference;
006import java.util.function.Supplier;
007import javax.annotation.Nullable;
008
009/**
010 * Global holder for a {@link Supplier} of additional {@link Labels} that are merged into every
011 * automatically-sampled Exemplar across the entire application.
012 *
013 * <p>This is the global counterpart to the per-metric {@code exemplarLabelsSupplier(...)} builder
014 * method. Registering a supplier here affects <em>all</em> metrics, including metrics registered by
015 * third-party libraries that the application does not control. This makes it the right tool when
016 * you cannot modify the code that creates the metrics.
017 *
018 * <p>The supplier is invoked on the metric hot path (rate-limited by the exemplar sampler), each
019 * time an Exemplar is sampled from a valid, sampled span context. It should therefore be cheap and
020 * non-blocking. It may return dynamic, request-scoped values, for example an identifier read from a
021 * thread-local:
022 *
023 * <pre>{@code
024 * ExemplarLabelsSupplier.setExemplarLabelsSupplier(
025 *     () -> Labels.of("management_id", currentManagementId()));
026 * }</pre>
027 *
028 * <p>Labels returned by the supplier that collide with {@code trace_id}/{@code span_id} (or, when a
029 * per-metric supplier is also configured, with that supplier's labels) are silently dropped rather
030 * than causing an error: the per-metric supplier takes precedence over the global one, and the
031 * reserved {@code trace_id}/{@code span_id} labels always win. If the supplier throws, the
032 * exception is swallowed and the Exemplar is created without the additional labels, so a
033 * misbehaving supplier never breaks metric collection.
034 */
035@StableApi
036public class ExemplarLabelsSupplier {
037
038  private static final AtomicReference<Supplier<Labels>> supplierRef = new AtomicReference<>();
039
040  private ExemplarLabelsSupplier() {}
041
042  /**
043   * Register a global supplier of additional exemplar labels. Pass {@code null} to remove a
044   * previously registered supplier. The most recently registered supplier wins.
045   */
046  public static void setExemplarLabelsSupplier(@Nullable Supplier<Labels> supplier) {
047    supplierRef.set(supplier);
048  }
049
050  /** Returns the registered global supplier, or {@code null} if none has been set. */
051  @Nullable
052  public static Supplier<Labels> getExemplarLabelsSupplier() {
053    return supplierRef.get();
054  }
055}