Skip to content

Commit 7a77d9e

Browse files
checkettsbrian-brazil
authored andcommitted
Add support for name[] parameter filtering in CollectorRegistry and MetricsServlet (prometheus#204)
Add support for `name[]` parameter filtering
1 parent 0ea0a30 commit 7a77d9e

14 files changed

Lines changed: 372 additions & 98 deletions

File tree

simpleclient/src/main/java/io/prometheus/client/CollectorRegistry.java

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
import java.util.HashMap;
88
import java.util.HashSet;
99
import java.util.Iterator;
10+
import java.util.List;
1011
import java.util.Map;
1112
import java.util.NoSuchElementException;
1213
import java.util.Set;
13-
import java.util.List;
1414

1515
/**
1616
* A registry of Collectors.
@@ -33,7 +33,7 @@ public class CollectorRegistry {
3333

3434
private final boolean autoDescribe;
3535

36-
public CollectorRegistry(){
36+
public CollectorRegistry() {
3737
this(false);
3838
}
3939

@@ -50,7 +50,7 @@ public void register(Collector m) {
5050
List<String> names = collectorNames(m);
5151
synchronized (collectorsToNames) {
5252
for (String name : names) {
53-
if(namesToCollectors.containsKey(name)) {
53+
if (namesToCollectors.containsKey(name)) {
5454
throw new IllegalArgumentException("Collector already registered that provides name: " + name);
5555
}
5656
}
@@ -72,6 +72,7 @@ public void unregister(Collector m) {
7272
collectorsToNames.remove(m);
7373
}
7474
}
75+
7576
/**
7677
* Unregister all Collectors.
7778
*/
@@ -94,7 +95,7 @@ private Set<Collector> collectors() {
9495
private List<String> collectorNames(Collector m) {
9596
List<Collector.MetricFamilySamples> mfs;
9697
if (m instanceof Collector.Describable) {
97-
mfs = ((Collector.Describable)m).describe();
98+
mfs = ((Collector.Describable) m).describe();
9899
} else if (autoDescribe) {
99100
mfs = m.collect();
100101
} else {
@@ -125,28 +126,73 @@ private List<String> collectorNames(Collector m) {
125126
public Enumeration<Collector.MetricFamilySamples> metricFamilySamples() {
126127
return new MetricFamilySamplesEnumeration();
127128
}
129+
130+
public Enumeration<Collector.MetricFamilySamples> filteredMetricFamilySamples(Set<String> includedNames) {
131+
return new MetricFamilySamplesEnumeration(includedNames);
132+
}
133+
128134
class MetricFamilySamplesEnumeration implements Enumeration<Collector.MetricFamilySamples> {
129135

130-
private final Iterator<Collector> collectorIter = collectors().iterator();
136+
private final Iterator<Collector> collectorIter;
131137
private Iterator<Collector.MetricFamilySamples> metricFamilySamples;
132138
private Collector.MetricFamilySamples next;
139+
private Set<String> includedNames;
133140

134-
MetricFamilySamplesEnumeration() {
141+
MetricFamilySamplesEnumeration(Set<String> includedNames) {
142+
this.includedNames = includedNames;
143+
collectorIter = includedCollectorIterator(includedNames);
135144
findNextElement();
136145
}
137146

138-
private void findNextElement() {
139-
if (metricFamilySamples != null && metricFamilySamples.hasNext()) {
140-
next = metricFamilySamples.next();
147+
private Iterator<Collector> includedCollectorIterator(Set<String> includedNames) {
148+
if (includedNames.isEmpty()) {
149+
return collectors().iterator();
141150
} else {
151+
HashSet<Collector> collectors = new HashSet<Collector>();
152+
synchronized (namesToCollectors) {
153+
for (Map.Entry<String, Collector> entry : namesToCollectors.entrySet()) {
154+
if (includedNames.contains(entry.getKey())) {
155+
collectors.add(entry.getValue());
156+
}
157+
}
158+
}
159+
160+
return collectors.iterator();
161+
}
162+
}
163+
164+
MetricFamilySamplesEnumeration() {
165+
this(Collections.<String>emptySet());
166+
}
167+
168+
private void findNextElement() {
169+
next = null;
170+
171+
while (metricFamilySamples != null && metricFamilySamples.hasNext()) {
172+
next = filter(metricFamilySamples.next());
173+
if (next != null) {
174+
return;
175+
}
176+
}
177+
178+
if (next == null) {
142179
while (collectorIter.hasNext()) {
143180
metricFamilySamples = collectorIter.next().collect().iterator();
144-
if (metricFamilySamples.hasNext()) {
145-
next = metricFamilySamples.next();
146-
return;
181+
while (metricFamilySamples.hasNext()) {
182+
next = filter(metricFamilySamples.next());
183+
if (next != null) {
184+
return;
185+
}
147186
}
148187
}
149-
next = null;
188+
}
189+
}
190+
191+
private Collector.MetricFamilySamples filter(Collector.MetricFamilySamples next) {
192+
if (includedNames.isEmpty() || includedNames.contains(next.name)) {
193+
return next;
194+
} else {
195+
return null;
150196
}
151197
}
152198

@@ -179,11 +225,11 @@ public Double getSampleValue(String name) {
179225
* This is inefficient, and intended only for use in unittests.
180226
*/
181227
public Double getSampleValue(String name, String[] labelNames, String[] labelValues) {
182-
for (Collector.MetricFamilySamples metricFamilySamples: Collections.list(metricFamilySamples())) {
183-
for (Collector.MetricFamilySamples.Sample sample: metricFamilySamples.samples) {
228+
for (Collector.MetricFamilySamples metricFamilySamples : Collections.list(metricFamilySamples())) {
229+
for (Collector.MetricFamilySamples.Sample sample : metricFamilySamples.samples) {
184230
if (sample.name.equals(name)
185-
&& Arrays.equals(sample.labelNames.toArray(), labelNames)
186-
&& Arrays.equals(sample.labelValues.toArray(), labelValues)) {
231+
&& Arrays.equals(sample.labelNames.toArray(), labelNames)
232+
&& Arrays.equals(sample.labelValues.toArray(), labelValues)) {
187233
return sample.value;
188234
}
189235
}

simpleclient/src/test/java/io/prometheus/client/CollectorRegistryTest.java

Lines changed: 68 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
package io.prometheus.client;
22

3-
import static org.junit.Assert.assertEquals;
4-
import static org.junit.Assert.assertFalse;
3+
import org.junit.Before;
4+
import org.junit.Test;
55

66
import java.util.ArrayList;
77
import java.util.Arrays;
88
import java.util.Collections;
99
import java.util.HashSet;
1010
import java.util.List;
11-
import org.junit.Test;
12-
import org.junit.Before;
11+
12+
import static org.junit.Assert.assertEquals;
13+
import static org.junit.Assert.assertFalse;
1314

1415

1516
public class CollectorRegistryTest {
@@ -53,7 +54,7 @@ public void testClear() {
5354
}
5455

5556
class EmptyCollector extends Collector {
56-
public List<MetricFamilySamples> collect(){
57+
public List<MetricFamilySamples> collect() {
5758
return new ArrayList<MetricFamilySamples>();
5859
}
5960
}
@@ -65,12 +66,31 @@ public void testMetricFamilySamples() {
6566
Collector s = Summary.build().name("s").help("h").register(registry);
6667
Collector ec = new EmptyCollector().register(registry);
6768
HashSet<String> names = new HashSet<String>();
68-
for (Collector.MetricFamilySamples metricFamilySamples: Collections.list(registry.metricFamilySamples())) {
69+
for (Collector.MetricFamilySamples metricFamilySamples : Collections.list(registry.metricFamilySamples())) {
6970
names.add(metricFamilySamples.name);
7071
}
7172
assertEquals(new HashSet<String>(Arrays.asList("g", "c", "s")), names);
7273
}
7374

75+
@Test
76+
public void testMetricFamilySamples_filterNames() {
77+
Collector g = Gauge.build().name("g").help("h").register(registry);
78+
Collector c = Counter.build().name("c").help("h").register(registry);
79+
Collector s = Summary.build().name("s").help("h").register(registry);
80+
Collector ec = new EmptyCollector().register(registry);
81+
SkippedCollector sr = new SkippedCollector().register(registry);
82+
PartiallyFilterCollector pfr = new PartiallyFilterCollector().register(registry);
83+
HashSet<String> names = new HashSet<String>();
84+
for (Collector.MetricFamilySamples metricFamilySamples : Collections.list(registry.filteredMetricFamilySamples(
85+
new HashSet<String>(Arrays.asList("", "s", "c", "part_filter_a", "part_filter_c"))))) {
86+
names.add(metricFamilySamples.name);
87+
}
88+
89+
assertEquals(1, sr.collectCallCount);
90+
assertEquals(2, pfr.collectCallCount);
91+
assertEquals(new HashSet<String>(Arrays.asList("s", "c", "part_filter_a", "part_filter_c")), names);
92+
}
93+
7494
@Test
7595
public void testEmptyRegistryHasNoMoreElements() {
7696
assertFalse(registry.metricFamilySamples().hasMoreElements());
@@ -82,25 +102,25 @@ public void testRegistryWithEmptyCollectorHasNoMoreElements() {
82102
assertFalse(registry.metricFamilySamples().hasMoreElements());
83103
}
84104

85-
@Test(expected=IllegalArgumentException.class)
105+
@Test(expected = IllegalArgumentException.class)
86106
public void testCounterAndGaugeWithSameNameThrows() {
87107
Gauge.build().name("g").help("h").register(registry);
88108
Counter.build().name("g").help("h").register(registry);
89109
}
90110

91-
@Test(expected=IllegalArgumentException.class)
111+
@Test(expected = IllegalArgumentException.class)
92112
public void testCounterAndSummaryWithSameNameThrows() {
93113
Counter.build().name("s").help("h").register(registry);
94114
Summary.build().name("s").help("h").register(registry);
95115
}
96116

97-
@Test(expected=IllegalArgumentException.class)
117+
@Test(expected = IllegalArgumentException.class)
98118
public void testCounterSumAndSummaryWithSameNameThrows() {
99119
Counter.build().name("s_sum").help("h").register(registry);
100120
Summary.build().name("s").help("h").register(registry);
101121
}
102122

103-
@Test(expected=IllegalArgumentException.class)
123+
@Test(expected = IllegalArgumentException.class)
104124
public void testHistogramAndSummaryWithSameNameThrows() {
105125
Histogram.build().name("s").help("h").register(registry);
106126
Summary.build().name("s").help("h").register(registry);
@@ -130,11 +150,47 @@ public void testAutoDescribeDisabledByDefault() {
130150
new MyCollector().register(r);
131151
}
132152

133-
@Test(expected=IllegalArgumentException.class)
153+
@Test(expected = IllegalArgumentException.class)
134154
public void testAutoDescribeThrowsOnReregisteringCustomCollector() {
135155
CollectorRegistry r = new CollectorRegistry(true);
136156
new MyCollector().register(r);
137157
new MyCollector().register(r);
138158
}
139-
159+
160+
private static class SkippedCollector extends Collector implements Collector.Describable {
161+
public int collectCallCount = 0;
162+
163+
@Override
164+
public List<MetricFamilySamples> collect() {
165+
collectCallCount++;
166+
List<MetricFamilySamples> mfs = new ArrayList<MetricFamilySamples>();
167+
mfs.add(new GaugeMetricFamily("slow_gauge", "help", 123));
168+
return mfs;
169+
}
170+
171+
@Override
172+
public List<MetricFamilySamples> describe() {
173+
return collect();
174+
}
175+
}
176+
177+
private static class PartiallyFilterCollector extends Collector implements Collector.Describable {
178+
public int collectCallCount = 0;
179+
180+
@Override
181+
public List<MetricFamilySamples> collect() {
182+
collectCallCount++;
183+
List<MetricFamilySamples> mfs = new ArrayList<MetricFamilySamples>();
184+
mfs.add(new GaugeMetricFamily("part_filter_a", "help", 123));
185+
mfs.add(new GaugeMetricFamily("part_filter_b", "help", 123));
186+
mfs.add(new GaugeMetricFamily("part_filter_c", "help", 123));
187+
return mfs;
188+
}
189+
190+
@Override
191+
public List<MetricFamilySamples> describe() {
192+
return collect();
193+
}
194+
}
195+
140196
}

simpleclient_servlet/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@
6161
<version>4.11</version>
6262
<scope>test</scope>
6363
</dependency>
64+
<dependency>
65+
<groupId>org.assertj</groupId>
66+
<artifactId>assertj-core</artifactId>
67+
<version>2.6.0</version>
68+
<scope>test</scope>
69+
</dependency>
6470
<dependency>
6571
<groupId>org.eclipse.jetty</groupId>
6672
<artifactId>jetty-servlet</artifactId>

simpleclient_servlet/src/main/java/io/prometheus/client/exporter/MetricsServlet.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
package io.prometheus.client.exporter;
22

3-
import java.io.IOException;
4-
import java.io.Writer;
3+
import io.prometheus.client.CollectorRegistry;
4+
import io.prometheus.client.exporter.common.TextFormat;
55

66
import javax.servlet.ServletException;
77
import javax.servlet.http.HttpServlet;
88
import javax.servlet.http.HttpServletRequest;
99
import javax.servlet.http.HttpServletResponse;
10-
11-
import io.prometheus.client.CollectorRegistry;
12-
import io.prometheus.client.exporter.common.TextFormat;
10+
import java.io.IOException;
11+
import java.io.Writer;
12+
import java.util.Arrays;
13+
import java.util.Collections;
14+
import java.util.HashSet;
15+
import java.util.Set;
1316

1417
public class MetricsServlet extends HttpServlet {
1518

@@ -31,22 +34,31 @@ public MetricsServlet(CollectorRegistry registry) {
3134

3235
@Override
3336
protected void doGet(final HttpServletRequest req, final HttpServletResponse resp)
34-
throws ServletException, IOException {
37+
throws ServletException, IOException {
3538
resp.setStatus(HttpServletResponse.SC_OK);
3639
resp.setContentType(TextFormat.CONTENT_TYPE_004);
3740

3841
Writer writer = resp.getWriter();
3942
try {
40-
TextFormat.write004(writer, registry.metricFamilySamples());
43+
TextFormat.write004(writer, registry.filteredMetricFamilySamples(parse(req)));
4144
writer.flush();
4245
} finally {
4346
writer.close();
4447
}
4548
}
4649

50+
private Set<String> parse(HttpServletRequest req) {
51+
String[] includedParam = req.getParameterValues("names[]");
52+
if (includedParam == null) {
53+
return Collections.emptySet();
54+
} else {
55+
return new HashSet<String>(Arrays.asList(includedParam));
56+
}
57+
}
58+
4759
@Override
4860
protected void doPost(final HttpServletRequest req, final HttpServletResponse resp)
49-
throws ServletException, IOException {
61+
throws ServletException, IOException {
5062
doGet(req, resp);
5163
}
5264

0 commit comments

Comments
 (0)