From 793e9a8795e8c8ed3ef5f001f54c647197eaabcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Thu, 29 Aug 2024 12:02:02 -0600 Subject: [PATCH] Add OpenTelemetry Logging Service Connection from LgtmStackContainer and Docker Compose See gh-42174 --- ...nectionDetailsFactoryIntegrationTests.java | 40 +++++++++++ ...DockerComposeConnectionDetailsFactory.java | 5 +- .../pages/features/dev-services.adoc | 2 +- .../pages/testing/testcontainers.adoc | 2 +- ...nectionDetailsFactoryIntegrationTests.java | 66 ++++++++++++++++++ ...gingContainerConnectionDetailsFactory.java | 67 +++++++++++++++++++ .../main/resources/META-INF/spring.factories | 1 + 7 files changed, 180 insertions(+), 3 deletions(-) create mode 100644 spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/GrafanaOpenTelemetryLoggingDockerComposeConnectionDetailsFactoryIntegrationTests.java create mode 100644 spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactoryIntegrationTests.java create mode 100644 spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactory.java diff --git a/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/GrafanaOpenTelemetryLoggingDockerComposeConnectionDetailsFactoryIntegrationTests.java b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/GrafanaOpenTelemetryLoggingDockerComposeConnectionDetailsFactoryIntegrationTests.java new file mode 100644 index 000000000000..ab4dda44ca97 --- /dev/null +++ b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/GrafanaOpenTelemetryLoggingDockerComposeConnectionDetailsFactoryIntegrationTests.java @@ -0,0 +1,40 @@ +/* + * 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.logging.opentelemetry.otlp.OtlpLoggingConnectionDetails; +import org.springframework.boot.actuate.autoconfigure.opentelemetry.otlp.Transport; +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 OpenTelemetryLoggingDockerComposeConnectionDetailsFactory} + * using {@link TestImage#GRAFANA_OTEL_LGTM}. + * + * @author Eddú Meléndez + */ +class GrafanaOpenTelemetryLoggingDockerComposeConnectionDetailsFactoryIntegrationTests { + + @DockerComposeTest(composeFile = "otlp-compose.yaml", image = TestImage.GRAFANA_OTEL_LGTM) + void runCreatesConnectionDetails(OtlpLoggingConnectionDetails connectionDetails) { + assertThat(connectionDetails.getUrl(Transport.HTTP)).startsWith("http://").endsWith("/v1/logs"); + assertThat(connectionDetails.getUrl(Transport.GRPC)).startsWith("http://").endsWith("/v1/logs"); + } + +} diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryLoggingDockerComposeConnectionDetailsFactory.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryLoggingDockerComposeConnectionDetailsFactory.java index df4f0da1c32e..be18e0c4d3bd 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryLoggingDockerComposeConnectionDetailsFactory.java +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryLoggingDockerComposeConnectionDetailsFactory.java @@ -31,12 +31,15 @@ class OpenTelemetryLoggingDockerComposeConnectionDetailsFactory extends DockerComposeConnectionDetailsFactory { + private static final String[] OPENTELEMETRY_IMAGE_NAMES = { "otel/opentelemetry-collector-contrib", + "grafana/otel-lgtm" }; + private static final int OTLP_GRPC_PORT = 4317; private static final int OTLP_HTTP_PORT = 4318; OpenTelemetryLoggingDockerComposeConnectionDetailsFactory() { - super("otel/opentelemetry-collector-contrib", + super(OPENTELEMETRY_IMAGE_NAMES, "org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp.OtlpLoggingAutoConfiguration"); } 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 0eea9b29bdc7..f7e026d6aaf8 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,7 +108,7 @@ The following service connections are currently supported: | Containers named "neo4j" or "bitnami/neo4j" | `OtlpLoggingConnectionDetails` -| Containers named "otel/opentelemetry-collector-contrib" +| Containers named "otel/opentelemetry-collector-contrib", "grafana/otel-lgtm" | `OtlpMetricsConnectionDetails` | Containers named "otel/opentelemetry-collector-contrib", "grafana/otel-lgtm" 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 fd795b4f8775..7a0fde2bf30b 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,7 +72,7 @@ The following service connection factories are provided in the `spring-boot-test | Containers of type `Neo4jContainer` | `OtlpLoggingConnectionDetails` -| Containers named "otel/opentelemetry-collector-contrib" +| Containers named "otel/opentelemetry-collector-contrib" or of type `LgtmStackContainer` | `OtlpMetricsConnectionDetails` | Containers named "otel/opentelemetry-collector-contrib" or of type `LgtmStackContainer` diff --git a/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactoryIntegrationTests.java b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactoryIntegrationTests.java new file mode 100644 index 000000000000..bf5b60d20287 --- /dev/null +++ b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactoryIntegrationTests.java @@ -0,0 +1,66 @@ +/* + * 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.logging.opentelemetry.otlp.OtlpLoggingAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp.OtlpLoggingConnectionDetails; +import org.springframework.boot.actuate.autoconfigure.opentelemetry.otlp.Transport; +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 GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactory}. + * + * @author Eddú Meléndez + */ +@SpringJUnitConfig +@Testcontainers(disabledWithoutDocker = true) +class GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactoryIntegrationTests { + + @Container + @ServiceConnection + static final LgtmStackContainer container = TestImage.container(LgtmStackContainer.class); + + @Autowired + private OtlpLoggingConnectionDetails connectionDetails; + + @Test + void connectionCanBeMadeToOpenTelemetryContainer() { + assertThat(this.connectionDetails.getUrl(Transport.GRPC)) + .isEqualTo("%s/v1/logs".formatted(container.getOtlpGrpcUrl())); + assertThat(this.connectionDetails.getUrl(Transport.HTTP)) + .isEqualTo("%s/v1/logs".formatted(container.getOtlpHttpUrl())); + } + + @Configuration(proxyBeanMethods = false) + @ImportAutoConfiguration(OtlpLoggingAutoConfiguration.class) + static class TestConfiguration { + + } + +} diff --git a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactory.java b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactory.java new file mode 100644 index 000000000000..6e7085ae675d --- /dev/null +++ b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/otlp/GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactory.java @@ -0,0 +1,67 @@ +/* + * 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.logging.opentelemetry.otlp.OtlpLoggingConnectionDetails; +import org.springframework.boot.actuate.autoconfigure.opentelemetry.otlp.Transport; +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 OtlpLoggingConnectionDetails} from a + * {@link ServiceConnection @ServiceConnection}-annotated {@link LgtmStackContainer} using + * the {@code "grafana/otel-lgtm"} image. + * + * @author Eddú Meléndez + */ +class GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactory + extends ContainerConnectionDetailsFactory { + + GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactory() { + super(ANY_CONNECTION_NAME, + "org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp.OtlpLoggingAutoConfiguration"); + } + + @Override + protected OtlpLoggingConnectionDetails getContainerConnectionDetails( + ContainerConnectionSource source) { + return new OpenTelemetryLoggingContainerConnectionDetails(source); + } + + private static final class OpenTelemetryLoggingContainerConnectionDetails + extends ContainerConnectionDetails implements OtlpLoggingConnectionDetails { + + private OpenTelemetryLoggingContainerConnectionDetails(ContainerConnectionSource source) { + super(source); + } + + @Override + public String getUrl(Transport transport) { + String url = switch (transport) { + case HTTP -> getContainer().getOtlpHttpUrl(); + case GRPC -> getContainer().getOtlpGrpcUrl(); + }; + return "%s/v1/logs".formatted(url); + } + + } + +} 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 23f293f975e2..bd92b9665f14 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,7 @@ 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.GrafanaOpenTelemetryLoggingContainerConnectionDetailsFactory,\ org.springframework.boot.testcontainers.service.connection.otlp.GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactory,\ org.springframework.boot.testcontainers.service.connection.otlp.GrafanaOpenTelemetryTracingContainerConnectionDetailsFactory,\ org.springframework.boot.testcontainers.service.connection.otlp.OpenTelemetryLoggingContainerConnectionDetailsFactory,\