diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingProperties.java index b7d484a9466a..eb2e3b82f6bd 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingProperties.java @@ -34,7 +34,7 @@ public class OtlpLoggingProperties { /** * URL to the OTel collector's HTTP API. */ - private String endpoint; + private String endpoint = "http://localhost:4318/v1/logs"; /** * Call timeout for the OTel Collector to process an exported batch of data. This diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingAutoConfigurationIntegrationTests.java index 71b4b55c9dd9..0e3e899c4468 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingAutoConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/opentelemetry/otlp/OtlpLoggingAutoConfigurationIntegrationTests.java @@ -45,7 +45,7 @@ * * @author Toshiaki Maki */ -public class OtlpLoggingAutoConfigurationIntegrationTests { +class OtlpLoggingAutoConfigurationIntegrationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withPropertyValues("spring.application.name=otlp-logs-test", diff --git a/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryLoggingDockerComposeConnectionDetailsFactoryIntegrationTests.java b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryLoggingDockerComposeConnectionDetailsFactoryIntegrationTests.java new file mode 100644 index 000000000000..239fdb0f5687 --- /dev/null +++ b/spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryLoggingDockerComposeConnectionDetailsFactoryIntegrationTests.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.logging.opentelemetry.otlp.OtlpLoggingConnectionDetails; +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}. + * + * @author Eddú Meléndez + */ +class OpenTelemetryLoggingDockerComposeConnectionDetailsFactoryIntegrationTests { + + @DockerComposeTest(composeFile = "otlp-compose.yaml", image = TestImage.OPENTELEMETRY) + void runCreatesConnectionDetails(OtlpLoggingConnectionDetails connectionDetails) { + assertThat(connectionDetails.getEndpoint()).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 new file mode 100644 index 000000000000..5a92fb199e1a --- /dev/null +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryLoggingDockerComposeConnectionDetailsFactory.java @@ -0,0 +1,65 @@ +/* + * 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.docker.compose.core.RunningService; +import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory; +import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource; + +/** + * {@link DockerComposeConnectionDetailsFactory} to create + * {@link OtlpLoggingConnectionDetails} for an OTLP service. + * + * @author Eddú Meléndez + */ +class OpenTelemetryLoggingDockerComposeConnectionDetailsFactory + extends DockerComposeConnectionDetailsFactory { + + private static final int OTLP_PORT = 4318; + + OpenTelemetryLoggingDockerComposeConnectionDetailsFactory() { + super("otel/opentelemetry-collector-contrib", + "org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp.OtlpLoggingAutoConfiguration"); + } + + @Override + protected OtlpLoggingConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) { + return new OpenTelemetryLoggingDockerComposeConnectionDetails(source.getRunningService()); + } + + private static final class OpenTelemetryLoggingDockerComposeConnectionDetails extends DockerComposeConnectionDetails + implements OtlpLoggingConnectionDetails { + + private final String host; + + private final int port; + + private OpenTelemetryLoggingDockerComposeConnectionDetails(RunningService source) { + super(source); + this.host = source.host(); + this.port = source.ports().get(OTLP_PORT); + } + + @Override + public String getEndpoint() { + return "http://%s:%d/v1/logs".formatted(this.host, this.port); + } + + } + +} diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-docker-compose/src/main/resources/META-INF/spring.factories index d5b70a5f7cc3..a532e257d139 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-docker-compose/src/main/resources/META-INF/spring.factories @@ -23,6 +23,7 @@ org.springframework.boot.docker.compose.service.connection.oracle.OracleFreeJdbc org.springframework.boot.docker.compose.service.connection.oracle.OracleXeJdbcDockerComposeConnectionDetailsFactory,\ org.springframework.boot.docker.compose.service.connection.oracle.OracleFreeR2dbcDockerComposeConnectionDetailsFactory,\ org.springframework.boot.docker.compose.service.connection.oracle.OracleXeR2dbcDockerComposeConnectionDetailsFactory,\ +org.springframework.boot.docker.compose.service.connection.otlp.OpenTelemetryLoggingDockerComposeConnectionDetailsFactory,\ org.springframework.boot.docker.compose.service.connection.otlp.OpenTelemetryMetricsDockerComposeConnectionDetailsFactory,\ org.springframework.boot.docker.compose.service.connection.otlp.OpenTelemetryTracingDockerComposeConnectionDetailsFactory,\ org.springframework.boot.docker.compose.service.connection.postgres.PostgresJdbcDockerComposeConnectionDetailsFactory,\ 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 a977998ca657..9b63f7548544 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 @@ -107,6 +107,9 @@ The following service connections are currently supported: | `Neo4jConnectionDetails` | Containers named "neo4j" or "bitnami/neo4j" +| `OtlpLoggingConnectionDetails` +| Containers named "otel/opentelemetry-collector-contrib" + | `OtlpMetricsConnectionDetails` | Containers named "otel/opentelemetry-collector-contrib" 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 3d2ff668e695..648616cb53ae 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 @@ -71,6 +71,9 @@ The following service connection factories are provided in the `spring-boot-test | `Neo4jConnectionDetails` | Containers of type `Neo4jContainer` +| `OtlpLoggingConnectionDetails` +| Containers named "otel/opentelemetry-collector-contrib" + | `OtlpMetricsConnectionDetails` | Containers named "otel/opentelemetry-collector-contrib" diff --git a/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/otlp/OpenTelemetryLoggingContainerConnectionDetailsFactoryIntegrationTests.java b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/otlp/OpenTelemetryLoggingContainerConnectionDetailsFactoryIntegrationTests.java new file mode 100644 index 000000000000..6ded3b289472 --- /dev/null +++ b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/otlp/OpenTelemetryLoggingContainerConnectionDetailsFactoryIntegrationTests.java @@ -0,0 +1,63 @@ +/* + * 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.containers.GenericContainer; +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.OtlpLoggingConnectionDetails; +import org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpAutoConfiguration; +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 OpenTelemetryLoggingContainerConnectionDetailsFactory}. + * + * @author Eddú Meléndez + */ +@SpringJUnitConfig +@Testcontainers(disabledWithoutDocker = true) +class OpenTelemetryLoggingContainerConnectionDetailsFactoryIntegrationTests { + + @Container + @ServiceConnection + static final GenericContainer container = TestImage.OPENTELEMETRY.genericContainer().withExposedPorts(4318); + + @Autowired + private OtlpLoggingConnectionDetails connectionDetails; + + @Test + void connectionCanBeMadeToOpenTelemetryContainer() { + assertThat(this.connectionDetails.getEndpoint()) + .isEqualTo("http://" + container.getHost() + ":" + container.getMappedPort(4318) + "/v1/logs"); + } + + @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/OpenTelemetryLoggingContainerConnectionDetailsFactory.java b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/otlp/OpenTelemetryLoggingContainerConnectionDetailsFactory.java new file mode 100644 index 000000000000..502a9655e64f --- /dev/null +++ b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/otlp/OpenTelemetryLoggingContainerConnectionDetailsFactory.java @@ -0,0 +1,63 @@ +/* + * 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.containers.Container; +import org.testcontainers.containers.GenericContainer; + +import org.springframework.boot.actuate.autoconfigure.logging.opentelemetry.otlp.OtlpLoggingConnectionDetails; +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 GenericContainer} using + * the {@code "otel/opentelemetry-collector-contrib"} image. + * + * @author Eddú Meléndez + */ +class OpenTelemetryLoggingContainerConnectionDetailsFactory + extends ContainerConnectionDetailsFactory, OtlpLoggingConnectionDetails> { + + OpenTelemetryLoggingContainerConnectionDetailsFactory() { + super("otel/opentelemetry-collector-contrib", + "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 getEndpoint() { + return "http://%s:%d/v1/logs".formatted(getContainer().getHost(), getContainer().getMappedPort(4318)); + } + + } + +} 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 813e438b31f6..4db781111e97 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.OpenTelemetryLoggingContainerConnectionDetailsFactory,\ org.springframework.boot.testcontainers.service.connection.otlp.OpenTelemetryMetricsContainerConnectionDetailsFactory,\ org.springframework.boot.testcontainers.service.connection.otlp.OpenTelemetryTracingContainerConnectionDetailsFactory,\ org.springframework.boot.testcontainers.service.connection.pulsar.PulsarContainerConnectionDetailsFactory,\