client_java
GitHubToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage

Multi-Target Pattern

This is for the upcoming release 1.1.0.

To support multi-target pattern you can create a custom collector overriding the purposed internal method in ExtendedMultiCollector see SampleExtendedMultiCollector in io.prometheus.metrics.examples.httpserver

public class SampleExtendedMultiCollector extends ExtendedMultiCollector {

	public SampleExtendedMultiCollector() {
		super();
	}

	@Override
	protected MetricSnapshots collectMetricSnapshots(PrometheusScrapeRequest scrapeRequest) {

		GaugeSnapshot.Builder gaugeBuilder = GaugeSnapshot.builder();
		gaugeBuilder.name("x_load").help("process load");

		CounterSnapshot.Builder counterBuilder = CounterSnapshot.builder();
		counterBuilder.name(PrometheusNaming.sanitizeMetricName("x_calls_total")).help("invocations");

		String[] targetNames = scrapeRequest.getParameterValues("target");
		String targetName;
		String[] procs = scrapeRequest.getParameterValues("proc");
		if (targetNames == null || targetNames.length == 0) {
			targetName = "defaultTarget";
			procs = null; //ignore procs param
		} else {
			targetName = targetNames[0];
		}
		Builder counterDataPointBuilder = CounterSnapshot.CounterDataPointSnapshot.builder();
		io.prometheus.metrics.model.snapshots.GaugeSnapshot.GaugeDataPointSnapshot.Builder gaugeDataPointBuilder = GaugeSnapshot.GaugeDataPointSnapshot.builder();
		Labels lbls = Labels.of("target", targetName);

		if (procs == null || procs.length == 0) {
			counterDataPointBuilder.labels(lbls.merge(Labels.of("proc", "defaultProc")));
			gaugeDataPointBuilder.labels(lbls.merge(Labels.of("proc", "defaultProc")));
			counterDataPointBuilder.value(70);
			gaugeDataPointBuilder.value(Math.random());

			counterBuilder.dataPoint(counterDataPointBuilder.build());
			gaugeBuilder.dataPoint(gaugeDataPointBuilder.build());

		} else {
			for (int i = 0; i < procs.length; i++) {
				counterDataPointBuilder.labels(lbls.merge(Labels.of("proc", procs[i])));
				gaugeDataPointBuilder.labels(lbls.merge(Labels.of("proc", procs[i])));
				counterDataPointBuilder.value(Math.random());
				gaugeDataPointBuilder.value(Math.random());

				counterBuilder.dataPoint(counterDataPointBuilder.build());
				gaugeBuilder.dataPoint(gaugeDataPointBuilder.build());
			}
		}
		Collection<MetricSnapshot> snaps = new ArrayList<MetricSnapshot>();
		snaps.add(counterBuilder.build());
		snaps.add(gaugeBuilder.build());
		MetricSnapshots msnaps = new MetricSnapshots(snaps);
		return msnaps;
	}

	public List<String> getPrometheusNames() {
		List<String> names = new ArrayList<String>();
		names.add("x_calls_total");
		names.add("x_load");
		return names;
	}

}

PrometheusScrapeRequest provides methods to access http-related infos from the request originally received by the endpoint

public interface PrometheusScrapeRequest {
	String getRequestURI();

	String[] getParameterValues(String name);
}

Sample Prometheus scrape_config

  - job_name: "multi-target"

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.
    params:
      proc: [proc1, proc2]
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: localhost:9401 
    static_configs:
      - targets: ["target1", "target2"]

It’s up to the specific MultiCollector implementation how to interpret the target parameter. It might be an explicit real target (i.e. via host name/ip address) or as an alias in some internal configuration. The latter is more suitable when the MultiCollector implementation is a proxy (see https://github.com/prometheus/snmp_exporter) In this case, invoking real target might require extra parameters (e.g. credentials) that might be complex to manage in Prometheus configuration (not considering the case where the proxy might become an “open relay”)