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