diff --git a/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/GrafanaOpenTelemetryMetricsDockerComposeConnectionDetailsFactoryIntegrationTests.java b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/GrafanaOpenTelemetryMetricsDockerComposeConnectionDetailsFactoryIntegrationTests.java new file mode 100644 index 00000000000..81f9632a392 --- /dev/null +++ b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/GrafanaOpenTelemetryMetricsDockerComposeConnectionDetailsFactoryIntegrationTests.java @@ -0,0 +1,38 @@ +/* + * Copyright 2012-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.docker.compose.service.connection.otlp; + +import org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsConnectionDetails; +import org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest; +import org.springframework.boot.testsupport.container.TestImage; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for {@link OpenTelemetryMetricsDockerComposeConnectionDetailsFactory} + * using {@link TestImage#GRAFANA_OTEL_LGTM}. + * + * @author Eddú Meléndez + */ +class GrafanaOpenTelemetryMetricsDockerComposeConnectionDetailsFactoryIntegrationTests { + + @DockerComposeTest(composeFile = "otlp-compose.yaml", image = TestImage.GRAFANA_OTEL_LGTM) + void runCreatesConnectionDetails(OtlpMetricsConnectionDetails connectionDetails) { + assertThat(connectionDetails.getUrl()).startsWith("http://").endsWith("/v1/metrics"); + } + +} diff --git a/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/GrafanaOpenTelemetryTracingDockerComposeConnectionDetailsFactoryIntegrationTests.java b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/GrafanaOpenTelemetryTracingDockerComposeConnectionDetailsFactoryIntegrationTests.java new file mode 100644 index 00000000000..f5158cef6d6 --- /dev/null +++ b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/GrafanaOpenTelemetryTracingDockerComposeConnectionDetailsFactoryIntegrationTests.java @@ -0,0 +1,38 @@ +/* + * Copyright 2012-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.docker.compose.service.connection.otlp; + +import org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpTracingConnectionDetails; +import org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest; +import org.springframework.boot.testsupport.container.TestImage; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for {@link OpenTelemetryTracingDockerComposeConnectionDetailsFactory} + * using {@link TestImage#GRAFANA_OTEL_LGTM}. + * + * @author Eddú Meléndez + */ +class GrafanaOpenTelemetryTracingDockerComposeConnectionDetailsFactoryIntegrationTests { + + @DockerComposeTest(composeFile = "otlp-compose.yaml", image = TestImage.GRAFANA_OTEL_LGTM) + void runCreatesConnectionDetails(OtlpTracingConnectionDetails connectionDetails) { + assertThat(connectionDetails.getUrl()).startsWith("http://").endsWith("/v1/traces"); + } + +} diff --git a/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryMetricsDockerComposeConnectionDetailsFactoryIntegrationTests.java b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryMetricsDockerComposeConnectionDetailsFactoryIntegrationTests.java index 3ec07184e9e..c885e10636c 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryMetricsDockerComposeConnectionDetailsFactoryIntegrationTests.java +++ b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryMetricsDockerComposeConnectionDetailsFactoryIntegrationTests.java @@ -23,8 +23,8 @@ import org.springframework.boot.testsupport.container.TestImage; import static org.assertj.core.api.Assertions.assertThat; /** - * Integration tests for - * {@link OpenTelemetryMetricsDockerComposeConnectionDetailsFactory}. + * Integration tests for {@link OpenTelemetryMetricsDockerComposeConnectionDetailsFactory} + * using {@link TestImage#OPENTELEMETRY}. * * @author Eddú Meléndez */ diff --git a/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryTracingDockerComposeConnectionDetailsFactoryIntegrationTests.java b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryTracingDockerComposeConnectionDetailsFactoryIntegrationTests.java index 97fc794c628..50a713e7fdb 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryTracingDockerComposeConnectionDetailsFactoryIntegrationTests.java +++ b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryTracingDockerComposeConnectionDetailsFactoryIntegrationTests.java @@ -23,8 +23,8 @@ import org.springframework.boot.testsupport.container.TestImage; import static org.assertj.core.api.Assertions.assertThat; /** - * Integration tests for - * {@link OpenTelemetryTracingDockerComposeConnectionDetailsFactory}. + * Integration tests for {@link OpenTelemetryTracingDockerComposeConnectionDetailsFactory} + * using {@link TestImage#OPENTELEMETRY}. * * @author Eddú Meléndez */ diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryMetricsDockerComposeConnectionDetailsFactory.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryMetricsDockerComposeConnectionDetailsFactory.java index 49913297040..419bf357bee 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryMetricsDockerComposeConnectionDetailsFactory.java +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryMetricsDockerComposeConnectionDetailsFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,10 +30,13 @@ import org.springframework.boot.docker.compose.service.connection.DockerComposeC class OpenTelemetryMetricsDockerComposeConnectionDetailsFactory extends DockerComposeConnectionDetailsFactory { + private static final String[] OPENTELEMETRY_IMAGE_NAMES = { "otel/opentelemetry-collector-contrib", + "grafana/otel-lgtm" }; + private static final int OTLP_PORT = 4318; OpenTelemetryMetricsDockerComposeConnectionDetailsFactory() { - super("otel/opentelemetry-collector-contrib", + super(OPENTELEMETRY_IMAGE_NAMES, "org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsExportAutoConfiguration"); } diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryTracingDockerComposeConnectionDetailsFactory.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryTracingDockerComposeConnectionDetailsFactory.java index 20e5b06b3da..d2be0b11eec 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryTracingDockerComposeConnectionDetailsFactory.java +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryTracingDockerComposeConnectionDetailsFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,10 +30,13 @@ import org.springframework.boot.docker.compose.service.connection.DockerComposeC class OpenTelemetryTracingDockerComposeConnectionDetailsFactory extends DockerComposeConnectionDetailsFactory { + private static final String[] OPENTELEMETRY_IMAGE_NAMES = { "otel/opentelemetry-collector-contrib", + "grafana/otel-lgtm" }; + private static final int OTLP_PORT = 4318; OpenTelemetryTracingDockerComposeConnectionDetailsFactory() { - super("otel/opentelemetry-collector-contrib", + super(OPENTELEMETRY_IMAGE_NAMES, "org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpAutoConfiguration"); } diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/dev-services.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/dev-services.adoc index 7190c0ee320..fe59b9d944f 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/dev-services.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/dev-services.adoc @@ -108,10 +108,10 @@ The following service connections are currently supported: | Containers named "neo4j" or "bitnami/neo4j" | `OtlpMetricsConnectionDetails` -| Containers named "otel/opentelemetry-collector-contrib" +| Containers named "otel/opentelemetry-collector-contrib", "grafana/otel-lgtm" | `OtlpTracingConnectionDetails` -| Containers named "otel/opentelemetry-collector-contrib" +| Containers named "otel/opentelemetry-collector-contrib", "grafana/otel-lgtm" | `PulsarConnectionDetails` | Containers named "apachepulsar/pulsar" diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc index 0ee1dcab5aa..2e1f7b157f7 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc @@ -72,10 +72,10 @@ The following service connection factories are provided in the `spring-boot-test | Containers of type `Neo4jContainer` | `OtlpMetricsConnectionDetails` -| Containers named "otel/opentelemetry-collector-contrib" +| Containers named "otel/opentelemetry-collector-contrib" or of type `LgtmStackContainer` | `OtlpTracingConnectionDetails` -| Containers named "otel/opentelemetry-collector-contrib" +| Containers named "otel/opentelemetry-collector-contrib" or of type `LgtmStackContainer` | `PulsarConnectionDetails` | Containers of type `PulsarContainer` diff --git a/spring-boot-project/spring-boot-testcontainers/build.gradle b/spring-boot-project/spring-boot-testcontainers/build.gradle index c78397114e9..6bf43ef0df0 100644 --- a/spring-boot-project/spring-boot-testcontainers/build.gradle +++ b/spring-boot-project/spring-boot-testcontainers/build.gradle @@ -66,6 +66,7 @@ dependencies { optional("org.testcontainers:cassandra") optional("org.testcontainers:couchbase") optional("org.testcontainers:elasticsearch") + optional("org.testcontainers:grafana") optional("org.testcontainers:jdbc") optional("org.testcontainers:kafka") optional("org.testcontainers:mariadb") diff --git a/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactoryIntegrationTests.java b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactoryIntegrationTests.java new file mode 100644 index 00000000000..fed9b1ed063 --- /dev/null +++ b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactoryIntegrationTests.java @@ -0,0 +1,129 @@ +/* + * Copyright 2012-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.testcontainers.service.connection.otlp; + +import java.time.Duration; + +import io.micrometer.core.instrument.Clock; +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.DistributionSummary; +import io.micrometer.core.instrument.Gauge; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Timer; +import io.restassured.RestAssured; +import io.restassured.response.Response; +import org.awaitility.Awaitility; +import org.junit.jupiter.api.Test; +import org.testcontainers.grafana.LgtmStackContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsExportAutoConfiguration; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.boot.testsupport.container.TestImage; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactory}. + * + * @author Eddú Meléndez + */ +@SpringJUnitConfig +@TestPropertySource(properties = { "management.otlp.metrics.export.resource-attributes.service.name=test", + "management.otlp.metrics.export.step=1s" }) +@Testcontainers(disabledWithoutDocker = true) +class GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactoryIntegrationTests { + + @Container + @ServiceConnection + static final LgtmStackContainer container = TestImage.container(LgtmStackContainer.class); + + @Autowired + private MeterRegistry meterRegistry; + + @Test + void connectionCanBeMadeToOpenTelemetryCollectorContainer() { + Counter.builder("test.counter").register(this.meterRegistry).increment(42); + Gauge.builder("test.gauge", () -> 12).register(this.meterRegistry); + Timer.builder("test.timer").register(this.meterRegistry).record(Duration.ofMillis(123)); + DistributionSummary.builder("test.distributionsummary").register(this.meterRegistry).record(24); + + Awaitility.given() + .pollInterval(Duration.ofSeconds(2)) + .atMost(Duration.ofSeconds(10)) + .ignoreExceptions() + .untilAsserted(() -> { + Response response = RestAssured.given() + .queryParam("query", "{job=\"test\"}") + .get("%s/api/v1/query".formatted(container.getPromehteusHttpUrl())) + .prettyPeek() + .thenReturn(); + assertThat(response.getStatusCode()).isEqualTo(200); + assertThat(response.body() + .jsonPath() + .getList("data.result.find { it.metric.__name__ == 'test_counter_total' }.value")).contains("42"); + assertThat(response.body() + .jsonPath() + .getList("data.result.find { it.metric.__name__ == 'test_gauge' }.value")).contains("12"); + assertThat(response.body() + .jsonPath() + .getList("data.result.find { it.metric.__name__ == 'test_timer_milliseconds_count' }.value")) + .contains("1"); + assertThat(response.body() + .jsonPath() + .getList("data.result.find { it.metric.__name__ == 'test_timer_milliseconds_sum' }.value")) + .contains("123"); + assertThat(response.body() + .jsonPath() + .getList( + "data.result.find { it.metric.__name__ == 'test_timer_milliseconds_bucket' & it.metric.le == '+Inf' }.value")) + .contains("1"); + assertThat(response.body() + .jsonPath() + .getList("data.result.find { it.metric.__name__ == 'test_distributionsummary_count' }.value")) + .contains("1"); + assertThat(response.body() + .jsonPath() + .getList("data.result.find { it.metric.__name__ == 'test_distributionsummary_sum' }.value")) + .contains("24"); + assertThat(response.body() + .jsonPath() + .getList( + "data.result.find { it.metric.__name__ == 'test_distributionsummary_bucket' & it.metric.le == '+Inf' }.value")) + .contains("1"); + }); + } + + @Configuration(proxyBeanMethods = false) + @ImportAutoConfiguration(OtlpMetricsExportAutoConfiguration.class) + static class TestConfiguration { + + @Bean + Clock customClock() { + return Clock.SYSTEM; + } + + } + +} diff --git a/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryTracingContainerConnectionDetailsFactoryIntegrationTests.java b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryTracingContainerConnectionDetailsFactoryIntegrationTests.java new file mode 100644 index 00000000000..c5139145665 --- /dev/null +++ b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryTracingContainerConnectionDetailsFactoryIntegrationTests.java @@ -0,0 +1,62 @@ +/* + * Copyright 2012-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.testcontainers.service.connection.otlp; + +import org.junit.jupiter.api.Test; +import org.testcontainers.grafana.LgtmStackContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpTracingConnectionDetails; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.boot.testsupport.container.TestImage; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link GrafanaOpenTelemetryTracingContainerConnectionDetailsFactory}. + * + * @author Eddú Meléndez + */ +@SpringJUnitConfig +@Testcontainers(disabledWithoutDocker = true) +class GrafanaOpenTelemetryTracingContainerConnectionDetailsFactoryIntegrationTests { + + @Container + @ServiceConnection + static final LgtmStackContainer container = TestImage.container(LgtmStackContainer.class); + + @Autowired + private OtlpTracingConnectionDetails connectionDetails; + + @Test + void connectionCanBeMadeToOpenTelemetryContainer() { + assertThat(this.connectionDetails.getUrl()).isEqualTo("%s/v1/traces".formatted(container.getOtlpHttpUrl())); + } + + @Configuration(proxyBeanMethods = false) + @ImportAutoConfiguration(OtlpAutoConfiguration.class) + static class TestConfiguration { + + } + +} diff --git a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactory.java b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactory.java new file mode 100644 index 00000000000..130e6d6ffe7 --- /dev/null +++ b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactory.java @@ -0,0 +1,62 @@ +/* + * Copyright 2012-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.testcontainers.service.connection.otlp; + +import org.testcontainers.grafana.LgtmStackContainer; + +import org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsConnectionDetails; +import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory; +import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; + +/** + * {@link ContainerConnectionDetailsFactory} to create + * {@link OtlpMetricsConnectionDetails} from a + * {@link ServiceConnection @ServiceConnection}-annotated {@link LgtmStackContainer} using + * the {@code "grafana/otel-lgtmb"} image. + * + * @author Eddú Meléndez + */ +class GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactory + extends ContainerConnectionDetailsFactory { + + GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactory() { + super(ANY_CONNECTION_NAME, + "org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsExportAutoConfiguration"); + } + + @Override + protected OtlpMetricsConnectionDetails getContainerConnectionDetails( + ContainerConnectionSource source) { + return new OpenTelemetryMetricsContainerConnectionDetails(source); + } + + private static final class OpenTelemetryMetricsContainerConnectionDetails + extends ContainerConnectionDetails implements OtlpMetricsConnectionDetails { + + private OpenTelemetryMetricsContainerConnectionDetails(ContainerConnectionSource source) { + super(source); + } + + @Override + public String getUrl() { + return "%s/v1/metrics".formatted(getContainer().getOtlpHttpUrl()); + } + + } + +} diff --git a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryTracingContainerConnectionDetailsFactory.java b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryTracingContainerConnectionDetailsFactory.java new file mode 100644 index 00000000000..eb03927598a --- /dev/null +++ b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryTracingContainerConnectionDetailsFactory.java @@ -0,0 +1,61 @@ +/* + * Copyright 2012-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.testcontainers.service.connection.otlp; + +import org.testcontainers.grafana.LgtmStackContainer; + +import org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpTracingConnectionDetails; +import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory; +import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; + +/** + * {@link ContainerConnectionDetailsFactory} to create + * {@link OtlpTracingConnectionDetails} from a + * {@link ServiceConnection @ServiceConnection}-annotated {@link LgtmStackContainer} using + * the {@code "grafana/otel-lgtm"} image. + * + * @author Eddú Meléndez + */ +class GrafanaOpenTelemetryTracingContainerConnectionDetailsFactory + extends ContainerConnectionDetailsFactory { + + GrafanaOpenTelemetryTracingContainerConnectionDetailsFactory() { + super(ANY_CONNECTION_NAME, "org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpAutoConfiguration"); + } + + @Override + protected OtlpTracingConnectionDetails getContainerConnectionDetails( + ContainerConnectionSource source) { + return new OpenTelemetryTracingContainerConnectionDetails(source); + } + + private static final class OpenTelemetryTracingContainerConnectionDetails + extends ContainerConnectionDetails implements OtlpTracingConnectionDetails { + + private OpenTelemetryTracingContainerConnectionDetails(ContainerConnectionSource source) { + super(source); + } + + @Override + public String getUrl() { + return "%s/v1/traces".formatted(getContainer().getOtlpHttpUrl()); + } + + } + +} diff --git a/spring-boot-project/spring-boot-testcontainers/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-testcontainers/src/main/resources/META-INF/spring.factories index 813e438b31f..6e222c0012b 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-testcontainers/src/main/resources/META-INF/spring.factories @@ -23,6 +23,8 @@ org.springframework.boot.testcontainers.service.connection.ldap.OpenLdapContaine org.springframework.boot.testcontainers.service.connection.liquibase.LiquibaseContainerConnectionDetailsFactory,\ org.springframework.boot.testcontainers.service.connection.mongo.MongoContainerConnectionDetailsFactory,\ org.springframework.boot.testcontainers.service.connection.neo4j.Neo4jContainerConnectionDetailsFactory,\ +org.springframework.boot.testcontainers.service.connection.otlp.GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactory,\ +org.springframework.boot.testcontainers.service.connection.otlp.GrafanaOpenTelemetryTracingContainerConnectionDetailsFactory,\ org.springframework.boot.testcontainers.service.connection.otlp.OpenTelemetryMetricsContainerConnectionDetailsFactory,\ org.springframework.boot.testcontainers.service.connection.otlp.OpenTelemetryTracingContainerConnectionDetailsFactory,\ org.springframework.boot.testcontainers.service.connection.pulsar.PulsarContainerConnectionDetailsFactory,\ diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support-docker/build.gradle b/spring-boot-project/spring-boot-tools/spring-boot-test-support-docker/build.gradle index 41a47c555a6..967cc8dc958 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-test-support-docker/build.gradle +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support-docker/build.gradle @@ -20,6 +20,7 @@ dependencies { optional("org.testcontainers:cassandra") optional("org.testcontainers:couchbase") optional("org.testcontainers:elasticsearch") + optional("org.testcontainers:grafana") optional("org.testcontainers:junit-jupiter") optional("org.testcontainers:kafka") optional("org.testcontainers:mongodb") diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support-docker/src/main/java/org/springframework/boot/testsupport/container/TestImage.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support-docker/src/main/java/org/springframework/boot/testsupport/container/TestImage.java index 0c3c024a029..26c5a3eb27b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-test-support-docker/src/main/java/org/springframework/boot/testsupport/container/TestImage.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support-docker/src/main/java/org/springframework/boot/testsupport/container/TestImage.java @@ -36,6 +36,7 @@ import org.testcontainers.containers.PulsarContainer; import org.testcontainers.containers.RabbitMQContainer; import org.testcontainers.couchbase.CouchbaseContainer; import org.testcontainers.elasticsearch.ElasticsearchContainer; +import org.testcontainers.grafana.LgtmStackContainer; import org.testcontainers.redpanda.RedpandaContainer; import org.testcontainers.utility.DockerImageName; @@ -100,6 +101,12 @@ public enum TestImage { */ ELASTICSEARCH_8("elasticsearch", "8.6.1"), + /** + * A container image suitable for testing Grafana OTel LGTM. + */ + GRAFANA_OTEL_LGTM("grafana/otel-lgtm", "0.6.0", () -> LgtmStackContainer.class, + (container) -> ((LgtmStackContainer) container).withStartupTimeout(Duration.ofMinutes(2))), + /** * A container image suitable for testing Confluent's distribution of Kafka. */