diff --git a/examples/prometheus/README.md b/examples/prometheus/README.md new file mode 100644 index 00000000000..4eb5a4600e4 --- /dev/null +++ b/examples/prometheus/README.md @@ -0,0 +1,41 @@ +# Prometheus Example + +This example demonstrates how to use the OpenTelemetry SDK +to instrument a simple application using Prometheus as the metric exporter and expose the metrics via HTTP. + +These are collected by a Prometheus instance which is configured to pull these metrics via HTTP. + +# How to run + +## Prerequisites +* Java 1.7 +* Docker 19.03 + +## 1 - Compile +```shell script +../gradlew fatJar +``` +## 2 - Run Prometheus + +Start Prometheus instance with a configuration that sets up a HTTP collection job for ```127.0.0.1:19090``` + +See [prometheus.yml](prometheus.yml) + +```shell script +docker run --network="host" --rm -it \ + --name prometheus \ + -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml \ + prom/prometheus + +``` + +## 3 - Start the Application +```shell script +java -cp build/libs/opentelemetry-examples-prometheus-all-0.1.0-SNAPSHOT.jar io.opentelemetry.example.PrometheusExample 19090 +``` +## 4 - Open the Prometheus UI + +Navigate to: + +http://localhost:9090/graph?g0.range_input=15m&g0.expr=incoming_messages&g0.tab=0 + diff --git a/examples/prometheus/build.gradle b/examples/prometheus/build.gradle new file mode 100644 index 00000000000..802d962d3c3 --- /dev/null +++ b/examples/prometheus/build.gradle @@ -0,0 +1,14 @@ +plugins { + id 'java' +} + +description = 'OpenTelemetry Example for Prometheus Exporter' +ext.moduleName = "io.opentelemetry.examples.prometheus" + +dependencies { + compile("io.opentelemetry:opentelemetry-api:${opentelemetryVersion}") + compile("io.opentelemetry:opentelemetry-sdk:${opentelemetryVersion}") + compile("io.opentelemetry:opentelemetry-exporters-prometheus:${opentelemetryVersion}") + compile("io.prometheus:simpleclient:0.8.1") + compile("io.prometheus:simpleclient_httpserver:0.8.1") +} diff --git a/examples/prometheus/prometheus.yml b/examples/prometheus/prometheus.yml new file mode 100644 index 00000000000..5160b3dfab4 --- /dev/null +++ b/examples/prometheus/prometheus.yml @@ -0,0 +1,30 @@ +global: + scrape_interval: 15s + scrape_timeout: 10s + evaluation_interval: 15s +alerting: + alertmanagers: + - static_configs: + - targets: [] + scheme: http + timeout: 10s + api_version: v1 +scrape_configs: +- job_name: prometheus + honor_timestamps: true + scrape_interval: 15s + scrape_timeout: 10s + metrics_path: /metrics + scheme: http + static_configs: + - targets: + - localhost:9090 +- job_name: otel_java_prometheus_example + honor_timestamps: true + scrape_interval: 15s + scrape_timeout: 10s + metrics_path: /metrics + scheme: http + static_configs: + - targets: + - 127.0.0.1:19090 diff --git a/examples/prometheus/src/main/java/io/opentelemetry/example/PrometheusExample.java b/examples/prometheus/src/main/java/io/opentelemetry/example/PrometheusExample.java new file mode 100644 index 00000000000..ffedb582aca --- /dev/null +++ b/examples/prometheus/src/main/java/io/opentelemetry/example/PrometheusExample.java @@ -0,0 +1,86 @@ +package io.opentelemetry.example; + +import io.opentelemetry.common.Labels; +import io.opentelemetry.exporters.prometheus.PrometheusCollector; +import io.opentelemetry.metrics.AsynchronousInstrument; +import io.opentelemetry.metrics.LongValueObserver; +import io.opentelemetry.metrics.Meter; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.metrics.MeterSdkProvider; +import io.prometheus.client.exporter.HTTPServer; +import java.io.IOException; +import java.util.concurrent.ThreadLocalRandom; + +/** + * Example of using the {@link PrometheusCollector} to convert OTel metrics to Prometheus format and + * expose these to a Prometheus instance via a {@link HTTPServer} exporter. + * + *

A {@link LongValueObserver} is used to periodically measure how many incoming messages are + * awaiting processing. The {@link LongValueObserver.Callback} gets executed every collection + * interval. + */ +public class PrometheusExample { + + private final MeterSdkProvider meterSdkProvider = OpenTelemetrySdk.getMeterProvider(); + private final Meter meter = meterSdkProvider.get("PrometheusExample", "0.7"); + private final HTTPServer server; + private long incomingMessageCount; + + public PrometheusExample(int port) throws IOException { + + LongValueObserver observer = + meter + .longValueObserverBuilder("incoming.messages") + .setDescription("No of incoming messages awaiting processing") + .setUnit("message") + .build(); + + observer.setCallback( + new LongValueObserver.Callback() { + @Override + public void update(AsynchronousInstrument.LongResult result) { + result.observe(incomingMessageCount, Labels.empty()); + } + }); + + PrometheusCollector.newBuilder() + .setMetricProducer(meterSdkProvider.getMetricProducer()) + .buildAndRegister(); + + server = new HTTPServer(port); + } + + void shutdown() { + server.stop(); + } + + void simulate() { + for (int i = 300; i > 0; i--) { + try { + System.out.println( + i + " Iterations to go, current incomingMessageCount is: " + incomingMessageCount); + incomingMessageCount = ThreadLocalRandom.current().nextLong(100); + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + } + + public static void main(String[] args) throws IOException { + + int port = 0; + try { + port = Integer.parseInt(args[0]); + } catch (Exception e) { + System.out.println("Port not set, or is invalid. Exiting"); + System.exit(1); + } + + PrometheusExample prometheusExample = new PrometheusExample(port); + + prometheusExample.simulate(); + prometheusExample.shutdown(); + + System.out.println("Exiting"); + } +} diff --git a/examples/settings.gradle b/examples/settings.gradle index 6b395e42873..e07bd1e2d34 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -16,6 +16,7 @@ include ":opentelemetry-examples-grpc", ":opentelemetry-examples-http", ":opentelemetry-examples-jaeger", ":opentelemetry-examples-metrics", + ":opentelemetry-examples-prometheus", ":opentelemetry-examples-sdk-usage", ":opentelemetry-examples-zipkin"