Skip to content

Commit 8563165

Browse files
committed
Add service connection from Testcontainers OpenTelemetry Collector
1 parent c55d398 commit 8563165

File tree

13 files changed

+362
-10
lines changed

13 files changed

+362
-10
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsExportAutoConfiguration.java

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2022 the original author or authors.
2+
* Copyright 2012-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@
2929
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
3030
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
3131
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
32+
import org.springframework.boot.autoconfigure.otlp.OtlpConnectionDetails;
3233
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3334
import org.springframework.context.annotation.Bean;
3435

@@ -53,10 +54,16 @@ public OtlpMetricsExportAutoConfiguration(OtlpProperties properties) {
5354
this.properties = properties;
5455
}
5556

57+
@Bean
58+
@ConditionalOnMissingBean(OtlpConnectionDetails.class)
59+
public OtlpConnectionDetails otlpConnectionDetails() {
60+
return new PropertiesOtlpConnectionDetails(this.properties);
61+
}
62+
5663
@Bean
5764
@ConditionalOnMissingBean
58-
public OtlpConfig otlpConfig() {
59-
return new OtlpPropertiesConfigAdapter(this.properties);
65+
public OtlpConfig otlpConfig(OtlpConnectionDetails connectionDetails) {
66+
return new OtlpPropertiesConfigAdapter(this.properties, connectionDetails);
6067
}
6168

6269
@Bean
@@ -65,4 +72,22 @@ public OtlpMeterRegistry otlpMeterRegistry(OtlpConfig otlpConfig, Clock clock) {
6572
return new OtlpMeterRegistry(otlpConfig, clock);
6673
}
6774

75+
/**
76+
* Adapts {@link OtlpProperties} to {@link OtlpConnectionDetails}.
77+
*/
78+
static class PropertiesOtlpConnectionDetails implements OtlpConnectionDetails {
79+
80+
private final OtlpProperties properties;
81+
82+
PropertiesOtlpConnectionDetails(OtlpProperties properties) {
83+
this.properties = properties;
84+
}
85+
86+
@Override
87+
public String getUrl() {
88+
return this.properties.getUrl();
89+
}
90+
91+
}
92+
6893
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesConfigAdapter.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import io.micrometer.registry.otlp.OtlpConfig;
2323

2424
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesConfigAdapter;
25+
import org.springframework.boot.autoconfigure.otlp.OtlpConnectionDetails;
2526

2627
/**
2728
* Adapter to convert {@link OtlpProperties} to an {@link OtlpConfig}.
@@ -31,8 +32,11 @@
3132
*/
3233
class OtlpPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<OtlpProperties> implements OtlpConfig {
3334

34-
OtlpPropertiesConfigAdapter(OtlpProperties properties) {
35+
private final OtlpConnectionDetails connectionDetails;
36+
37+
OtlpPropertiesConfigAdapter(OtlpProperties properties, OtlpConnectionDetails connectionDetails) {
3538
super(properties);
39+
this.connectionDetails = connectionDetails;
3640
}
3741

3842
@Override
@@ -42,7 +46,7 @@ public String prefix() {
4246

4347
@Override
4448
public String url() {
45-
return get(OtlpProperties::getUrl, OtlpConfig.super::url);
49+
return get((properties) -> this.connectionDetails.getUrl(), OtlpConfig.super::url);
4650
}
4751

4852
@Override

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsExportAutoConfigurationTests.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.junit.jupiter.api.Test;
2323

2424
import org.springframework.boot.autoconfigure.AutoConfigurations;
25+
import org.springframework.boot.autoconfigure.otlp.OtlpConnectionDetails;
2526
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
2627
import org.springframework.context.annotation.Bean;
2728
import org.springframework.context.annotation.Configuration;
@@ -83,6 +84,24 @@ void allowsRegistryToBeCustomized() {
8384
.hasBean("customRegistry"));
8485
}
8586

87+
@Test
88+
void definesPropertiesBasedConnectionDetailsByDefault() {
89+
this.contextRunner.withUserConfiguration(BaseConfiguration.class)
90+
.run((context) -> assertThat(context)
91+
.hasSingleBean(OtlpMetricsExportAutoConfiguration.PropertiesOtlpConnectionDetails.class));
92+
}
93+
94+
@Test
95+
void testConnectionFactoryWithOverridesWhenUsingCustomConnectionDetails() {
96+
this.contextRunner.withUserConfiguration(BaseConfiguration.class, ConnectionDetailsConfiguration.class)
97+
.run((context) -> {
98+
assertThat(context).hasSingleBean(OtlpConnectionDetails.class)
99+
.doesNotHaveBean(OtlpMetricsExportAutoConfiguration.PropertiesOtlpConnectionDetails.class);
100+
OtlpConfig config = context.getBean(OtlpConfig.class);
101+
assertThat(config.url()).isEqualTo("http://localhost:12345/v1/metrics");
102+
});
103+
}
104+
86105
@Configuration(proxyBeanMethods = false)
87106
static class BaseConfiguration {
88107

@@ -115,4 +134,14 @@ OtlpMeterRegistry customRegistry(OtlpConfig config, Clock clock) {
115134

116135
}
117136

137+
@Configuration(proxyBeanMethods = false)
138+
static class ConnectionDetailsConfiguration {
139+
140+
@Bean
141+
OtlpConnectionDetails otlpConnectionDetails() {
142+
return () -> "http://localhost:12345/v1/metrics";
143+
}
144+
145+
}
146+
118147
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesConfigAdapterTests.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,37 +34,42 @@ class OtlpPropertiesConfigAdapterTests {
3434
void whenPropertiesUrlIsSetAdapterUrlReturnsIt() {
3535
OtlpProperties properties = new OtlpProperties();
3636
properties.setUrl("http://another-url:4318/v1/metrics");
37-
assertThat(new OtlpPropertiesConfigAdapter(properties).url()).isEqualTo("http://another-url:4318/v1/metrics");
37+
assertThat(otlpPropertiesConfigAdapter(properties).url()).isEqualTo("http://another-url:4318/v1/metrics");
3838
}
3939

4040
@Test
4141
void whenPropertiesAggregationTemporalityIsNotSetAdapterAggregationTemporalityReturnsCumulative() {
4242
OtlpProperties properties = new OtlpProperties();
43-
assertThat(new OtlpPropertiesConfigAdapter(properties).aggregationTemporality())
43+
assertThat(otlpPropertiesConfigAdapter(properties).aggregationTemporality())
4444
.isSameAs(AggregationTemporality.CUMULATIVE);
4545
}
4646

4747
@Test
4848
void whenPropertiesAggregationTemporalityIsSetAdapterAggregationTemporalityReturnsIt() {
4949
OtlpProperties properties = new OtlpProperties();
5050
properties.setAggregationTemporality(AggregationTemporality.DELTA);
51-
assertThat(new OtlpPropertiesConfigAdapter(properties).aggregationTemporality())
51+
assertThat(otlpPropertiesConfigAdapter(properties).aggregationTemporality())
5252
.isSameAs(AggregationTemporality.DELTA);
5353
}
5454

5555
@Test
5656
void whenPropertiesResourceAttributesIsSetAdapterResourceAttributesReturnsIt() {
5757
OtlpProperties properties = new OtlpProperties();
5858
properties.setResourceAttributes(Map.of("service.name", "boot-service"));
59-
assertThat(new OtlpPropertiesConfigAdapter(properties).resourceAttributes()).containsEntry("service.name",
59+
assertThat(otlpPropertiesConfigAdapter(properties).resourceAttributes()).containsEntry("service.name",
6060
"boot-service");
6161
}
6262

6363
@Test
6464
void whenPropertiesHeadersIsSetAdapterHeadersReturnsIt() {
6565
OtlpProperties properties = new OtlpProperties();
6666
properties.setHeaders(Map.of("header", "value"));
67-
assertThat(new OtlpPropertiesConfigAdapter(properties).headers()).containsEntry("header", "value");
67+
assertThat(otlpPropertiesConfigAdapter(properties).headers()).containsEntry("header", "value");
68+
}
69+
70+
private static OtlpPropertiesConfigAdapter otlpPropertiesConfigAdapter(OtlpProperties properties) {
71+
return new OtlpPropertiesConfigAdapter(properties,
72+
new OtlpMetricsExportAutoConfiguration.PropertiesOtlpConnectionDetails(properties));
6873
}
6974

7075
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2012-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.otlp;
18+
19+
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
20+
21+
/**
22+
* Details required to establish a connection to a OpenTelemetry Collector
23+
* service.
24+
*
25+
* @author Eddú Meléndez
26+
* @since 3.1.0
27+
*/
28+
public interface OtlpConnectionDetails extends ConnectionDetails {
29+
30+
String getUrl();
31+
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2012-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* Auto-configuration for OpenTelemetry Collector.
19+
*/
20+
package org.springframework.boot.autoconfigure.otlp;

spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/testing.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,9 @@ The following service connection factories are provided in the `spring-boot-test
970970
| `Neo4jConnectionDetails`
971971
| Containers of type `Neo4jContainer`
972972

973+
| `OtlpConnectionDetails`
974+
| Containers named "otel/opentelemetry-collector-contrib"
975+
973976
| `R2dbcConnectionDetails`
974977
| Containers of type `MariaDBContainer`, `MSSQLServerContainer`, `MySQLContainer`, `OracleContainer`, or `PostgreSQLContainer`
975978

spring-boot-project/spring-boot-testcontainers/build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,12 @@ dependencies {
3131
optional("org.testcontainers:redpanda")
3232
optional("org.testcontainers:r2dbc")
3333

34+
testImplementation(project(":spring-boot-project:spring-boot-actuator-autoconfigure"))
35+
testImplementation(project(":spring-boot-project:spring-boot-testcontainers"))
3436
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
3537
testImplementation("ch.qos.logback:logback-classic")
38+
testImplementation("io.micrometer:micrometer-registry-otlp")
39+
testImplementation("io.rest-assured:rest-assured")
3640
testImplementation("org.assertj:assertj-core")
3741
testImplementation("org.awaitility:awaitility")
3842
testImplementation("org.influxdb:influxdb-java")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2012-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.testcontainers.service.connection.otlp;
18+
19+
import org.testcontainers.containers.Container;
20+
import org.testcontainers.containers.GenericContainer;
21+
22+
import org.springframework.boot.autoconfigure.otlp.OtlpConnectionDetails;
23+
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
24+
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
25+
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
26+
27+
/**
28+
* {@link ContainerConnectionDetailsFactory} to create {@link OtlpConnectionDetails} from
29+
* a {@link ServiceConnection @ServiceConnection}-annotated {@link GenericContainer} using
30+
* the {@code "otel/opentelemetry-collector-contrib"} image.
31+
*
32+
* @author Moritz Halbritter
33+
* @author Andy Wilkinson
34+
* @author Phillip Webb
35+
*/
36+
class OpenTelemetryConnectionDetailsFactory
37+
extends ContainerConnectionDetailsFactory<OtlpConnectionDetails, Container<?>> {
38+
39+
OpenTelemetryConnectionDetailsFactory() {
40+
super("otel/opentelemetry-collector-contrib");
41+
}
42+
43+
@Override
44+
protected OtlpConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {
45+
return new OpenTelemetryContainerConnectionDetails(source);
46+
}
47+
48+
private static final class OpenTelemetryContainerConnectionDetails extends ContainerConnectionDetails
49+
implements OtlpConnectionDetails {
50+
51+
private final String url;
52+
53+
private OpenTelemetryContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {
54+
super(source);
55+
this.url = "http://" + source.getContainer().getHost() + ":" + source.getContainer().getMappedPort(4318)
56+
+ "/v1/metrics";
57+
}
58+
59+
@Override
60+
public String getUrl() {
61+
return this.url;
62+
}
63+
64+
}
65+
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2012-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* Support for testcontainers OpenTelemetry service connections.
19+
*/
20+
package org.springframework.boot.testcontainers.service.connection.otlp;

0 commit comments

Comments
 (0)