001package io.prometheus.client; 002 003import io.prometheus.client.CKMSQuantiles.Quantile; 004 005import java.io.Closeable; 006import java.util.ArrayList; 007import java.util.Arrays; 008import java.util.Collections; 009import java.util.List; 010import java.util.Map; 011import java.util.TreeMap; 012import java.util.concurrent.Callable; 013import java.util.concurrent.TimeUnit; 014 015/** 016 * Info metric, key-value pairs. 017 * 018 * Examples of Info include, build information, version information, and potential target metadata, 019 * The first provided state will be the default. 020 * 021 * <p> 022 * Example enumeration: 023 * <pre> 024 * {@code 025 * class YourClass { 026 * static final Info buildInfo = Info.build() 027 * .name("your_build_info").help("Build information.") 028 * .register(); 029 * 030 * void func() { 031 * // Your code here. 032 * buildInfo.info("branch", "HEAD", "version", "1.2.3", "revision", "e0704b"); 033 * } 034 * } 035 * } 036 * </pre> 037 */ 038public class Info extends SimpleCollector<Info.Child> implements Counter.Describable { 039 040 Info(Builder b) { 041 super(b); 042 } 043 044 public static class Builder extends SimpleCollector.Builder<Builder, Info> { 045 @Override 046 public Info create() { 047 if (!unit.isEmpty()) { 048 throw new IllegalStateException("Info metrics cannot have a unit."); 049 } 050 return new Info(this); 051 } 052 } 053 054 /** 055 * Return a Builder to allow configuration of a new Info. Ensures required fields are provided. 056 * 057 * @param name The name of the metric 058 * @param help The help string of the metric 059 */ 060 public static Builder build(String name, String help) { 061 return new Builder().name(name).help(help); 062 } 063 064 /** 065 * Return a Builder to allow configuration of a new Info. 066 */ 067 public static Builder build() { 068 return new Builder(); 069 } 070 071 @Override 072 protected Child newChild() { 073 return new Child(labelNames); 074 } 075 076 077 /** 078 * The value of a single Info. 079 * <p> 080 * <em>Warning:</em> References to a Child become invalid after using 081 * {@link SimpleCollector#remove} or {@link SimpleCollector#clear}. 082 */ 083 public static class Child { 084 085 private Map<String, String> value = Collections.emptyMap(); 086 private List<String> labelNames; 087 088 private Child(List<String> labelNames) { 089 this.labelNames = labelNames; 090 } 091 092 /** 093 * Set the info. 094 */ 095 public void info(Map<String, String> v) { 096 for (String key : v.keySet()) { 097 checkMetricLabelName(key); 098 } 099 for (String label : labelNames) { 100 if (v.containsKey(label)) { 101 throw new IllegalArgumentException("Info and its value cannot have the same label name."); 102 } 103 } 104 this.value = v; 105 } 106 /** 107 * Set the info. 108 * 109 * @param v labels as pairs of key values 110 */ 111 public void info(String... v) { 112 if (v.length % 2 != 0) { 113 throw new IllegalArgumentException("An even number of arguments must be passed"); 114 } 115 Map<String, String> m = new TreeMap<String, String>(); 116 for (int i = 0; i < v.length; i+=2) { 117 m.put(v[i], v[i+1]); 118 } 119 info(m); 120 } 121 122 /** 123 * Get the info. 124 */ 125 public Map<String, String> get() { 126 return value; 127 } 128 } 129 130 // Convenience methods. 131 /** 132 * Set the info on the info with no labels. 133 */ 134 public void info(String... v) { 135 noLabelsChild.info(v); 136 } 137 138 /** 139 * Set the info on the info with no labels. 140 * 141 * @param v labels as pairs of key values 142 */ 143 public void info(Map<String, String> v) { 144 noLabelsChild.info(v); 145 } 146 147 /** 148 * Get the the info. 149 */ 150 public Map<String, String> get() { 151 return noLabelsChild.get(); 152 } 153 154 @Override 155 public List<MetricFamilySamples> collect() { 156 List<MetricFamilySamples.Sample> samples = new ArrayList<MetricFamilySamples.Sample>(); 157 for(Map.Entry<List<String>, Child> c: children.entrySet()) { 158 Map<String, String> v = c.getValue().get(); 159 List<String> names = new ArrayList<String>(labelNames); 160 List<String> values = new ArrayList<String>(c.getKey()); 161 for(Map.Entry<String, String> l: v.entrySet()) { 162 names.add(l.getKey()); 163 values.add(l.getValue()); 164 } 165 samples.add(new MetricFamilySamples.Sample(fullname + "_info", names, values, 1.0)); 166 } 167 168 return familySamplesList(Type.INFO, samples); 169 } 170 171 @Override 172 public List<MetricFamilySamples> describe() { 173 return Collections.singletonList( 174 new MetricFamilySamples(fullname, Type.INFO, help, Collections.<MetricFamilySamples.Sample>emptyList())); 175 } 176 177}