Skip to content

Commit c208b81

Browse files
committed
Add HTTPServer exporter
Signed-off-by: Fabian Stäber <[email protected]>
1 parent 8aea914 commit c208b81

File tree

42 files changed

+2464
-64
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+2464
-64
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Built-in HTTPServer for Exposing Metrics
2+
3+
## Build
4+
5+
This example is built as part of the `client_java` project.
6+
7+
```
8+
./mvnw package
9+
```
10+
11+
## Run
12+
13+
The build creates a JAR file with the example application in `./examples/example-httpserver/target/`.
14+
15+
```
16+
java -jar ./examples/example-httpserver/target/example-tomcat-servlet-1.0.0-alpha-3-SNAPSHOT.jar
17+
```
18+
19+
## Manually testing the Metrics Endpoint
20+
21+
Accessing [http://localhost:9400/metrics](http://localhost:9400/metrics) with a Web browser should yield an example of a counter metric.
22+
23+
```
24+
# HELP uptime_seconds_total total number of seconds since this application was started
25+
# TYPE uptime_seconds_total counter
26+
uptime_seconds_total 301.0
27+
```
28+
29+
The exporter supports a `debug` URL parameter to quickly view other formats in your Web browser:
30+
31+
* [http://localhost:9400/metrics?debug=text](http://localhost:9400/metrics?debug=text): Prometheus text format, same as without the `debug` option.
32+
* [http://localhost:9400/metrics?debug=openmetrics](http://localhost:9400/metrics?debug=openmetrics): OpenMetrics text format.
33+
* [http://localhost:9400/metrics?debug=prometheus-protobuf](http://localhost:9400/metrics?debug=prometheus-protobuf): Text representation of the Prometheus protobuf format.
34+
35+
## TODO
36+
37+
Implement an example of a histogram and show how to use this with Prometheus, see [../example-tomcat-servlet](../example-tomcat-servlet).
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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>examples</artifactId>
8+
<version>1.0.0-alpha-3-SNAPSHOT</version>
9+
</parent>
10+
11+
<artifactId>example-httpserver</artifactId>
12+
13+
<name>Example - HTTPServer</name>
14+
<description>
15+
Prometheus Metrics Example using the HTTPServer for exposing the metrics endpoint
16+
</description>
17+
18+
<licenses>
19+
<license>
20+
<name>The Apache Software License, Version 2.0</name>
21+
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
22+
<distribution>repo</distribution>
23+
</license>
24+
</licenses>
25+
26+
<developers>
27+
<developer>
28+
<id>fstab</id>
29+
<name>Fabian Stäber</name>
30+
<email>[email protected]</email>
31+
</developer>
32+
</developers>
33+
34+
<dependencies>
35+
<dependency>
36+
<groupId>io.prometheus</groupId>
37+
<artifactId>prometheus-metrics-core</artifactId>
38+
<version>${project.version}</version>
39+
</dependency>
40+
<dependency>
41+
<groupId>io.prometheus</groupId>
42+
<artifactId>prometheus-metrics-exporter-httpserver</artifactId>
43+
<version>${project.version}</version>
44+
</dependency>
45+
</dependencies>
46+
47+
<build>
48+
<plugins>
49+
<plugin>
50+
<groupId>org.apache.maven.plugins</groupId>
51+
<artifactId>maven-shade-plugin</artifactId>
52+
<executions>
53+
<execution>
54+
<phase>package</phase>
55+
<goals>
56+
<goal>shade</goal>
57+
</goals>
58+
<configuration>
59+
<transformers>
60+
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
61+
<mainClass>io.prometheus.metrics.examples.httpserver.Main</mainClass>
62+
</transformer>
63+
</transformers>
64+
</configuration>
65+
</execution>
66+
</executions>
67+
</plugin>
68+
</plugins>
69+
</build>
70+
</project>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package io.prometheus.metrics.examples.httpserver;
2+
3+
import io.prometheus.metrics.core.metrics.Counter;
4+
import io.prometheus.metrics.exporter.httpserver.HTTPServer;
5+
import io.prometheus.metrics.model.snapshots.Unit;
6+
7+
import java.io.IOException;
8+
9+
/**
10+
* Simple example of an application exposing metrics via Prometheus' built-in HTTPServer.
11+
*/
12+
public class Main {
13+
14+
public static void main(String[] args) throws IOException, InterruptedException {
15+
16+
Counter counter = Counter.newBuilder()
17+
.withName("uptime_seconds_total")
18+
.withHelp("total number of seconds since this application was started")
19+
.withUnit(Unit.SECONDS)
20+
.register();
21+
22+
HTTPServer server = HTTPServer.newBuilder()
23+
.withPort(9400)
24+
.buildAndStart();
25+
26+
System.out.println("HTTPServer listening on port http://localhost:" + server.getPort() + "/metrics");
27+
28+
while (true) {
29+
Thread.sleep(1000);
30+
counter.inc();
31+
}
32+
}
33+
}

examples/example-tomcat-servlet/src/main/java/io/prometheus/metrics/examples/tomcat_servlet/Main.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,20 @@
66
import org.apache.catalina.startup.Tomcat;
77

88
import java.io.File;
9+
import java.io.IOException;
10+
import java.nio.file.Files;
11+
import java.nio.file.Path;
912

1013
/**
1114
* Simple example using embedded Tomcat and the {@link PrometheusMetricsServlet}.
1215
*/
1316
public class Main {
1417

15-
public static void main(String[] args) throws LifecycleException {
18+
public static void main(String[] args) throws LifecycleException, IOException {
1619

1720
Tomcat tomcat = new Tomcat();
18-
tomcat.setPort(8080);
21+
Path tmpDir = Files.createTempDirectory("prometheus-tomcat-servlet-example-");
22+
tomcat.setBaseDir(tmpDir.toFile().getAbsolutePath());
1923

2024
Context ctx = tomcat.addContext("", new File(".").getAbsolutePath());
2125

examples/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
</developers>
3434

3535
<modules>
36+
<module>example-httpserver</module>
3637
<module>example-tomcat-servlet</module>
3738
<module>example-exemplars-tail-sampling</module>
3839
</modules>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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>1.0.0-alpha-3-SNAPSHOT</version>
9+
</parent>
10+
11+
<artifactId>it-common</artifactId>
12+
13+
<name>Integration Tests - Common Utilities</name>
14+
<url>http://github.com/prometheus/client_java</url>
15+
<description>
16+
Common utilities for integration tests
17+
</description>
18+
19+
<licenses>
20+
<license>
21+
<name>The Apache Software License, Version 2.0</name>
22+
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
23+
<distribution>repo</distribution>
24+
</license>
25+
</licenses>
26+
27+
<dependencies>
28+
<dependency>
29+
<groupId>org.testcontainers</groupId>
30+
<artifactId>testcontainers</artifactId>
31+
<scope>test</scope>
32+
</dependency>
33+
</dependencies>
34+
35+
<build>
36+
<testResources>
37+
<testResource>
38+
<directory>src/test/resources</directory>
39+
<filtering>true</filtering>
40+
</testResource>
41+
</testResources>
42+
<plugins>
43+
<plugin>
44+
<groupId>org.apache.maven.plugins</groupId>
45+
<artifactId>maven-jar-plugin</artifactId>
46+
<executions>
47+
<execution>
48+
<goals>
49+
<goal>test-jar</goal>
50+
</goals>
51+
</execution>
52+
</executions>
53+
</plugin>
54+
</plugins>
55+
</build>
56+
</project>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package io.prometheus.client.it.common;
2+
3+
import org.testcontainers.containers.output.OutputFrame;
4+
5+
import java.util.function.Consumer;
6+
7+
/**
8+
* Print Docker logs from TestContainers to stdout or stderr.
9+
*/
10+
public class LogConsumer implements Consumer<OutputFrame> {
11+
12+
private final String prefix;
13+
14+
private LogConsumer(String prefix) {
15+
this.prefix = prefix;
16+
}
17+
18+
public static LogConsumer withPrefix(String prefix) {
19+
return new LogConsumer(prefix);
20+
}
21+
22+
@Override
23+
public void accept(OutputFrame outputFrame) {
24+
switch (outputFrame.getType()) {
25+
case STDOUT:
26+
System.out.print(prefix + " - " + outputFrame.getUtf8String());
27+
break;
28+
case END:
29+
System.out.println(prefix + " - END");
30+
break;
31+
default: // STDERR or unexpected
32+
System.err.print(prefix + " - " + outputFrame.getUtf8String());
33+
break;
34+
}
35+
}
36+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package io.prometheus.client.it.common;
2+
3+
import org.junit.Assert;
4+
5+
import java.io.File;
6+
import java.io.IOException;
7+
import java.net.URISyntaxException;
8+
import java.nio.file.*;
9+
import java.nio.file.attribute.BasicFileAttributes;
10+
import java.util.function.Predicate;
11+
12+
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
13+
14+
/**
15+
* Temporary directory in ./target/ to be mounted as a volume in Docker containers.
16+
*/
17+
public class Volume {
18+
19+
private final Path tmpDir; // will be created in the ./target/ directory
20+
21+
private Volume(Path tmpDir) {
22+
this.tmpDir = tmpDir;
23+
}
24+
25+
public static Volume create(String prefix) throws IOException, URISyntaxException {
26+
Path targetDir = Paths.get(Volume.class.getResource("/").toURI()).getParent();
27+
Assert.assertEquals("failed to locate target/ directory", "target", targetDir.getFileName().toString());
28+
return new Volume(Files.createTempDirectory(targetDir, prefix + "-"));
29+
}
30+
31+
/**
32+
* Copy a file or directory to this volume.
33+
* @param src is reltive to {@code ./target/}
34+
*/
35+
public Volume copy(String src) throws IOException {
36+
Path srcPath = tmpDir.getParent().resolve(src);
37+
if (Files.isRegularFile(srcPath)) {
38+
Files.copy(srcPath, tmpDir.resolve(srcPath.getFileName()), REPLACE_EXISTING);
39+
} else if (Files.isDirectory(srcPath)) {
40+
Path dest = tmpDir.resolve(srcPath.getFileName());
41+
Files.createDirectories(dest);
42+
Files.walkFileTree(srcPath, new SimpleFileVisitor<Path>() {
43+
44+
// create parent directories
45+
@Override
46+
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
47+
Files.createDirectories(dest.resolve(srcPath.relativize(dir)));
48+
return FileVisitResult.CONTINUE;
49+
}
50+
51+
// copy file
52+
@Override
53+
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
54+
Files.copy(file, dest.resolve(srcPath.relativize(file)), REPLACE_EXISTING);
55+
return FileVisitResult.CONTINUE;
56+
}
57+
});
58+
} else {
59+
Assert.fail(src + ": No such file or directory");
60+
}
61+
return this;
62+
}
63+
64+
/**
65+
* Remove files in tmpDir if they match the predicate.
66+
*/
67+
public void rm(Predicate<Path> predicate) throws IOException {
68+
Files.walkFileTree(tmpDir, new SimpleFileVisitor<Path>() {
69+
@Override
70+
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
71+
if (predicate.test(file)) {
72+
Files.delete(file);
73+
}
74+
return FileVisitResult.CONTINUE;
75+
}
76+
});
77+
}
78+
79+
public String getHostPath() {
80+
return tmpDir.toString();
81+
}
82+
83+
/**
84+
* Recursively remove tmpDir and its contents.
85+
*/
86+
public void remove() throws IOException {
87+
if (!deleteRecursively(tmpDir.toFile())) {
88+
throw new IOException(tmpDir + ": Failed to remove temporary test directory.");
89+
}
90+
}
91+
92+
private boolean deleteRecursively(File file) {
93+
File[] allContents = file.listFiles();
94+
if (allContents != null) {
95+
for (File child : allContents) {
96+
deleteRecursively(child);
97+
}
98+
}
99+
return file.delete();
100+
}
101+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# ${project.version} will be replaced by Maven at built time when this file is copied to the target/ directory.
2+
project.version=${project.version}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<ruleset comparisonMethod="maven"
2+
xmlns="http://mojo.codehaus.org/versions-maven-plugin/rule/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://mojo.codehaus.org/versions-maven-plugin/rule/2.0.0 https://www.mojohaus.org/versions-maven-plugin/xsd/rule-2.0.0.xsd">
4+
<rules>
5+
</rules>
6+
</ruleset>

0 commit comments

Comments
 (0)