Skip to content

Commit e68daf2

Browse files
authored
Add a sample name filter for in-/excluding metrics by name or name prefix (#680)
Signed-off-by: Fabian Stäber <[email protected]>
1 parent 17c98eb commit e68daf2

File tree

35 files changed

+1898
-458
lines changed

35 files changed

+1898
-458
lines changed

README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -672,9 +672,14 @@ There are HTTPServer, Servlet, SpringBoot, and Vert.x integrations included in t
672672
The simplest of these is the HTTPServer:
673673

674674
```java
675-
HTTPServer server = new HTTPServer(1234);
675+
HTTPServer server = new HTTPServer.Builder()
676+
.withPort(1234)
677+
.build();
676678
```
677679

680+
The `HTTPServer.Builder` supports configuration of a `SampleNameFilter` which can be used to
681+
restrict the time series being exported by name.
682+
678683
To add Prometheus exposition to an existing HTTP server using servlets, see the `MetricsServlet`.
679684
It also serves as a simple example of how to write a custom endpoint.
680685

@@ -689,11 +694,14 @@ server.setHandler(context);
689694
context.addServlet(new ServletHolder(new MetricsServlet()), "/metrics");
690695
```
691696

697+
Like the HTTPServer, the `MetricsServlet` can be configured with a `SampleNameFilter` which can
698+
be used to restrict the time series being exported by name. See `integration_tests/servlet_jakarta_exporter_webxml/`
699+
for an example how to configure this in `web.xml`.
700+
692701
All HTTP exposition integrations support restricting which time series to return
693702
using `?name[]=` URL parameters. Due to implementation limitations, this may
694703
have false negatives.
695704

696-
697705
## Exporting to a Pushgateway
698706

699707
The [Pushgateway](https://github.com/prometheus/pushgateway)

integration_tests/example_application/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
</dependencies>
3131

3232
<build>
33-
<finalName>${artifactId}</finalName>
33+
<finalName>${project.artifactId}</finalName>
3434
<plugins>
3535
<plugin>
3636
<groupId>org.apache.maven.plugins</groupId>

integration_tests/exemplars_otel/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
</dependencies>
5555

5656
<build>
57-
<finalName>${artifactId}</finalName>
57+
<finalName>${project.artifactId}</finalName>
5858
<plugins>
5959
<plugin>
6060
<groupId>org.apache.maven.plugins</groupId>

integration_tests/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
<module>exemplars_otel_agent</module>
2727
<module>example_application</module>
2828
<module>java_versions</module>
29+
<module>servlet_jakarta_exporter_webxml</module>
2930
</modules>
3031

3132
<build>
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<parent>
6+
<groupId>io.prometheus</groupId>
7+
<artifactId>integration_tests</artifactId>
8+
<version>0.11.1-SNAPSHOT</version>
9+
</parent>
10+
11+
<artifactId>servlet_jakarta_exporter_webxml</artifactId>
12+
<name>Integration Test - Servlet Jakarta Exporter web.xml</name>
13+
<packaging>war</packaging>
14+
15+
<properties>
16+
<otel.version>1.2.0</otel.version>
17+
</properties>
18+
19+
<dependencies>
20+
<dependency>
21+
<groupId>io.prometheus</groupId>
22+
<artifactId>simpleclient</artifactId>
23+
<version>${project.version}</version>
24+
</dependency>
25+
<dependency>
26+
<groupId>io.prometheus</groupId>
27+
<artifactId>simpleclient_servlet_jakarta</artifactId>
28+
<version>${project.version}</version>
29+
</dependency>
30+
<dependency>
31+
<groupId>io.prometheus</groupId>
32+
<artifactId>simpleclient_hotspot</artifactId>
33+
<version>${project.version}</version>
34+
</dependency>
35+
<dependency>
36+
<groupId>com.squareup.okhttp3</groupId>
37+
<artifactId>okhttp</artifactId>
38+
<version>4.9.1</version>
39+
</dependency>
40+
<dependency>
41+
<groupId>org.testcontainers</groupId>
42+
<artifactId>testcontainers</artifactId>
43+
<scope>test</scope>
44+
</dependency>
45+
<dependency>
46+
<groupId>ch.qos.logback</groupId>
47+
<artifactId>logback-classic</artifactId>
48+
<version>1.1.2</version>
49+
</dependency>
50+
<dependency>
51+
<groupId>jakarta.servlet</groupId>
52+
<artifactId>jakarta.servlet-api</artifactId>
53+
<version>5.0.0</version>
54+
<scope>provided</scope>
55+
</dependency>
56+
</dependencies>
57+
58+
<build>
59+
<finalName>${project.artifactId}</finalName>
60+
<plugins>
61+
<plugin>
62+
<groupId>org.apache.maven.plugins</groupId>
63+
<artifactId>maven-compiler-plugin</artifactId>
64+
<configuration>
65+
<source>1.8</source>
66+
<target>1.8</target>
67+
</configuration>
68+
</plugin>
69+
<plugin>
70+
<groupId>org.apache.maven.plugins</groupId>
71+
<artifactId>maven-failsafe-plugin</artifactId>
72+
<executions>
73+
<execution>
74+
<id>integration-test</id>
75+
<phase>integration-test</phase>
76+
<goals>
77+
<goal>integration-test</goal>
78+
</goals>
79+
</execution>
80+
<execution>
81+
<id>verify</id>
82+
<phase>verify</phase>
83+
<goals>
84+
<goal>verify</goal>
85+
</goals>
86+
</execution>
87+
</executions>
88+
</plugin>
89+
<plugin>
90+
<groupId>org.apache.maven.plugins</groupId>
91+
<artifactId>maven-dependency-plugin</artifactId>
92+
<executions>
93+
<execution>
94+
<id>copy-dependencies</id>
95+
<phase>package</phase>
96+
<goals>
97+
<goal>copy-dependencies</goal>
98+
</goals>
99+
</execution>
100+
</executions>
101+
</plugin>
102+
<plugin>
103+
<artifactId>maven-war-plugin</artifactId>
104+
<version>3.3.1</version>
105+
</plugin>
106+
</plugins>
107+
</build>
108+
109+
<licenses>
110+
<license>
111+
<name>The Apache Software License, Version 2.0</name>
112+
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
113+
<distribution>repo</distribution>
114+
</license>
115+
</licenses>
116+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package io.prometheus.client.it.servlet.jakarta;
2+
3+
import io.prometheus.client.hotspot.DefaultExports;
4+
import jakarta.servlet.http.HttpServlet;
5+
import jakarta.servlet.http.HttpServletRequest;
6+
import jakarta.servlet.http.HttpServletResponse;
7+
8+
import java.io.BufferedWriter;
9+
import java.io.IOException;
10+
import java.io.Writer;
11+
12+
public class ExampleServlet extends HttpServlet {
13+
14+
@Override
15+
public void init() {
16+
DefaultExports.initialize();
17+
}
18+
19+
@Override
20+
protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws IOException {
21+
resp.setStatus(200);
22+
resp.setContentType("text/plain");
23+
Writer writer = new BufferedWriter(resp.getWriter());
24+
writer.write("Hello, world!\n");
25+
writer.close();
26+
}
27+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
5+
version="5.0">
6+
<!-- Anyone still using web.xml in 2021? -->
7+
<servlet>
8+
<servlet-name>example</servlet-name>
9+
<servlet-class>io.prometheus.client.it.servlet.jakarta.ExampleServlet</servlet-class>
10+
<load-on-startup/>
11+
</servlet>
12+
<filter>
13+
<filter-name>prometheus</filter-name>
14+
<filter-class>io.prometheus.client.servlet.jakarta.filter.MetricsFilter</filter-class>
15+
<init-param>
16+
<param-name>metric-name</param-name>
17+
<param-value>requests</param-value>
18+
</init-param>
19+
</filter>
20+
<servlet>
21+
<servlet-name>prometheus-exporter</servlet-name>
22+
<servlet-class>io.prometheus.client.servlet.jakarta.exporter.MetricsServlet</servlet-class>
23+
<init-param>
24+
<param-name>name-must-not-start-with</param-name>
25+
<param-value>
26+
jvm_threads_deadlocked
27+
jvm_memory_pool
28+
</param-value>
29+
</init-param>
30+
</servlet>
31+
<servlet-mapping>
32+
<servlet-name>example</servlet-name>
33+
<url-pattern>/*</url-pattern>
34+
</servlet-mapping>
35+
<servlet-mapping>
36+
<servlet-name>prometheus-exporter</servlet-name>
37+
<url-pattern>/metrics</url-pattern>
38+
</servlet-mapping>
39+
<filter-mapping>
40+
<filter-name>prometheus</filter-name>
41+
<servlet-name>example</servlet-name>
42+
</filter-mapping>
43+
</web-app>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package io.prometheus.client.it.servlet.jakarta;
2+
3+
import okhttp3.OkHttpClient;
4+
import okhttp3.Request;
5+
import okhttp3.Response;
6+
import org.junit.Assert;
7+
import org.junit.Rule;
8+
import org.junit.Test;
9+
import org.testcontainers.containers.GenericContainer;
10+
import org.testcontainers.containers.wait.strategy.Wait;
11+
import org.testcontainers.images.builder.ImageFromDockerfile;
12+
13+
import java.io.IOException;
14+
import java.nio.file.Paths;
15+
import java.util.Arrays;
16+
import java.util.List;
17+
18+
public class ServletJakartaExporterWebXmlIT {
19+
20+
private final OkHttpClient client = new OkHttpClient();
21+
22+
private static class DockerContainer extends GenericContainer<DockerContainer> {
23+
DockerContainer() {
24+
super(new ImageFromDockerfile("servlet-jakarta-exporter-webxml")
25+
.withFileFromPath("servlet_jakarta_exporter_webxml.war", Paths.get("target/servlet_jakarta_exporter_webxml.war"))
26+
.withFileFromClasspath("Dockerfile", "Dockerfile"));
27+
}
28+
}
29+
30+
@Rule
31+
public DockerContainer dockerContainer = new DockerContainer()
32+
.withExposedPorts(8080)
33+
.waitingFor(Wait.forLogMessage(".*oejs.Server:main: Started Server.*", 1));
34+
35+
@Test
36+
public void testSampleNameFilter() throws IOException, InterruptedException {
37+
callExampleServlet();
38+
List<String> metrics = scrapeMetrics();
39+
assertContains(metrics, "requests_bucket");
40+
assertContains(metrics, "requests_count");
41+
assertContains(metrics, "requests_sum");
42+
assertContains(metrics, "requests_created");
43+
assertContains(metrics, "requests_status_total");
44+
assertContains(metrics, "requests_status_created");
45+
assertContains(metrics, "jvm_gc_collection_seconds_count");
46+
assertNotContains(metrics, "jvm_threads_deadlocked");
47+
assertNotContains(metrics, "jvm_memory_pool");
48+
49+
List<String> filteredMetrics = scrapeMetricsWithNameFilter("requests_count", "requests_sum");
50+
assertNotContains(filteredMetrics, "requests_bucket");
51+
assertContains(filteredMetrics, "requests_count");
52+
assertContains(filteredMetrics, "requests_sum");
53+
assertNotContains(filteredMetrics, "requests_created");
54+
assertNotContains(filteredMetrics, "requests_status_total");
55+
assertNotContains(filteredMetrics, "requests_status_created");
56+
assertNotContains(filteredMetrics, "jvm_gc_collection_seconds_count");
57+
assertNotContains(filteredMetrics, "jvm_threads_deadlocked");
58+
assertNotContains(filteredMetrics, "jvm_memory_pool");
59+
}
60+
61+
private void assertContains(List<String> metrics, String prefix) {
62+
for (String metric : metrics) {
63+
if (metric.startsWith(prefix)) {
64+
return;
65+
}
66+
}
67+
Assert.fail("metric not found: " + prefix);
68+
}
69+
private void assertNotContains(List<String> metrics, String prefix) {
70+
for (String metric : metrics) {
71+
if (metric.startsWith(prefix)) {
72+
Assert.fail("unexpected metric found: " + metric);
73+
}
74+
}
75+
}
76+
private void callExampleServlet() throws IOException {
77+
Request request = new Request.Builder()
78+
.url("http://localhost:" + dockerContainer.getMappedPort(8080) + "/hello")
79+
.build();
80+
try (Response response = client.newCall(request).execute()) {
81+
Assert.assertEquals("Hello, world!\n", response.body().string());
82+
}
83+
}
84+
85+
private List<String> scrapeMetrics() throws IOException {
86+
Request request = new Request.Builder()
87+
.url("http://localhost:" + dockerContainer.getMappedPort(8080) + "/metrics")
88+
.header("Accept", "application/openmetrics-text; version=1.0.0; charset=utf-8")
89+
.build();
90+
try (Response response = client.newCall(request).execute()) {
91+
return Arrays.asList(response.body().string().split("\\n"));
92+
}
93+
}
94+
95+
private List<String> scrapeMetricsWithNameFilter(String... names) throws IOException {
96+
StringBuilder param = new StringBuilder();
97+
boolean first = true;
98+
for (String name : names) {
99+
if (!first) {
100+
param.append("&");
101+
}
102+
param.append("name[]=").append(name);
103+
first = false;
104+
}
105+
Request request = new Request.Builder()
106+
.url("http://localhost:" + dockerContainer.getMappedPort(8080) + "/metrics?" + param)
107+
.header("Accept", "application/openmetrics-text; version=1.0.0; charset=utf-8")
108+
.build();
109+
try (Response response = client.newCall(request).execute()) {
110+
return Arrays.asList(response.body().string().split("\\n"));
111+
}
112+
}
113+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
FROM jetty:11.0.6
2+
COPY servlet_jakarta_exporter_webxml.war /var/lib/jetty/webapps/ROOT.war
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<configuration>
2+
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
3+
<encoder>
4+
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
5+
</encoder>
6+
</appender>
7+
8+
<root level="info">
9+
<appender-ref ref="STDOUT"/>
10+
</root>
11+
12+
<logger name="org.testcontainers" level="INFO"/>
13+
<logger name="com.github.dockerjava" level="WARN"/>
14+
</configuration>

pom.xml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,6 @@
8888
<artifactId>maven-install-plugin</artifactId>
8989
<version>2.4</version>
9090
</plugin>
91-
<plugin>
92-
<artifactId>maven-deploy-plugin</artifactId>
93-
<version>2.7</version>
94-
</plugin>
9591
<plugin>
9692
<artifactId>maven-resources-plugin</artifactId>
9793
<version>2.6</version>

0 commit comments

Comments
 (0)