001package io.prometheus.metrics.instrumentation.dropwizard5.labels; 002 003import io.prometheus.metrics.model.snapshots.Labels; 004import java.util.ArrayList; 005import java.util.List; 006import java.util.Map; 007 008/** 009 * A LabelMapper to allow Dropwizard metrics to be translated to Prometheus metrics including custom 010 * labels and names. Prometheus metric name and labels are extracted from the Dropwizard name based 011 * on the provided list of {@link MapperConfig}s. The FIRST matching config will be used. 012 */ 013public class CustomLabelMapper { 014 private final List<CompiledMapperConfig> compiledMapperConfigs; 015 016 public CustomLabelMapper(final List<MapperConfig> mapperConfigs) { 017 if (mapperConfigs == null || mapperConfigs.isEmpty()) { 018 throw new IllegalArgumentException("CustomLabelMapper needs some mapper configs!"); 019 } 020 021 this.compiledMapperConfigs = new ArrayList<CompiledMapperConfig>(mapperConfigs.size()); 022 for (MapperConfig config : mapperConfigs) { 023 this.compiledMapperConfigs.add(new CompiledMapperConfig(config)); 024 } 025 } 026 027 public String getName(final String dropwizardName) { 028 if (dropwizardName == null) { 029 throw new IllegalArgumentException("Dropwizard metric name cannot be null"); 030 } 031 032 CompiledMapperConfig matchingConfig = null; 033 for (CompiledMapperConfig config : this.compiledMapperConfigs) { 034 if (config.pattern.matches(dropwizardName)) { 035 matchingConfig = config; 036 break; 037 } 038 } 039 040 if (matchingConfig != null) { 041 final Map<String, String> params = matchingConfig.pattern.extractParameters(dropwizardName); 042 final NameAndLabels nameAndLabels = getNameAndLabels(matchingConfig.mapperConfig, params); 043 return nameAndLabels.name; 044 } 045 046 return dropwizardName; 047 } 048 049 public Labels getLabels( 050 final String dropwizardName, 051 final List<String> additionalLabelNames, 052 final List<String> additionalLabelValues) { 053 if (dropwizardName == null) { 054 throw new IllegalArgumentException("Dropwizard metric name cannot be null"); 055 } 056 057 CompiledMapperConfig matchingConfig = null; 058 for (CompiledMapperConfig config : this.compiledMapperConfigs) { 059 if (config.pattern.matches(dropwizardName)) { 060 matchingConfig = config; 061 break; 062 } 063 } 064 065 if (matchingConfig != null) { 066 final Map<String, String> params = matchingConfig.pattern.extractParameters(dropwizardName); 067 final NameAndLabels nameAndLabels = getNameAndLabels(matchingConfig.mapperConfig, params); 068 nameAndLabels.labelNames.addAll(additionalLabelNames); 069 nameAndLabels.labelValues.addAll(additionalLabelValues); 070 return Labels.of(nameAndLabels.labelNames, nameAndLabels.labelValues); 071 } 072 073 return Labels.of(additionalLabelNames, additionalLabelValues); 074 } 075 076 protected NameAndLabels getNameAndLabels( 077 final MapperConfig config, final Map<String, String> parameters) { 078 final String metricName = formatTemplate(config.getName(), parameters); 079 final List<String> labels = new ArrayList<String>(config.getLabels().size()); 080 final List<String> labelValues = new ArrayList<String>(config.getLabels().size()); 081 for (Map.Entry<String, String> entry : config.getLabels().entrySet()) { 082 labels.add(entry.getKey()); 083 labelValues.add(formatTemplate(entry.getValue(), parameters)); 084 } 085 086 return new NameAndLabels(metricName, labels, labelValues); 087 } 088 089 private String formatTemplate(final String template, final Map<String, String> params) { 090 String result = template; 091 for (Map.Entry<String, String> entry : params.entrySet()) { 092 result = result.replace(entry.getKey(), entry.getValue()); 093 } 094 095 return result; 096 } 097 098 static class CompiledMapperConfig { 099 final MapperConfig mapperConfig; 100 final GraphiteNamePattern pattern; 101 102 CompiledMapperConfig(final MapperConfig mapperConfig) { 103 this.mapperConfig = mapperConfig; 104 this.pattern = new GraphiteNamePattern(mapperConfig.getMatch()); 105 } 106 } 107 108 static class NameAndLabels { 109 final String name; 110 final List<String> labelNames; 111 final List<String> labelValues; 112 113 NameAndLabels( 114 final String name, final List<String> labelNames, final List<String> labelValues) { 115 this.name = name; 116 this.labelNames = labelNames; 117 this.labelValues = labelValues; 118 } 119 } 120}