Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add service connection from Testcontainers OpenTelemetry Collector #35082

Closed
Show file tree
Hide file tree
Changes from 3 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2012-2023 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.actuate.autoconfigure.metrics.export.otlp;

import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;

/**
* Details required to establish a connection to a OpenTelemetry Collector service.
*
* @author Eddú Meléndez
* @since 3.1.0
*/
public interface OtlpConnectionDetails extends ConnectionDetails {

String getUrl();

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2023 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.
Expand Down Expand Up @@ -53,10 +53,16 @@ public OtlpMetricsExportAutoConfiguration(OtlpProperties properties) {
this.properties = properties;
}

@Bean
@ConditionalOnMissingBean(OtlpConnectionDetails.class)
public OtlpConnectionDetails otlpConnectionDetails() {
return new PropertiesOtlpConnectionDetails(this.properties);
}

@Bean
@ConditionalOnMissingBean
public OtlpConfig otlpConfig() {
return new OtlpPropertiesConfigAdapter(this.properties);
public OtlpConfig otlpConfig(OtlpConnectionDetails connectionDetails) {
return new OtlpPropertiesConfigAdapter(this.properties, connectionDetails);
}

@Bean
Expand All @@ -65,4 +71,22 @@ public OtlpMeterRegistry otlpMeterRegistry(OtlpConfig otlpConfig, Clock clock) {
return new OtlpMeterRegistry(otlpConfig, clock);
}

/**
* Adapts {@link OtlpProperties} to {@link OtlpConnectionDetails}.
*/
static class PropertiesOtlpConnectionDetails implements OtlpConnectionDetails {

private final OtlpProperties properties;

PropertiesOtlpConnectionDetails(OtlpProperties properties) {
this.properties = properties;
}

@Override
public String getUrl() {
return this.properties.getUrl();
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@
*/
class OtlpPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<OtlpProperties> implements OtlpConfig {

OtlpPropertiesConfigAdapter(OtlpProperties properties) {
private final OtlpConnectionDetails connectionDetails;

OtlpPropertiesConfigAdapter(OtlpProperties properties, OtlpConnectionDetails connectionDetails) {
super(properties);
this.connectionDetails = connectionDetails;
}

@Override
Expand All @@ -42,7 +45,7 @@ public String prefix() {

@Override
public String url() {
return get(OtlpProperties::getUrl, OtlpConfig.super::url);
return get((properties) -> this.connectionDetails.getUrl(), OtlpConfig.super::url);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,24 @@ void allowsRegistryToBeCustomized() {
.hasBean("customRegistry"));
}

@Test
void definesPropertiesBasedConnectionDetailsByDefault() {
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
.run((context) -> assertThat(context)
.hasSingleBean(OtlpMetricsExportAutoConfiguration.PropertiesOtlpConnectionDetails.class));
}

@Test
void testConnectionFactoryWithOverridesWhenUsingCustomConnectionDetails() {
this.contextRunner.withUserConfiguration(BaseConfiguration.class, ConnectionDetailsConfiguration.class)
.run((context) -> {
assertThat(context).hasSingleBean(OtlpConnectionDetails.class)
.doesNotHaveBean(OtlpMetricsExportAutoConfiguration.PropertiesOtlpConnectionDetails.class);
OtlpConfig config = context.getBean(OtlpConfig.class);
assertThat(config.url()).isEqualTo("http://localhost:12345/v1/metrics");
});
}

@Configuration(proxyBeanMethods = false)
static class BaseConfiguration {

Expand Down Expand Up @@ -115,4 +133,14 @@ OtlpMeterRegistry customRegistry(OtlpConfig config, Clock clock) {

}

@Configuration(proxyBeanMethods = false)
static class ConnectionDetailsConfiguration {

@Bean
OtlpConnectionDetails otlpConnectionDetails() {
return () -> "http://localhost:12345/v1/metrics";
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,37 +34,42 @@ class OtlpPropertiesConfigAdapterTests {
void whenPropertiesUrlIsSetAdapterUrlReturnsIt() {
OtlpProperties properties = new OtlpProperties();
properties.setUrl("http://another-url:4318/v1/metrics");
assertThat(new OtlpPropertiesConfigAdapter(properties).url()).isEqualTo("http://another-url:4318/v1/metrics");
assertThat(otlpPropertiesConfigAdapter(properties).url()).isEqualTo("http://another-url:4318/v1/metrics");
}

@Test
void whenPropertiesAggregationTemporalityIsNotSetAdapterAggregationTemporalityReturnsCumulative() {
OtlpProperties properties = new OtlpProperties();
assertThat(new OtlpPropertiesConfigAdapter(properties).aggregationTemporality())
assertThat(otlpPropertiesConfigAdapter(properties).aggregationTemporality())
.isSameAs(AggregationTemporality.CUMULATIVE);
}

@Test
void whenPropertiesAggregationTemporalityIsSetAdapterAggregationTemporalityReturnsIt() {
OtlpProperties properties = new OtlpProperties();
properties.setAggregationTemporality(AggregationTemporality.DELTA);
assertThat(new OtlpPropertiesConfigAdapter(properties).aggregationTemporality())
assertThat(otlpPropertiesConfigAdapter(properties).aggregationTemporality())
.isSameAs(AggregationTemporality.DELTA);
}

@Test
void whenPropertiesResourceAttributesIsSetAdapterResourceAttributesReturnsIt() {
OtlpProperties properties = new OtlpProperties();
properties.setResourceAttributes(Map.of("service.name", "boot-service"));
assertThat(new OtlpPropertiesConfigAdapter(properties).resourceAttributes()).containsEntry("service.name",
assertThat(otlpPropertiesConfigAdapter(properties).resourceAttributes()).containsEntry("service.name",
"boot-service");
}

@Test
void whenPropertiesHeadersIsSetAdapterHeadersReturnsIt() {
OtlpProperties properties = new OtlpProperties();
properties.setHeaders(Map.of("header", "value"));
assertThat(new OtlpPropertiesConfigAdapter(properties).headers()).containsEntry("header", "value");
assertThat(otlpPropertiesConfigAdapter(properties).headers()).containsEntry("header", "value");
}

private static OtlpPropertiesConfigAdapter otlpPropertiesConfigAdapter(OtlpProperties properties) {
return new OtlpPropertiesConfigAdapter(properties,
new OtlpMetricsExportAutoConfiguration.PropertiesOtlpConnectionDetails(properties));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,9 @@ The following service connection factories are provided in the `spring-boot-test
| `Neo4jConnectionDetails`
| Containers of type `Neo4jContainer`

| `OtlpConnectionDetails`
| Containers named "otel/opentelemetry-collector-contrib"

| `R2dbcConnectionDetails`
| Containers of type `MariaDBContainer`, `MSSQLServerContainer`, `MySQLContainer`, `OracleContainer`, or `PostgreSQLContainer`

Expand Down
5 changes: 5 additions & 0 deletions spring-boot-project/spring-boot-testcontainers/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ description = "Spring Boot Testcontainers Support"
dependencies {
api(project(":spring-boot-project:spring-boot-autoconfigure"))

optional(project(":spring-boot-project:spring-boot-actuator-autoconfigure"))
optional("org.springframework:spring-test")
optional("org.springframework.data:spring-data-mongodb")
optional("org.springframework.data:spring-data-neo4j")
Expand All @@ -33,6 +34,10 @@ dependencies {

testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
testImplementation("ch.qos.logback:logback-classic")
testImplementation("io.micrometer:micrometer-registry-otlp")
testImplementation("io.rest-assured:rest-assured") {
exclude group: "commons-logging", module: "commons-logging"
}
testImplementation("org.assertj:assertj-core")
testImplementation("org.awaitility:awaitility")
testImplementation("org.influxdb:influxdb-java")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright 2012-2023 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.metrics.export.otlp.OtlpConnectionDetails;
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 OtlpConnectionDetails} from
* a {@link ServiceConnection @ServiceConnection}-annotated {@link GenericContainer} using
* the {@code "otel/opentelemetry-collector-contrib"} image.
*
* @author Eddú Meléndez
*/
class OpenTelemetryConnectionDetailsFactory
extends ContainerConnectionDetailsFactory<OtlpConnectionDetails, Container<?>> {

OpenTelemetryConnectionDetailsFactory() {
super("otel/opentelemetry-collector-contrib",
"org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsExportAutoConfiguration");
}

@Override
protected OtlpConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {
return new OpenTelemetryContainerConnectionDetails(source);
}

private static final class OpenTelemetryContainerConnectionDetails extends ContainerConnectionDetails
implements OtlpConnectionDetails {

private final String url;

private OpenTelemetryContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {
super(source);
this.url = "http://" + source.getContainer().getHost() + ":" + source.getContainer().getMappedPort(4318)
+ "/v1/metrics";
}

@Override
public String getUrl() {
return this.url;
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright 2012-2023 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.
*/

/**
* Support for testcontainers OpenTelemetry service connections.
*/
package org.springframework.boot.testcontainers.service.connection.otlp;
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ org.springframework.boot.testcontainers.service.connection.kafka.KafkaContainerC
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.OpenTelemetryConnectionDetailsFactory,\
org.springframework.boot.testcontainers.service.connection.r2dbc.MariaDbR2dbcContainerConnectionDetailsFactory,\
org.springframework.boot.testcontainers.service.connection.r2dbc.MsSqlServerR2dbcContainerConnectionDetailsFactory,\
org.springframework.boot.testcontainers.service.connection.r2dbc.MySqlR2dbcContainerConnectionDetailsFactory,\
Expand Down
Loading