Skip to content

Commit a526bae

Browse files
authored
Count HTTP statuses returned along with the HTTP response times (#560)
Signed-off-by: Ken Dombeck <[email protected]>
1 parent ca22b57 commit a526bae

File tree

2 files changed

+75
-3
lines changed

2 files changed

+75
-3
lines changed

simpleclient_servlet/src/main/java/io/prometheus/client/filter/MetricsFilter.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.prometheus.client.filter;
22

3+
import io.prometheus.client.Counter;
34
import io.prometheus.client.Histogram;
45

56
import javax.servlet.Filter;
@@ -9,13 +10,14 @@
910
import javax.servlet.ServletRequest;
1011
import javax.servlet.ServletResponse;
1112
import javax.servlet.http.HttpServletRequest;
13+
import javax.servlet.http.HttpServletResponse;
1214
import java.io.IOException;
1315

1416
/**
1517
* The MetricsFilter class exists to provide a high-level filter that enables tunable collection of metrics for Servlet
1618
* performance.
1719
*
18-
* <p>The Histogram name itself is required, and configured with a {@code metric-name} init parameter.
20+
* <p>The metric name itself is required, and configured with a {@code metric-name} init parameter.
1921
*
2022
* <p>The help parameter, configured with the {@code help} init parameter, is not required but strongly recommended.
2123
*
@@ -26,6 +28,8 @@
2628
* <p>The Histogram buckets can be configured with a {@code buckets} init parameter whose value is a comma-separated list
2729
* of valid {@code double} values.
2830
*
31+
* <p>HTTP statuses will be aggregated via Counter. The name for this counter will be derived from the {@code metric-name} init parameter.
32+
*
2933
* <pre>{@code
3034
* <filter>
3135
* <filter-name>prometheusFilter</filter-name>
@@ -34,7 +38,7 @@
3438
* <param-name>metric-name</param-name>
3539
* <param-value>webapp_metrics_filter</param-value>
3640
* </init-param>
37-
* <init-param>
41+
* <init-param>
3842
* <param-name>help</param-name>
3943
* <param-value>The time taken fulfilling servlet requests</param-value>
4044
* </init-param>
@@ -56,8 +60,10 @@ public class MetricsFilter implements Filter {
5660
static final String HELP_PARAM = "help";
5761
static final String METRIC_NAME_PARAM = "metric-name";
5862
static final String BUCKET_CONFIG_PARAM = "buckets";
63+
static final String UNKNOWN_HTTP_STATUS_CODE = "";
5964

6065
private Histogram histogram = null;
66+
private Counter statusCounter = null;
6167

6268
// Package-level for testing purposes.
6369
int pathComponents = 1;
@@ -149,6 +155,10 @@ public void init(FilterConfig filterConfig) throws ServletException {
149155
.help(help)
150156
.name(metricName)
151157
.register();
158+
159+
statusCounter = Counter.build(metricName + "_status_total", "HTTP status codes of " + help)
160+
.labelNames("path", "method", "status")
161+
.register();
152162
}
153163

154164
@Override
@@ -162,17 +172,28 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo
162172

163173
String path = request.getRequestURI();
164174

175+
String components = getComponents(path);
176+
String method = request.getMethod();
165177
Histogram.Timer timer = histogram
166-
.labels(getComponents(path), request.getMethod())
178+
.labels(components, method)
167179
.startTimer();
168180

169181
try {
170182
filterChain.doFilter(servletRequest, servletResponse);
171183
} finally {
172184
timer.observeDuration();
185+
statusCounter.labels(components, method, getStatusCode(servletResponse)).inc();
173186
}
174187
}
175188

189+
private String getStatusCode(ServletResponse servletResponse) {
190+
if (!(servletResponse instanceof HttpServletResponse)) {
191+
return UNKNOWN_HTTP_STATUS_CODE;
192+
}
193+
194+
return Integer.toString(((HttpServletResponse) servletResponse).getStatus());
195+
}
196+
176197
@Override
177198
public void destroy() {
178199
}

simpleclient_servlet/src/test/java/io/prometheus/client/filter/MetricsFilterTest.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import javax.servlet.FilterChain;
1212
import javax.servlet.FilterConfig;
13+
import javax.servlet.ServletResponse;
1314
import javax.servlet.http.HttpServletRequest;
1415
import javax.servlet.http.HttpServletResponse;
1516
import java.util.Enumeration;
@@ -180,4 +181,54 @@ public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
180181
assertEquals(buckets.split(",").length+1, count);
181182
}
182183

184+
@Test
185+
public void testStatusCode() throws Exception {
186+
HttpServletRequest req = mock(HttpServletRequest.class);
187+
when(req.getRequestURI()).thenReturn("/foo/bar/baz/bang");
188+
when(req.getMethod()).thenReturn(HttpMethods.GET);
189+
190+
HttpServletResponse res = mock(HttpServletResponse.class);
191+
when(res.getStatus()).thenReturn(200);
192+
193+
FilterChain c = mock(FilterChain.class);
194+
195+
MetricsFilter constructed = new MetricsFilter(
196+
"foobar_filter",
197+
"Help for my filter",
198+
2,
199+
null
200+
);
201+
constructed.init(mock(FilterConfig.class));
202+
203+
constructed.doFilter(req, res, c);
204+
205+
final Double sampleValue = CollectorRegistry.defaultRegistry.getSampleValue("foobar_filter_status_total", new String[]{"path", "method", "status"}, new String[]{"/foo/bar", HttpMethods.GET, "200"});
206+
assertNotNull(sampleValue);
207+
assertEquals(1, sampleValue, 0.0001);
208+
}
209+
210+
@Test
211+
public void testStatusCodeWithNonHttpServletResponse() throws Exception {
212+
HttpServletRequest req = mock(HttpServletRequest.class);
213+
when(req.getRequestURI()).thenReturn("/foo/bar/baz/bang");
214+
when(req.getMethod()).thenReturn(HttpMethods.GET);
215+
216+
ServletResponse res = mock(ServletResponse.class);
217+
218+
FilterChain c = mock(FilterChain.class);
219+
220+
MetricsFilter constructed = new MetricsFilter(
221+
"foobar_filter",
222+
"Help for my filter",
223+
2,
224+
null
225+
);
226+
constructed.init(mock(FilterConfig.class));
227+
228+
constructed.doFilter(req, res, c);
229+
230+
final Double sampleValue = CollectorRegistry.defaultRegistry.getSampleValue("foobar_filter_status_total", new String[]{"path", "method", "status"}, new String[]{"/foo/bar", HttpMethods.GET, MetricsFilter.UNKNOWN_HTTP_STATUS_CODE});
231+
assertNotNull(sampleValue);
232+
assertEquals(1, sampleValue, 0.0001);
233+
}
183234
}

0 commit comments

Comments
 (0)