diff --git a/modules/grafana/src/main/java/org/testcontainers/grafana/LgtmStackContainer.java b/modules/grafana/src/main/java/org/testcontainers/grafana/LgtmStackContainer.java index 00299ac27f2..52443d7ba8a 100644 --- a/modules/grafana/src/main/java/org/testcontainers/grafana/LgtmStackContainer.java +++ b/modules/grafana/src/main/java/org/testcontainers/grafana/LgtmStackContainer.java @@ -31,6 +31,8 @@ public class LgtmStackContainer extends GenericContainer { private static final int OTLP_HTTP_PORT = 4318; + private static final int LOKI_PORT = 3100; + private static final int TEMPO_PORT = 3200; private static final int PROMETHEUS_PORT = 9090; @@ -42,7 +44,7 @@ public LgtmStackContainer(String image) { public LgtmStackContainer(DockerImageName image) { super(image); image.assertCompatibleWith(DEFAULT_IMAGE_NAME); - withExposedPorts(GRAFANA_PORT, TEMPO_PORT, OTLP_GRPC_PORT, OTLP_HTTP_PORT, PROMETHEUS_PORT); + withExposedPorts(GRAFANA_PORT, TEMPO_PORT, LOKI_PORT, OTLP_GRPC_PORT, OTLP_HTTP_PORT, PROMETHEUS_PORT); waitingFor( Wait.forLogMessage(".*The OpenTelemetry collector and the Grafana LGTM stack are up and running.*\\s", 1) ); @@ -61,6 +63,10 @@ public String getTempoUrl() { return "http://" + getHost() + ":" + getMappedPort(TEMPO_PORT); } + public String getLokiUrl() { + return "http://" + getHost() + ":" + getMappedPort(LOKI_PORT); + } + public String getOtlpHttpUrl() { return "http://" + getHost() + ":" + getMappedPort(OTLP_HTTP_PORT); } diff --git a/modules/grafana/src/test/java/org/testcontainers/grafana/LgtmStackContainerTest.java b/modules/grafana/src/test/java/org/testcontainers/grafana/LgtmStackContainerTest.java index a2b4f5a221a..ba4fb94856c 100644 --- a/modules/grafana/src/test/java/org/testcontainers/grafana/LgtmStackContainerTest.java +++ b/modules/grafana/src/test/java/org/testcontainers/grafana/LgtmStackContainerTest.java @@ -7,10 +7,14 @@ import io.micrometer.registry.otlp.OtlpMeterRegistry; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.logs.Logger; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.logs.SdkLoggerProvider; +import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.SdkTracerProvider; import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; @@ -28,20 +32,52 @@ public class LgtmStackContainerTest { @Test - public void shouldPublishMetricAndTrace() throws Exception { + public void shouldPublishMetricsTracesAndLogs() throws Exception { try ( // container { - LgtmStackContainer lgtm = new LgtmStackContainer("grafana/otel-lgtm:0.11.0") + LgtmStackContainer lgtm = new LgtmStackContainer("grafana/otel-lgtm:0.11.1") // } ) { lgtm.start(); + OtlpGrpcSpanExporter spanExporter = OtlpGrpcSpanExporter + .builder() + .setTimeout(Duration.ofSeconds(1)) + .setEndpoint(lgtm.getOtlpGrpcUrl()) + .build(); + + OtlpGrpcLogRecordExporter logExporter = OtlpGrpcLogRecordExporter + .builder() + .setTimeout(Duration.ofSeconds(1)) + .setEndpoint(lgtm.getOtlpGrpcUrl()) + .build(); + + BatchSpanProcessor spanProcessor = BatchSpanProcessor + .builder(spanExporter) + .setScheduleDelay(500, TimeUnit.MILLISECONDS) + .build(); + + SdkTracerProvider tracerProvider = SdkTracerProvider + .builder() + .addSpanProcessor(spanProcessor) + .setResource(Resource.create(Attributes.of(AttributeKey.stringKey("service.name"), "test-service"))) + .build(); + + SdkLoggerProvider loggerProvider = SdkLoggerProvider + .builder() + .addLogRecordProcessor(SimpleLogRecordProcessor.create(logExporter)) + .build(); + + OpenTelemetrySdk openTelemetry = OpenTelemetrySdk + .builder() + .setTracerProvider(tracerProvider) + .setLoggerProvider(loggerProvider) + .build(); + String version = RestAssured .get(String.format("http://%s:%s/api/health", lgtm.getHost(), lgtm.getMappedPort(3000))) .jsonPath() .get("version"); - assertThat(version).isEqualTo("11.6.0"); - - generateTrace(lgtm); + assertThat(version).isEqualTo("12.0.0"); OtlpConfig otlpConfig = createOtlpConfig(lgtm); MeterRegistry meterRegistry = SystemStubs @@ -49,65 +85,54 @@ public void shouldPublishMetricAndTrace() throws Exception { .execute(() -> new OtlpMeterRegistry(otlpConfig, Clock.SYSTEM)); Counter.builder("test.counter").register(meterRegistry).increment(2); + Logger logger = openTelemetry.getSdkLoggerProvider().loggerBuilder("test").build(); + logger + .logRecordBuilder() + .setBody("Test log!") + .setAttribute(AttributeKey.stringKey("job"), "test-job") + .emit(); + + Tracer tracer = openTelemetry.getTracer("test"); + Span span = tracer.spanBuilder("test").startSpan(); + span.end(); + Awaitility .given() .pollInterval(Duration.ofSeconds(2)) .atMost(Duration.ofSeconds(5)) .ignoreExceptions() .untilAsserted(() -> { - Response response = RestAssured + Response metricResponse = RestAssured .given() .queryParam("query", "test_counter_total{job=\"testcontainers\"}") .get(String.format("%s/api/v1/query", lgtm.getPrometheusHttpUrl())) .prettyPeek() .thenReturn(); - assertThat(response.getStatusCode()).isEqualTo(200); - assertThat(response.body().jsonPath().getList("data.result[0].value")).contains("2"); - }); + assertThat(metricResponse.getStatusCode()).isEqualTo(200); + assertThat(metricResponse.body().jsonPath().getList("data.result[0].value")).contains("2"); - Awaitility - .given() - .pollInterval(Duration.ofSeconds(2)) - .atMost(Duration.ofSeconds(5)) - .ignoreExceptions() - .untilAsserted(() -> { - Response response = RestAssured + Response logResponse = RestAssured + .given() + .queryParam("query", "{service_name=\"unknown_service:java\"}") + .get(String.format("%s/loki/api/v1/query_range", lgtm.getLokiUrl())) + .prettyPeek() + .thenReturn(); + assertThat(logResponse.getStatusCode()).isEqualTo(200); + assertThat(logResponse.body().jsonPath().getString("data.result[0].values[0][1]")) + .isEqualTo("Test log!"); + + Response traceResponse = RestAssured .given() .get(String.format("%s/api/search", lgtm.getTempoUrl())) .prettyPeek() .thenReturn(); - assertThat(response.getStatusCode()).isEqualTo(200); - assertThat(response.body().jsonPath().getString("traces[0].rootServiceName")) + assertThat(traceResponse.getStatusCode()).isEqualTo(200); + assertThat(traceResponse.body().jsonPath().getString("traces[0].rootServiceName")) .isEqualTo("test-service"); }); - } - } - - private void generateTrace(LgtmStackContainer lgtm) { - OtlpGrpcSpanExporter exporter = OtlpGrpcSpanExporter - .builder() - .setTimeout(Duration.ofSeconds(1)) - .setEndpoint(lgtm.getOtlpGrpcUrl()) - .build(); - BatchSpanProcessor spanProcessor = BatchSpanProcessor - .builder(exporter) - .setScheduleDelay(500, TimeUnit.MILLISECONDS) - .build(); - - SdkTracerProvider tracerProvider = SdkTracerProvider - .builder() - .addSpanProcessor(spanProcessor) - .setResource(Resource.create(Attributes.of(AttributeKey.stringKey("service.name"), "test-service"))) - .build(); - - OpenTelemetrySdk openTelemetry = OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).build(); - - Tracer tracer = openTelemetry.getTracer("test"); - Span span = tracer.spanBuilder("test").startSpan(); - span.end(); - - openTelemetry.shutdown(); + openTelemetry.close(); + } } private static OtlpConfig createOtlpConfig(LgtmStackContainer lgtm) {