001package io.prometheus.client.servlet.common.exporter;
002
003import io.prometheus.client.CollectorRegistry;
004import io.prometheus.client.SampleNameFilter;
005import io.prometheus.client.Predicate;
006import io.prometheus.client.servlet.common.adapter.HttpServletRequestAdapter;
007import io.prometheus.client.servlet.common.adapter.HttpServletResponseAdapter;
008import io.prometheus.client.exporter.common.TextFormat;
009import io.prometheus.client.servlet.common.adapter.ServletConfigAdapter;
010
011import java.io.BufferedWriter;
012import java.io.IOException;
013import java.io.Writer;
014import java.util.Arrays;
015import java.util.Collections;
016import java.util.HashSet;
017import java.util.List;
018import java.util.Set;
019
020/**
021 * The MetricsServlet class exists to provide a simple way of exposing the metrics values.
022 */
023public class Exporter {
024
025  public static final String NAME_MUST_BE_EQUAL_TO = "name-must-be-equal-to";
026  public static final String NAME_MUST_NOT_BE_EQUAL_TO = "name-must-not-be-equal-to";
027  public static final String NAME_MUST_START_WITH = "name-must-start-with";
028  public static final String NAME_MUST_NOT_START_WITH = "name-must-not-start-with";
029
030  private CollectorRegistry registry;
031  private Predicate<String> sampleNameFilter;
032
033  /**
034   * Construct a MetricsServlet for the given registry.
035   * @param registry collector registry
036   * @param sampleNameFilter programmatically set a {@link SampleNameFilter}.
037   *                         If there are any filter options configured in {@code ServletConfig}, they will be merged
038   *                         so that samples need to pass both filters to be exported.
039   *                         sampleNameFilter may be {@code null} indicating that nothing should be filtered.
040   */
041  public Exporter(CollectorRegistry registry, Predicate<String> sampleNameFilter) {
042    this.registry = registry;
043    this.sampleNameFilter = sampleNameFilter;
044  }
045
046  public void init(ServletConfigAdapter servletConfig) throws ServletConfigurationException {
047    List<String> allowedNames = SampleNameFilter.stringToList(servletConfig.getInitParameter(NAME_MUST_BE_EQUAL_TO));
048    List<String> excludedNames = SampleNameFilter.stringToList(servletConfig.getInitParameter(NAME_MUST_NOT_BE_EQUAL_TO));
049    List<String> allowedPrefixes = SampleNameFilter.stringToList(servletConfig.getInitParameter(NAME_MUST_START_WITH));
050    List<String> excludedPrefixes = SampleNameFilter.stringToList(servletConfig.getInitParameter(NAME_MUST_NOT_START_WITH));
051    if (!allowedPrefixes.isEmpty() || !excludedPrefixes.isEmpty() || !allowedNames.isEmpty() || !excludedNames.isEmpty()) {
052      SampleNameFilter filter = new SampleNameFilter.Builder()
053              .nameMustBeEqualTo(allowedNames)
054              .nameMustNotBeEqualTo(excludedNames)
055              .nameMustStartWith(allowedPrefixes)
056              .nameMustNotStartWith(excludedPrefixes)
057              .build();
058      if (this.sampleNameFilter != null) {
059        this.sampleNameFilter = filter.and(this.sampleNameFilter);
060      } else {
061        this.sampleNameFilter = filter;
062      }
063    }
064  }
065
066  public void doGet(final HttpServletRequestAdapter req, final HttpServletResponseAdapter resp) throws IOException {
067    resp.setStatus(200);
068    String contentType = TextFormat.chooseContentType(req.getHeader("Accept"));
069    resp.setContentType(contentType);
070
071    Writer writer = new BufferedWriter(resp.getWriter());
072    try {
073      Predicate<String> filter = SampleNameFilter.restrictToNamesEqualTo(sampleNameFilter, parse(req));
074      if (filter == null) {
075        TextFormat.writeFormat(contentType, writer, registry.metricFamilySamples());
076      } else {
077        TextFormat.writeFormat(contentType, writer, registry.filteredMetricFamilySamples(filter));
078      }
079      writer.flush();
080    } finally {
081      writer.close();
082    }
083  }
084
085  private Set<String> parse(HttpServletRequestAdapter req) {
086    String[] includedParam = req.getParameterValues("name[]");
087    if (includedParam == null) {
088      return Collections.emptySet();
089    } else {
090      return new HashSet<String>(Arrays.asList(includedParam));
091    }
092  }
093
094  public void doPost(final HttpServletRequestAdapter req, final HttpServletResponseAdapter resp)
095          throws IOException {
096    doGet(req, resp);
097  }
098}