001/* 002 * Copyright (C) 2024-present The Prometheus jmx_exporter Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package io.prometheus.jmx; 018 019import io.prometheus.jmx.logger.Logger; 020import io.prometheus.jmx.logger.LoggerFactory; 021import io.prometheus.metrics.model.snapshots.*; 022import java.util.*; 023import java.util.logging.Level; 024 025public class MatchedRuleToMetricSnapshotsConverter { 026 027 private static final Logger LOGGER = 028 LoggerFactory.getLogger(MatchedRuleToMetricSnapshotsConverter.class); 029 030 private static final String OBJECTNAME = "_objectname"; 031 032 public static MetricSnapshots convert(List<MatchedRule> matchedRules) { 033 Map<String, List<MatchedRule>> rulesByPrometheusMetricName = new HashMap<>(); 034 035 for (MatchedRule matchedRule : matchedRules) { 036 List<MatchedRule> matchedRulesWithSameName = 037 rulesByPrometheusMetricName.computeIfAbsent( 038 matchedRule.name, name -> new ArrayList<>()); 039 matchedRulesWithSameName.add(matchedRule); 040 } 041 042 if (LOGGER.isLoggable(Level.FINE)) { 043 rulesByPrometheusMetricName 044 .values() 045 .forEach( 046 matchedRules1 -> 047 matchedRules1.forEach( 048 matchedRule -> 049 LOGGER.log( 050 Level.FINE, 051 "matchedRule %s", 052 matchedRule))); 053 } 054 055 MetricSnapshots.Builder result = MetricSnapshots.builder(); 056 for (List<MatchedRule> rulesWithSameName : rulesByPrometheusMetricName.values()) { 057 result.metricSnapshot(convertRulesWithSameName(rulesWithSameName)); 058 } 059 return result.build(); 060 } 061 062 private static MetricSnapshot convertRulesWithSameName(List<MatchedRule> rulesWithSameName) { 063 boolean labelsUnique = isLabelsUnique(rulesWithSameName); 064 switch (getType(rulesWithSameName)) { 065 case "COUNTER": 066 CounterSnapshot.Builder counterBuilder = 067 CounterSnapshot.builder() 068 .name(rulesWithSameName.get(0).name) 069 .help(rulesWithSameName.get(0).help); 070 for (MatchedRule rule : rulesWithSameName) { 071 Labels labels = Labels.of(rule.labelNames, rule.labelValues); 072 if (!labelsUnique) { 073 labels = 074 labels.merge( 075 Labels.of( 076 OBJECTNAME, 077 rule.matchName.substring( 078 0, rule.matchName.lastIndexOf(":")))); 079 } 080 counterBuilder.dataPoint( 081 CounterSnapshot.CounterDataPointSnapshot.builder() 082 .labels(labels) 083 .value(rule.value) 084 .build()); 085 } 086 return counterBuilder.build(); 087 case "GAUGE": 088 GaugeSnapshot.Builder gaugeBuilder = 089 GaugeSnapshot.builder() 090 .name(rulesWithSameName.get(0).name) 091 .help(rulesWithSameName.get(0).help); 092 for (MatchedRule rule : rulesWithSameName) { 093 Labels labels = Labels.of(rule.labelNames, rule.labelValues); 094 if (!labelsUnique) { 095 labels = 096 labels.merge( 097 Labels.of( 098 OBJECTNAME, 099 rule.matchName.substring( 100 0, rule.matchName.lastIndexOf(":")))); 101 } 102 gaugeBuilder.dataPoint( 103 GaugeSnapshot.GaugeDataPointSnapshot.builder() 104 .labels(labels) 105 .value(rule.value) 106 .build()); 107 } 108 return gaugeBuilder.build(); 109 default: 110 UnknownSnapshot.Builder unknownBuilder = 111 UnknownSnapshot.builder() 112 .name(rulesWithSameName.get(0).name) 113 .help(rulesWithSameName.get(0).help); 114 for (MatchedRule rule : rulesWithSameName) { 115 Labels labels = Labels.of(rule.labelNames, rule.labelValues); 116 if (!labelsUnique) { 117 labels = 118 labels.merge( 119 Labels.of( 120 OBJECTNAME, 121 rule.matchName.substring( 122 0, rule.matchName.lastIndexOf(":")))); 123 } 124 unknownBuilder.dataPoint( 125 UnknownSnapshot.UnknownDataPointSnapshot.builder() 126 .labels(labels) 127 .value(rule.value) 128 .build()); 129 } 130 return unknownBuilder.build(); 131 } 132 } 133 134 /** If all rules have the same type, that type is returned. Otherwise, "UNKNOWN" is returned. */ 135 private static String getType(List<MatchedRule> rulesWithSameName) { 136 if (rulesWithSameName.stream().map(rule -> rule.type).distinct().count() == 1) { 137 return rulesWithSameName.get(0).type; 138 } 139 return "UNKNOWN"; 140 } 141 142 private static boolean isLabelsUnique(List<MatchedRule> rulesWithSameName) { 143 Set<Labels> labelsSet = new HashSet<>(rulesWithSameName.size()); 144 for (MatchedRule matchedRule : rulesWithSameName) { 145 Labels labels = Labels.of(matchedRule.labelNames, matchedRule.labelValues); 146 if (labelsSet.contains(labels)) { 147 return false; 148 } 149 labelsSet.add(labels); 150 } 151 return true; 152 } 153}