001package io.prometheus.metrics.model.snapshots; 002 003import io.prometheus.metrics.config.EscapingScheme; 004import javax.annotation.Nullable; 005 006/** Immutable container for metric metadata: name, help, unit. */ 007public final class MetricMetadata { 008 009 /** 010 * Name without suffix. 011 * 012 * <p>For example, the name for a counter "http_requests_total" is "http_requests". The name of an 013 * info called "jvm_info" is "jvm". 014 * 015 * <p>We allow dots in label names. Dots are automatically replaced with underscores in Prometheus 016 * exposition formats. However, if metrics from this library are exposed in OpenTelemetry format 017 * dots are retained. 018 * 019 * <p>See {@link #MetricMetadata(String, String, Unit)} for more info on naming conventions. 020 */ 021 private final String name; 022 023 /** 024 * Same as name that all invalid char (without Unicode support) are replaced by _ 025 * 026 * <p>Multiple metrics with the same prometheusName are not allowed, because they would end up in 027 * the same time series in Prometheus if {@link EscapingScheme#UNDERSCORE_ESCAPING} or {@link 028 * EscapingScheme#DOTS_ESCAPING} is used. 029 */ 030 private final String prometheusName; 031 032 @Nullable private final String help; 033 @Nullable private final Unit unit; 034 035 /** See {@link #MetricMetadata(String, String, Unit)} */ 036 public MetricMetadata(String name) { 037 this(name, null, null); 038 } 039 040 /** See {@link #MetricMetadata(String, String, Unit)} */ 041 public MetricMetadata(String name, String help) { 042 this(name, help, null); 043 } 044 045 /** 046 * Constructor. 047 * 048 * @param name must not be {@code null}. {@link PrometheusNaming#isValidMetricName(String) 049 * isValidMetricName(name)} must be {@code true}. Use {@link 050 * PrometheusNaming#sanitizeMetricName(String)} to convert arbitrary strings into valid names. 051 * @param help optional. May be {@code null}. 052 * @param unit optional. May be {@code null}. 053 */ 054 public MetricMetadata(String name, @Nullable String help, @Nullable Unit unit) { 055 this.name = name; 056 this.help = help; 057 this.unit = unit; 058 validate(); 059 this.prometheusName = PrometheusNaming.prometheusName(name); 060 } 061 062 /** 063 * The name does not include the {@code _total} suffix for counter metrics or the {@code _info} 064 * suffix for Info metrics. 065 * 066 * <p>The name may contain any Unicode chars. Use {@link #getPrometheusName()} to get the name in 067 * legacy Prometheus format, i.e. with all dots and all invalid chars replaced by underscores. 068 */ 069 public String getName() { 070 return name; 071 } 072 073 /** 074 * Same as {@link #getName()} but with all invalid characters and dots replaced by underscores. 075 * 076 * <p>This is used by Prometheus exposition formats. 077 */ 078 public String getPrometheusName() { 079 return prometheusName; 080 } 081 082 @Nullable 083 public String getHelp() { 084 return help; 085 } 086 087 public boolean hasUnit() { 088 return unit != null; 089 } 090 091 @Nullable 092 public Unit getUnit() { 093 return unit; 094 } 095 096 private void validate() { 097 if (name == null) { 098 throw new IllegalArgumentException("Missing required field: name is null"); 099 } 100 String error = PrometheusNaming.validateMetricName(name); 101 if (error != null) { 102 throw new IllegalArgumentException( 103 "'" 104 + name 105 + "': Illegal metric name. " 106 + error 107 + " Call " 108 + PrometheusNaming.class.getSimpleName() 109 + ".sanitizeMetricName(name) to avoid this error."); 110 } 111 if (hasUnit()) { 112 if (!name.endsWith("_" + unit) && !name.endsWith("." + unit)) { 113 throw new IllegalArgumentException( 114 "'" 115 + name 116 + "': Illegal metric name. If the unit is non-null, " 117 + "the name must end with the unit: _" 118 + unit 119 + "." 120 + " Call " 121 + PrometheusNaming.class.getSimpleName() 122 + ".sanitizeMetricName(name, unit) to avoid this error."); 123 } 124 } 125 } 126 127 MetricMetadata escape(EscapingScheme escapingScheme) { 128 return new MetricMetadata(PrometheusNaming.escapeName(name, escapingScheme), help, unit); 129 } 130}