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