001package io.prometheus.metrics.expositionformats;
002
003import io.prometheus.metrics.annotations.StableApi;
004import io.prometheus.metrics.config.EscapingScheme;
005import io.prometheus.metrics.model.snapshots.MetricSnapshots;
006import java.io.IOException;
007import java.io.OutputStream;
008import javax.annotation.Nullable;
009
010/**
011 * Write the Prometheus protobuf format as defined in <a
012 * href="https://github.com/prometheus/client_model/tree/master/io/prometheus/client">github.com/prometheus/client_model</a>.
013 *
014 * <p>As of today, this is the only exposition format that supports native histograms.
015 */
016@StableApi
017public class PrometheusProtobufWriter implements ExpositionFormatWriter {
018
019  @Nullable private static final ExpositionFormatWriter DELEGATE = createProtobufWriter();
020
021  public static final String CONTENT_TYPE =
022      "application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; "
023          + "encoding=delimited";
024
025  @Nullable
026  private static ExpositionFormatWriter createProtobufWriter() {
027    try {
028      return Class.forName(
029              "io.prometheus.metrics.expositionformats.internal.PrometheusProtobufWriterImpl")
030          .asSubclass(ExpositionFormatWriter.class)
031          .getDeclaredConstructor()
032          .newInstance();
033    } catch (Exception e) {
034      // not in classpath
035      return null;
036    }
037  }
038
039  @Override
040  public boolean accepts(@Nullable String acceptHeader) {
041    if (acceptHeader == null) {
042      return false;
043    } else {
044      return acceptHeader.contains("application/vnd.google.protobuf")
045          && acceptHeader.contains("proto=io.prometheus.client.MetricFamily");
046    }
047  }
048
049  @Override
050  public String getContentType() {
051    return CONTENT_TYPE;
052  }
053
054  @Override
055  public boolean isAvailable() {
056    return DELEGATE != null;
057  }
058
059  @Override
060  public String toDebugString(MetricSnapshots metricSnapshots, EscapingScheme escapingScheme) {
061    return getDelegate().toDebugString(metricSnapshots, escapingScheme);
062  }
063
064  @Override
065  public void write(
066      OutputStream out, MetricSnapshots metricSnapshots, EscapingScheme escapingScheme)
067      throws IOException {
068    getDelegate().write(out, metricSnapshots, escapingScheme);
069  }
070
071  private ExpositionFormatWriter getDelegate() {
072    if (DELEGATE == null) {
073      throw new UnsupportedOperationException("Prometheus protobuf writer not available");
074    }
075    return DELEGATE;
076  }
077}