001 002package io.prometheus.client; 003 004import java.util.Arrays; 005import java.util.List; 006import java.util.regex.Pattern; 007 008/** 009 * A collector for a set of metrics. 010 * <p> 011 * Normal users should use {@link Gauge}, {@link Counter} and {@link Summary}. 012 * <p> 013 * Subclasssing Collector is for advanced uses, such as proxying metrics from another monitoring system. 014 * It is it the responsibility of subclasses to ensure they produce valid metrics. 015 * @see <a href="http://prometheus.io/docs/instrumenting/exposition_formats/">Exposition formats</a>. 016 */ 017public abstract class Collector { 018 /** 019 * Return all of the metrics of this Collector. 020 */ 021 public abstract List<MetricFamilySamples> collect(); 022 public static enum Type { 023 COUNTER, 024 GAUGE, 025 SUMMARY, 026 HISTOGRAM, 027 } 028 029 /** 030 * A metric, and all of it's samples. 031 */ 032 static public class MetricFamilySamples { 033 public final String name; 034 public final Type type; 035 public final String help; 036 public final List<Sample> samples; 037 038 public MetricFamilySamples(String name, Type type, String help, List<Sample> samples) { 039 this.name = name; 040 this.type = type; 041 this.help = help; 042 this.samples = samples; 043 } 044 045 @Override 046 public boolean equals(Object obj) { 047 if (obj == null || !(obj instanceof MetricFamilySamples)) { 048 return false; 049 } 050 MetricFamilySamples other = (MetricFamilySamples) obj; 051 052 return other.name.equals(name) && other.type.equals(type) 053 && other.help.equals(help) && other.samples.equals(samples) ; 054 } 055 056 @Override 057 public int hashCode() { 058 int hash = 1; 059 hash = 37 * hash + name.hashCode(); 060 hash = 37 * hash + type.hashCode(); 061 hash = 37 * hash + help.hashCode(); 062 hash = 37 * hash + samples.hashCode(); 063 return hash; 064 } 065 066 @Override 067 public String toString() { 068 return "Name: " + name + " Type: " + type + " Help: " + help + 069 " Samples: " + samples; 070 } 071 072 /** 073 * A single Sample, with a unique name and set of labels. 074 */ 075 public static class Sample { 076 public final String name; 077 public final List<String> labelNames; 078 public final List<String> labelValues; // Must have same length as labelNames. 079 public final double value; 080 081 public Sample(String name, List<String> labelNames, List<String> labelValues, double value) { 082 this.name = name; 083 this.labelNames = labelNames; 084 this.labelValues = labelValues; 085 this.value = value; 086 } 087 088 @Override 089 public boolean equals(Object obj) { 090 if (obj == null || !(obj instanceof Sample)) { 091 return false; 092 } 093 Sample other = (Sample) obj; 094 return other.name.equals(name) && other.labelNames.equals(labelNames) 095 && other.labelValues.equals(labelValues) && other.value == value; 096 } 097 098 @Override 099 public int hashCode() { 100 int hash = 1; 101 hash = 37 * hash + name.hashCode(); 102 hash = 37 * hash + labelNames.hashCode(); 103 hash = 37 * hash + labelValues.hashCode(); 104 long d = Double.doubleToLongBits(value); 105 hash = 37 * hash + (int)(d ^ (d >>> 32)); 106 return hash; 107 } 108 109 @Override 110 public String toString() { 111 return "Name: " + name + " LabelNames: " + Arrays.asList(labelNames) + " labelValues: " + labelValues + 112 " Value: " + value; 113 } 114 } 115 } 116 117 /** 118 * Register the Collector with the default registry. 119 */ 120 public <T extends Collector> T register() { 121 return register(CollectorRegistry.defaultRegistry); 122 } 123 124 /** 125 * Register the Collector with the given registry. 126 */ 127 public <T extends Collector> T register(CollectorRegistry registry) { 128 registry.register(this); 129 return (T)this; 130 } 131 132 /* Various utility functions for implementing Collectors. */ 133 134 /** 135 * Number of nanoseconds in a second. 136 */ 137 public static final double NANOSECONDS_PER_SECOND = 1E9; 138 /** 139 * Number of milliseconds in a second. 140 */ 141 public static final double MILLISECONDS_PER_SECOND = 1E3; 142 143 protected static final Pattern METRIC_NAME_RE = Pattern.compile("[a-zA-Z_:][a-zA-Z0-9_:]*"); 144 protected static final Pattern METRIC_LABEL_NAME_RE = Pattern.compile("[a-zA-Z_][a-zA-Z0-9_]*"); 145 protected static final Pattern RESERVED_METRIC_LABEL_NAME_RE = Pattern.compile("__.*"); 146 147 /** 148 * Throw an exception if the metric name is invalid. 149 */ 150 protected static void checkMetricName(String name) { 151 if (!METRIC_NAME_RE.matcher(name).matches()) { 152 throw new IllegalArgumentException("Invalid metric name: " + name); 153 } 154 } 155 156 /** 157 * Throw an exception if the metric label name is invalid. 158 */ 159 protected static void checkMetricLabelName(String name) { 160 if (!METRIC_LABEL_NAME_RE.matcher(name).matches()) { 161 throw new IllegalArgumentException("Invalid metric label name: " + name); 162 } 163 if (RESERVED_METRIC_LABEL_NAME_RE.matcher(name).matches()) { 164 throw new IllegalArgumentException("Invalid metric label name, reserved for internal use: " + name); 165 } 166 } 167 168 /** 169 * Convert a double to it's string representation in Go. 170 */ 171 public static String doubleToGoString(double d) { 172 if (d == Double.POSITIVE_INFINITY) { 173 return "+Inf"; 174 } 175 if (d == Double.NEGATIVE_INFINITY) { 176 return "-Inf"; 177 } 178 return Double.toString(d); 179 } 180}