001package io.prometheus.metrics.model.snapshots;
002
003import io.prometheus.metrics.config.EscapingScheme;
004import java.util.ArrayList;
005import java.util.List;
006import javax.annotation.Nullable;
007
008public class SnapshotEscaper {
009
010  private SnapshotEscaper() {}
011
012  /** Escapes the given metric names and labels with the given escaping scheme. */
013  public static MetricSnapshot escapeMetricSnapshot(MetricSnapshot v, EscapingScheme scheme) {
014    if (scheme == EscapingScheme.ALLOW_UTF8 || scheme == EscapingScheme.UNDERSCORE_ESCAPING) {
015      // we re-use the prometheus name for underscore escaping as an optimization
016      return v;
017    }
018
019    List<DataPointSnapshot> outDataPoints = new ArrayList<>();
020
021    for (DataPointSnapshot d : v.getDataPoints()) {
022      if (snapshotNeedsEscaping(d, scheme)) {
023        outDataPoints.add(d.escape(scheme));
024      } else {
025        outDataPoints.add(d);
026      }
027    }
028
029    return v.escape(scheme, outDataPoints);
030  }
031
032  static boolean snapshotNeedsEscaping(DataPointSnapshot d, EscapingScheme scheme) {
033    Labels labels = d.getLabels();
034    if (labelsNeedsEscaping(labels, scheme)) {
035      return true;
036    }
037    if (d instanceof SummarySnapshot.SummaryDataPointSnapshot) {
038      return exemplarsNeedsEscaping(
039          ((SummarySnapshot.SummaryDataPointSnapshot) d).getExemplars(), scheme);
040    }
041    if (d instanceof HistogramSnapshot.HistogramDataPointSnapshot) {
042      return exemplarsNeedsEscaping(
043          ((HistogramSnapshot.HistogramDataPointSnapshot) d).getExemplars(), scheme);
044    }
045    if (d instanceof CounterSnapshot.CounterDataPointSnapshot) {
046      return exemplarNeedsEscaping(
047          ((CounterSnapshot.CounterDataPointSnapshot) d).getExemplar(), scheme);
048    }
049    if (d instanceof UnknownSnapshot.UnknownDataPointSnapshot) {
050      return exemplarNeedsEscaping(
051          ((UnknownSnapshot.UnknownDataPointSnapshot) d).getExemplar(), scheme);
052    }
053    if (d instanceof GaugeSnapshot.GaugeDataPointSnapshot) {
054      return exemplarNeedsEscaping(
055          ((GaugeSnapshot.GaugeDataPointSnapshot) d).getExemplar(), scheme);
056    }
057
058    return false;
059  }
060
061  private static boolean labelsNeedsEscaping(Labels labels, EscapingScheme scheme) {
062    for (Label l : labels) {
063      if (PrometheusNaming.needsEscaping(l.getName(), scheme)) {
064        return true;
065      }
066    }
067    return false;
068  }
069
070  private static boolean exemplarNeedsEscaping(@Nullable Exemplar exemplar, EscapingScheme scheme) {
071    return exemplar != null && labelsNeedsEscaping(exemplar.getLabels(), scheme);
072  }
073
074  private static boolean exemplarsNeedsEscaping(Exemplars exemplars, EscapingScheme scheme) {
075    for (Exemplar exemplar : exemplars) {
076      if (labelsNeedsEscaping(exemplar.getLabels(), scheme)) {
077        return true;
078      }
079    }
080    return false;
081  }
082
083  public static String getSnapshotLabelName(Labels labels, int index, EscapingScheme scheme) {
084    if (scheme == EscapingScheme.UNDERSCORE_ESCAPING) {
085      return labels.getPrometheusName(index);
086    } else {
087      return labels.getName(index);
088    }
089  }
090
091  public static String getMetadataName(MetricMetadata metadata, EscapingScheme scheme) {
092    if (scheme == EscapingScheme.UNDERSCORE_ESCAPING) {
093      return metadata.getPrometheusName();
094    } else {
095      return metadata.getName();
096    }
097  }
098
099  public static Labels escapeLabels(Labels labels, EscapingScheme scheme) {
100    Labels.Builder outLabelsBuilder = Labels.builder();
101
102    for (Label l : labels) {
103      outLabelsBuilder.label(PrometheusNaming.escapeName(l.getName(), scheme), l.getValue());
104    }
105
106    return outLabelsBuilder.build();
107  }
108
109  public static Exemplars escapeExemplars(Exemplars exemplars, EscapingScheme scheme) {
110    List<Exemplar> escapedExemplars = new ArrayList<>(exemplars.size());
111    for (Exemplar exemplar : exemplars) {
112      escapedExemplars.add(escapeExemplar(exemplar, scheme));
113    }
114    return Exemplars.of(escapedExemplars);
115  }
116
117  @Nullable
118  public static Exemplar escapeExemplar(@Nullable Exemplar exemplar, EscapingScheme scheme) {
119    if (exemplar == null) {
120      return null;
121    }
122    return Exemplar.builder()
123        .labels(escapeLabels(exemplar.getLabels(), scheme))
124        .timestampMillis(exemplar.getTimestampMillis())
125        .value(exemplar.getValue())
126        .build();
127  }
128}