Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 20 additions & 12 deletions examples/java/testcontainer/README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,41 @@
# Using Testcontainers

The provided code demonstrates how to use **Testcontainers** with **Grafana's LGTM stack** to test OpenTelemetry metrics in a Java application. Here's a step-by-step explanation:
The provided code demonstrates how to use **Testcontainers** with **Grafana's LGTM stack** to test OpenTelemetry metrics
in a Java application. Here's a step-by-step explanation:

1. **Set Up the Testcontainers Environment**:

- The `@Testcontainers` annotation enables the Testcontainers extension for JUnit 5.
- The `@Container` annotation is used to define a `LgtmStackContainer` that runs the Grafana LGTM stack in a Docker container.
- The `@Testcontainers` annotation enables the Testcontainers extension for JUnit 5.
- The `@Container` annotation is used to define a `LgtmStackContainer` that runs the Grafana LGTM stack in a Docker
container.

2. **Configure OpenTelemetry**:

- In the `@BeforeEach` method, system properties are set to configure the OpenTelemetry exporter to send metrics to the LGTM stack running in the container.
- In the `@BeforeEach` method, system properties are set to configure the OpenTelemetry exporter to send metrics to
the LGTM stack running in the container.

3. **Run the Application**:

- The `OtelApp` class initializes OpenTelemetry and generates a custom metric (`sold_items`) with attributes (e.g., `tenant`).
- The `OtelApp` class initializes OpenTelemetry and generates a custom metric (`sold_items`) with attributes (e.g.,
`tenant`) as well as a span representing the block the code.

4. **Test the Metrics Export**:
4. **Test Exporting Metrics and Traces**:

- The test method `testExportMetric` runs the application and queries the Prometheus endpoint in the LGTM stack to verify that the metric (`sold_items`) has been exported successfully.
- The `Awaitility` library is used to poll the Prometheus endpoint until the metric is found or a timeout occurs.
- The test method `testExportMetricsAndTraces` runs the application and queries the Prometheus and Tempo endpoints
in the LGTM stack to verify that the metric (`sold_items`) and span have been exported successfully.
- The `Awaitility` library is used to poll the endpoints until the telemetry is found or a timeout occurs.

5. **Debugging with Grafana**:
- The test outputs the Grafana URL (`lgtm.getGrafanaHttpUrl()`) to the console, allowing you to manually inspect the metrics in the Grafana UI.

- The test outputs the Grafana URL (`lgtm.getGrafanaHttpUrl()`) to the console, allowing you to manually inspect the
telemetry in the Grafana UI if needed.

## Example Usage

1. Start the test using `mvn test`.
2. Check the console output for the Grafana URL.
3. Open the Grafana UI, navigate to the Explore tab, and query the metrics.
4. The test will pass if the metric is successfully exported and found in Prometheus.
3. Open the Grafana UI, navigate to the Explore tab, and query the metrics or traces.
4. The test will pass if the metric and span are successfully exported and found in Prometheus and Tempo.

This setup is useful for validating OpenTelemetry instrumentation and ensuring metrics are correctly exported to a monitoring system.
This setup is useful for validating OpenTelemetry instrumentation and ensuring metrics are correctly exported to a
monitoring system.
2 changes: 1 addition & 1 deletion examples/java/testcontainer/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>

<groupId>com.grafana.example</groupId>
<artifactId>testcontaier</artifactId>
<artifactId>testcontainer</artifactId>
<version>1.0.0-SNAPSHOT</version>

<name>Java Testcontainer Demo</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.testcontainers.grafana.LgtmStackContainer;
Expand All @@ -18,42 +19,41 @@
@Testcontainers
public class TestcontainerTest {

@Container private final LgtmStackContainer lgtm = new LgtmStackContainer("grafana/otel-lgtm");
@Container
private final LgtmStackContainer lgtm = new LgtmStackContainer("grafana/otel-lgtm");

@BeforeEach
void setUp() {
System.setProperty("otel.exporter.otlp.endpoint", lgtm.getOtlpHttpUrl());
System.setProperty("otel.exporter.otlp.protocol", "http/protobuf");
System.setProperty("otel.resource.attributes", "service.name=otel-java-test");
System.setProperty("otel.metric.export.interval", "1s");
System.setProperty("otel.bsp.schedule.delay", "500ms");
}

@Test
void testExportMetric() {
// Howto:
// 1. The test with a really long timeout
void testExportMetricsAndTraces() throws InterruptedException {
// How to debug:
// 1. Run the test with a really long timeout (update the awaitility argument)
// 2. Go to the Grafana UI
// 3. Open the Explore tab
// 4. Select the Prometheus data source
// 5. Find your metric by name or attribute (e.g. "tenant1")
// 6. Click on the metric to see the details
// 7. Copy the query and paste it into the test
System.out.println("Grafana URL to debug telemetry: " + lgtm.getGrafanaHttpUrl());

var app = new OtelApp();
app.run();

HttpClient client = HttpClient.newHttpClient();
String query =
URLEncoder.encode(
"sold_items_total{job=\"otel-java-test\",service_name=\"otel-java-test\",tenant=\"tenant1\"}",
Comment thread
jaydeluca marked this conversation as resolved.
StandardCharsets.UTF_8);
String prometheusHttpUrl = lgtm.getPromehteusHttpUrl() + "/api/v1/query?query=" + query;
String prometheusHttpUrl = lgtm.getPrometheusHttpUrl() + "/api/v1/query?query=" + query;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(prometheusHttpUrl)).build();

// Total time: 18.448 s (for the whole test, will take longer when the image needs to be
// downloaded)
await()
.atMost(Duration.ofSeconds(10))
.until(
Expand All @@ -63,5 +63,18 @@ void testExportMetric() {
String body = response.body();
return response.statusCode() == 200 && body.contains("sold_items");
});

HttpRequest traceRequest = HttpRequest.newBuilder()
.uri(URI.create(String.format("%s/api/search", lgtm.getTempoUrl())))
.build();

await()
.atMost(Duration.ofSeconds(10))
.until(
() -> {
HttpResponse<String> response = client.send(traceRequest, HttpResponse.BodyHandlers.ofString());
String body = response.body();
return response.statusCode() == 200 && body.contains("otel-java-test");
});
}
}