Skip to content

Commit 9701230

Browse files
committed
Add support for Jakarta servlet #647
1 parent d663d04 commit 9701230

File tree

23 files changed

+1370
-555
lines changed

23 files changed

+1370
-555
lines changed

README.md

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -567,8 +567,16 @@ new QueuedThreadPoolStatisticsCollector()
567567

568568
#### Servlet Filter
569569

570-
There is a servlet filter available for measuring the duration taken by servlet
571-
requests. The `metric-name` init parameter is required, and is the name of the
570+
There is a servlet filter available for measuring the duration taken by servlet requests:
571+
572+
* `javax` version: `io.prometheus.client.filter.MetricsFilter` provided by `simpleclient_servlet`
573+
* `jakarta` version: `io.prometheus.client.servlet.jakarta.filter.MetricsFilter` provided by `simpleclient_servlet_jakarta`
574+
575+
Both versions implement the same functionality.
576+
577+
Configuration is as follows:
578+
579+
The `metric-name` init parameter is required, and is the name of the
572580
metric prometheus will expose for the timing metrics. Help text via the `help`
573581
init parameter is not required, although it is highly recommended. The number
574582
of buckets is overridable, and can be configured by passing a comma-separated
@@ -577,9 +585,9 @@ measuring is also configurable, via the `path-components` init parameter. By
577585
default, the servlet filter will record each path differently, but by setting an
578586
integer here, you can tell the filter to only record up to the Nth slashes. That
579587
is, all requests with greater than N "/" characters in the servlet URI path will
580-
be measured in the same bucket and you will lose that granularity. The init
588+
be measured in the same bucket, and you will lose that granularity. The init
581589
parameter `strip-context-path` can be used to strip the leading part of the URL
582-
which is part of the deploy context (i.e. the folder the servlet is deployed to),
590+
which is part of the deployment context (i.e. the folder the servlet is deployed to),
583591
so that the same servlet deployed to different paths can lead to similar metrics.
584592

585593
The code below is an example of the XML configuration for the filter. You will
@@ -589,21 +597,24 @@ need to place this (replace your own values) code in your
589597
```xml
590598
<filter>
591599
<filter-name>prometheusFilter</filter-name>
600+
<!-- This example shows the javax version. For Jakarta you would use -->
601+
<!-- <filter-class>io.prometheus.client.filter.servlet.jakarta.MetricsFilter</filter-class> -->
592602
<filter-class>io.prometheus.client.filter.MetricsFilter</filter-class>
593603
<init-param>
594604
<param-name>metric-name</param-name>
595605
<param-value>webapp_metrics_filter</param-value>
596606
</init-param>
607+
<!-- help is optional, defaults to the message below -->
597608
<init-param>
598609
<param-name>help</param-name>
599610
<param-value>This is the help for your metrics filter</param-value>
600611
</init-param>
612+
<!-- buckets is optional, unless specified the default buckets from io.prometheus.client.Histogram are used -->
601613
<init-param>
602614
<param-name>buckets</param-name>
603615
<param-value>0.005,0.01,0.025,0.05,0.075,0.1,0.25,0.5,0.75,1,2.5,5,7.5,10</param-value>
604616
</init-param>
605-
<!-- Optionally override path components; anything less than 1 (1 is the default)
606-
means full granularity -->
617+
<!-- path-components is optional, anything less than 1 (1 is the default) means full granularity -->
607618
<init-param>
608619
<param-name>path-components</param-name>
609620
<param-value>1</param-value>
@@ -627,8 +638,7 @@ the most accurate measurement of latency. -->
627638
Additionally, you can instantiate your servlet filter directly in Java code. To
628639
do this, you just need to call the non-empty constructor. The first parameter,
629640
the metric name, is required. The second, help, is optional but highly
630-
recommended. The last two (path-components, and buckets) are optional and will
631-
default sensibly if omitted.
641+
recommended. The other parameters are optional and will default sensibly if omitted.
632642

633643
#### Spring AOP
634644

pom.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@
5151
<module>simpleclient_logback</module>
5252
<module>simpleclient_pushgateway</module>
5353
<module>simpleclient_servlet</module>
54+
<module>simpleclient_servlet_common</module>
55+
<module>simpleclient_servlet_jakarta</module>
5456
<module>simpleclient_spring_web</module>
5557
<module>simpleclient_spring_boot</module>
5658
<module>simpleclient_jetty</module>

simpleclient_servlet/pom.xml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@
88
<version>0.11.1-SNAPSHOT</version>
99
</parent>
1010

11-
<groupId>io.prometheus</groupId>
1211
<artifactId>simpleclient_servlet</artifactId>
1312
<packaging>bundle</packaging>
1413

15-
<name>Prometheus Java Simpleclient Servlet</name>
14+
<name>Prometheus Java Simpleclient Servlet - Javax</name>
1615
<description>
1716
HTTP servlet exporter for the simpleclient.
1817
</description>
@@ -48,6 +47,11 @@
4847
<artifactId>simpleclient_common</artifactId>
4948
<version>0.11.1-SNAPSHOT</version>
5049
</dependency>
50+
<dependency>
51+
<groupId>io.prometheus</groupId>
52+
<artifactId>simpleclient_servlet_common</artifactId>
53+
<version>0.11.1-SNAPSHOT</version>
54+
</dependency>
5155
<dependency>
5256
<groupId>javax.servlet</groupId>
5357
<artifactId>javax.servlet-api</artifactId>
@@ -80,4 +84,5 @@
8084
<scope>test</scope>
8185
</dependency>
8286
</dependencies>
87+
8388
</project>
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package io.prometheus.client;
2+
3+
import io.prometheus.client.servlet.common.adapter.FilterConfigAdapter;
4+
import io.prometheus.client.servlet.common.adapter.HttpServletRequestAdapter;
5+
import io.prometheus.client.servlet.common.adapter.HttpServletResponseAdapter;
6+
7+
import javax.servlet.FilterConfig;
8+
import javax.servlet.http.HttpServletRequest;
9+
import javax.servlet.http.HttpServletResponse;
10+
import java.io.IOException;
11+
import java.io.PrintWriter;
12+
13+
public class Adapter {
14+
15+
private static class HttpServletRequestAdapterImpl implements HttpServletRequestAdapter {
16+
17+
private final HttpServletRequest delegate;
18+
19+
HttpServletRequestAdapterImpl(HttpServletRequest delegate) {
20+
this.delegate = delegate;
21+
}
22+
23+
@Override
24+
public String getHeader(String name) {
25+
return delegate.getHeader(name);
26+
}
27+
28+
@Override
29+
public String getRequestURI() {
30+
return delegate.getRequestURI();
31+
}
32+
33+
@Override
34+
public String getMethod() {
35+
return delegate.getMethod();
36+
}
37+
38+
@Override
39+
public String[] getParameterValues(String name) {
40+
return delegate.getParameterValues(name);
41+
}
42+
43+
@Override
44+
public String getContextPath() {
45+
return delegate.getContextPath();
46+
}
47+
}
48+
49+
private static class HttpServletResponseAdapterImpl implements HttpServletResponseAdapter {
50+
51+
private final HttpServletResponse delegate;
52+
53+
HttpServletResponseAdapterImpl(HttpServletResponse delegate) {
54+
this.delegate = delegate;
55+
}
56+
57+
@Override
58+
public void setStatus(int httpStatusCode) {
59+
delegate.setBufferSize(httpStatusCode);
60+
}
61+
62+
@Override
63+
public void setContentType(String contentType) {
64+
delegate.setContentType(contentType);
65+
}
66+
67+
@Override
68+
public PrintWriter getWriter() throws IOException {
69+
return delegate.getWriter();
70+
}
71+
72+
@Override
73+
public int getStatus() {
74+
return delegate.getStatus();
75+
}
76+
}
77+
78+
private static class FilterConfigAdapterImpl implements FilterConfigAdapter {
79+
80+
private final FilterConfig delegate;
81+
82+
private FilterConfigAdapterImpl(FilterConfig delegate) {
83+
this.delegate = delegate;
84+
}
85+
86+
@Override
87+
public String getInitParameter(String name) {
88+
return delegate.getInitParameter(name);
89+
}
90+
}
91+
92+
public static HttpServletRequestAdapter wrap(HttpServletRequest req) {
93+
return new HttpServletRequestAdapterImpl(req);
94+
}
95+
96+
public static HttpServletResponseAdapter wrap(HttpServletResponse resp) {
97+
return new HttpServletResponseAdapterImpl(resp);
98+
}
99+
100+
public static FilterConfigAdapter wrap(FilterConfig filterConfig) {
101+
return new FilterConfigAdapterImpl(filterConfig);
102+
}
103+
}
Lines changed: 12 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,37 @@
11
package io.prometheus.client.exporter;
22

33
import io.prometheus.client.CollectorRegistry;
4-
import io.prometheus.client.exporter.common.TextFormat;
4+
import io.prometheus.client.servlet.common.exporter.Exporter;
55

6-
import javax.servlet.ServletException;
76
import javax.servlet.http.HttpServlet;
87
import javax.servlet.http.HttpServletRequest;
98
import javax.servlet.http.HttpServletResponse;
10-
import java.io.BufferedWriter;
119
import java.io.IOException;
12-
import java.io.Writer;
13-
import java.util.Arrays;
14-
import java.util.Collections;
15-
import java.util.HashSet;
16-
import java.util.Set;
10+
11+
import static io.prometheus.client.Adapter.wrap;
1712

1813
/**
19-
* The MetricsServlet class exists to provide a simple way of exposing the metrics values.
20-
*
14+
* The MetricsServlet class provides a simple way of exposing the metrics values.
2115
*/
2216
public class MetricsServlet extends HttpServlet {
2317

24-
private CollectorRegistry registry;
18+
private final Exporter exporter;
2519

26-
/**
27-
* Construct a MetricsServlet for the default registry.
28-
*/
2920
public MetricsServlet() {
30-
this(CollectorRegistry.defaultRegistry);
21+
exporter = new Exporter();
3122
}
3223

33-
/**
34-
* Construct a MetricsServlet for the given registry.
35-
* @param registry collector registry
36-
*/
3724
public MetricsServlet(CollectorRegistry registry) {
38-
this.registry = registry;
25+
exporter = new Exporter(registry);
3926
}
4027

4128
@Override
42-
protected void doGet(final HttpServletRequest req, final HttpServletResponse resp)
43-
throws ServletException, IOException {
44-
resp.setStatus(HttpServletResponse.SC_OK);
45-
String contentType = TextFormat.chooseContentType(req.getHeader("Accept"));
46-
resp.setContentType(contentType);
47-
48-
Writer writer = new BufferedWriter(resp.getWriter());
49-
try {
50-
TextFormat.writeFormat(contentType, writer, registry.filteredMetricFamilySamples(parse(req)));
51-
writer.flush();
52-
} finally {
53-
writer.close();
54-
}
55-
}
56-
57-
private Set<String> parse(HttpServletRequest req) {
58-
String[] includedParam = req.getParameterValues("name[]");
59-
if (includedParam == null) {
60-
return Collections.emptySet();
61-
} else {
62-
return new HashSet<String>(Arrays.asList(includedParam));
63-
}
29+
protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws IOException {
30+
exporter.doGet(wrap(req), wrap(resp));
6431
}
6532

6633
@Override
67-
protected void doPost(final HttpServletRequest req, final HttpServletResponse resp)
68-
throws ServletException, IOException {
69-
doGet(req, resp);
34+
protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws IOException {
35+
exporter.doPost(wrap(req), wrap(resp));
7036
}
71-
72-
}
37+
}

0 commit comments

Comments
 (0)