001package io.prometheus.metrics.expositionformats;
002
003import io.prometheus.metrics.annotations.StableApi;
004import io.prometheus.metrics.config.ExporterProperties;
005import io.prometheus.metrics.config.OpenMetrics2Properties;
006import io.prometheus.metrics.config.PrometheusProperties;
007import javax.annotation.Nullable;
008
009@StableApi
010public class ExpositionFormats {
011
012  private final PrometheusProtobufWriter prometheusProtobufWriter;
013  private final PrometheusTextFormatWriter prometheusTextFormatWriter;
014  private final OpenMetricsTextFormatWriter openMetricsTextFormatWriter;
015  private final OpenMetrics2TextFormatWriter openMetrics2TextFormatWriter;
016
017  private ExpositionFormats(
018      PrometheusProtobufWriter prometheusProtobufWriter,
019      PrometheusTextFormatWriter prometheusTextFormatWriter,
020      OpenMetricsTextFormatWriter openMetricsTextFormatWriter,
021      OpenMetrics2TextFormatWriter openMetrics2TextFormatWriter) {
022    this.prometheusProtobufWriter = prometheusProtobufWriter;
023    this.prometheusTextFormatWriter = prometheusTextFormatWriter;
024    this.openMetricsTextFormatWriter = openMetricsTextFormatWriter;
025    this.openMetrics2TextFormatWriter = openMetrics2TextFormatWriter;
026  }
027
028  public static ExpositionFormats init() {
029    return init(PrometheusProperties.get());
030  }
031
032  @SuppressWarnings("deprecation")
033  public static ExpositionFormats init(PrometheusProperties properties) {
034    ExporterProperties exporterProps = properties.getExporterProperties();
035    OpenMetrics2Properties om2Props = properties.getOpenMetrics2Properties();
036
037    return new ExpositionFormats(
038        new PrometheusProtobufWriter(),
039        PrometheusTextFormatWriter.builder()
040            .setIncludeCreatedTimestamps(exporterProps.getIncludeCreatedTimestamps())
041            .setTimestampsInMs(exporterProps.getPrometheusTimestampsInMs())
042            .build(),
043        OpenMetricsTextFormatWriter.builder()
044            .setCreatedTimestampsEnabled(exporterProps.getIncludeCreatedTimestamps())
045            .setExemplarsOnAllMetricTypesEnabled(exporterProps.getExemplarsOnAllMetricTypes())
046            .build(),
047        OpenMetrics2TextFormatWriter.builder()
048            .setOpenMetrics2Properties(om2Props)
049            .setCreatedTimestampsEnabled(exporterProps.getIncludeCreatedTimestamps())
050            .setExemplarsOnAllMetricTypesEnabled(exporterProps.getExemplarsOnAllMetricTypes())
051            .build());
052  }
053
054  /**
055   * @deprecated Use {@link #init(PrometheusProperties)} instead.
056   */
057  @Deprecated
058  @SuppressWarnings({"InlineMeSuggester"})
059  public static ExpositionFormats init(ExporterProperties properties) {
060    return init(PrometheusProperties.builder().exporterProperties(properties).build());
061  }
062
063  public ExpositionFormatWriter findWriter(@Nullable String acceptHeader) {
064    if (prometheusProtobufWriter.accepts(acceptHeader)) {
065      return prometheusProtobufWriter;
066    }
067
068    if (isOpenMetrics2Enabled() && openMetrics2TextFormatWriter.accepts(acceptHeader)) {
069      if (openMetrics2TextFormatWriter.getOpenMetrics2Properties().getContentNegotiation()) {
070        String version = parseOpenMetricsVersion(acceptHeader);
071        if ("2.0.0".equals(version)) {
072          return openMetrics2TextFormatWriter;
073        }
074        // version=1.0.0 or no version: fall through to OM1.
075      } else {
076        // contentNegotiation=false: OM2 handles all OpenMetrics requests.
077        return openMetrics2TextFormatWriter;
078      }
079    }
080
081    if (openMetricsTextFormatWriter.accepts(acceptHeader)) {
082      return openMetricsTextFormatWriter;
083    }
084
085    return prometheusTextFormatWriter;
086  }
087
088  private boolean isOpenMetrics2Enabled() {
089    return openMetrics2TextFormatWriter.getOpenMetrics2Properties().getEnabled();
090  }
091
092  public PrometheusProtobufWriter getPrometheusProtobufWriter() {
093    return prometheusProtobufWriter;
094  }
095
096  public PrometheusTextFormatWriter getPrometheusTextFormatWriter() {
097    return prometheusTextFormatWriter;
098  }
099
100  public OpenMetricsTextFormatWriter getOpenMetricsTextFormatWriter() {
101    return openMetricsTextFormatWriter;
102  }
103
104  public OpenMetrics2TextFormatWriter getOpenMetrics2TextFormatWriter() {
105    return openMetrics2TextFormatWriter;
106  }
107
108  @Nullable
109  private static String parseOpenMetricsVersion(@Nullable String acceptHeader) {
110    if (acceptHeader == null) {
111      return null;
112    }
113    for (String mediaType : acceptHeader.split(",")) {
114      if (mediaType.contains("application/openmetrics-text")) {
115        for (String param : mediaType.split(";")) {
116          String[] tokens = param.split("=");
117          if (tokens.length == 2) {
118            String key = tokens[0].trim();
119            String value = tokens[1].trim();
120            if (key.equals("version")) {
121              return value;
122            }
123          }
124        }
125        return null;
126      }
127    }
128    return null;
129  }
130}