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