Skip to content

Commit 6997277

Browse files
eddumelendezmhalbritter
authored andcommitted
Add service connection from OpenTelemetry Collector
See gh-35082
1 parent 4bb2e91 commit 6997277

File tree

24 files changed

+768
-8
lines changed

24 files changed

+768
-8
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
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.actuate.autoconfigure.metrics.export.otlp;
18+
19+
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
20+
21+
/**
22+
* Details required to establish a connection to a OpenTelemetry Collector service.
23+
*
24+
* @author Eddú Meléndez
25+
* @since 3.1.0
26+
*/
27+
public interface OtlpConnectionDetails extends ConnectionDetails {
28+
29+
String getUrl();
30+
31+
}

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

+26-2
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,17 @@
5050
@EnableConfigurationProperties({ OtlpProperties.class, OpenTelemetryProperties.class })
5151
public class OtlpMetricsExportAutoConfiguration {
5252

53+
@Bean
54+
@ConditionalOnMissingBean(OtlpConnectionDetails.class)
55+
public OtlpConnectionDetails otlpConnectionDetails(OtlpProperties properties) {
56+
return new PropertiesOtlpConnectionDetails(properties);
57+
}
58+
5359
@Bean
5460
@ConditionalOnMissingBean
5561
OtlpConfig otlpConfig(OtlpProperties properties, OpenTelemetryProperties openTelemetryProperties,
56-
Environment environment) {
57-
return new OtlpPropertiesConfigAdapter(properties, openTelemetryProperties, environment);
62+
OtlpConnectionDetails connectionDetails, Environment environment) {
63+
return new OtlpPropertiesConfigAdapter(properties, openTelemetryProperties, connectionDetails, environment);
5864
}
5965

6066
@Bean
@@ -63,4 +69,22 @@ public OtlpMeterRegistry otlpMeterRegistry(OtlpConfig otlpConfig, Clock clock) {
6369
return new OtlpMeterRegistry(otlpConfig, clock);
6470
}
6571

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

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

+5-2
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,14 @@ class OtlpPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<Ot
4545

4646
private final OpenTelemetryProperties openTelemetryProperties;
4747

48+
private final OtlpConnectionDetails connectionDetails;
49+
4850
private final Environment environment;
4951

5052
OtlpPropertiesConfigAdapter(OtlpProperties properties, OpenTelemetryProperties openTelemetryProperties,
51-
Environment environment) {
53+
OtlpConnectionDetails connectionDetails, Environment environment) {
5254
super(properties);
55+
this.connectionDetails = connectionDetails;
5356
this.openTelemetryProperties = openTelemetryProperties;
5457
this.environment = environment;
5558
}
@@ -61,7 +64,7 @@ public String prefix() {
6164

6265
@Override
6366
public String url() {
64-
return get(OtlpProperties::getUrl, OtlpConfig.super::url);
67+
return get((properties) -> this.connectionDetails.getUrl(), OtlpConfig.super::url);
6568
}
6669

6770
@Override

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpAutoConfiguration.java

+31-3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.springframework.boot.actuate.autoconfigure.tracing.ConditionalOnEnabledTracing;
2929
import org.springframework.boot.autoconfigure.AutoConfiguration;
3030
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
31+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
3132
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
3233
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
3334
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -47,21 +48,30 @@
4748
*
4849
* @author Jonatan Ivanov
4950
* @author Moritz Halbritter
51+
* @author Eddú Meléndez
5052
* @since 3.1.0
5153
*/
5254
@AutoConfiguration
5355
@ConditionalOnClass({ OtelTracer.class, SdkTracerProvider.class, OpenTelemetry.class, OtlpHttpSpanExporter.class })
5456
@EnableConfigurationProperties(OtlpProperties.class)
5557
public class OtlpAutoConfiguration {
5658

59+
@Bean
60+
@ConditionalOnMissingBean(OtlpTracingConnectionDetails.class)
61+
@ConditionalOnProperty(prefix = "management.otlp.tracing", name = "endpoint")
62+
OtlpTracingConnectionDetails otlpTracingConnectionDetails(OtlpProperties properties) {
63+
return new PropertiesOtlpTracingConnectionDetails(properties);
64+
}
65+
5766
@Bean
5867
@ConditionalOnMissingBean(value = OtlpHttpSpanExporter.class,
5968
type = "io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter")
60-
@ConditionalOnProperty(prefix = "management.otlp.tracing", name = "endpoint")
69+
@ConditionalOnBean(OtlpTracingConnectionDetails.class)
6170
@ConditionalOnEnabledTracing
62-
OtlpHttpSpanExporter otlpHttpSpanExporter(OtlpProperties properties) {
71+
OtlpHttpSpanExporter otlpHttpSpanExporter(OtlpProperties properties,
72+
OtlpTracingConnectionDetails connectionDetails) {
6373
OtlpHttpSpanExporterBuilder builder = OtlpHttpSpanExporter.builder()
64-
.setEndpoint(properties.getEndpoint())
74+
.setEndpoint(connectionDetails.getEndpoint())
6575
.setTimeout(properties.getTimeout())
6676
.setCompression(properties.getCompression().name().toLowerCase());
6777
for (Entry<String, String> header : properties.getHeaders().entrySet()) {
@@ -70,4 +80,22 @@ OtlpHttpSpanExporter otlpHttpSpanExporter(OtlpProperties properties) {
7080
return builder.build();
7181
}
7282

83+
/**
84+
* Adapts {@link OtlpProperties} to {@link OtlpTracingConnectionDetails}.
85+
*/
86+
static class PropertiesOtlpTracingConnectionDetails implements OtlpTracingConnectionDetails {
87+
88+
private final OtlpProperties properties;
89+
90+
PropertiesOtlpTracingConnectionDetails(OtlpProperties properties) {
91+
this.properties = properties;
92+
}
93+
94+
@Override
95+
public String getEndpoint() {
96+
return this.properties.getEndpoint();
97+
}
98+
99+
}
100+
73101
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
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.actuate.autoconfigure.tracing.otlp;
18+
19+
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
20+
21+
/**
22+
* Details required to establish a connection to a OpenTelemetry service.
23+
*
24+
* @author Eddú Meléndez
25+
* @since 3.1.0
26+
*/
27+
public interface OtlpTracingConnectionDetails extends ConnectionDetails {
28+
29+
String getEndpoint();
30+
31+
}

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

+28
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,24 @@ void allowsRegistryToBeCustomized() {
8383
.hasBean("customRegistry"));
8484
}
8585

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

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

116134
}
117135

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

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

+6-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.junit.jupiter.api.BeforeEach;
2525
import org.junit.jupiter.api.Test;
2626

27+
import org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsExportAutoConfiguration.PropertiesOtlpConnectionDetails;
2728
import org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryProperties;
2829
import org.springframework.mock.env.MockEnvironment;
2930

@@ -44,11 +45,14 @@ class OtlpPropertiesConfigAdapterTests {
4445

4546
private MockEnvironment environment;
4647

48+
private OtlpConnectionDetails connectionDetails;
49+
4750
@BeforeEach
4851
void setUp() {
4952
this.properties = new OtlpProperties();
5053
this.openTelemetryProperties = new OpenTelemetryProperties();
5154
this.environment = new MockEnvironment();
55+
this.connectionDetails = new PropertiesOtlpConnectionDetails(this.properties);
5256
}
5357

5458
@Test
@@ -136,7 +140,8 @@ void shouldUseDefaultApplicationNameIfApplicationNameIsNotSet() {
136140
}
137141

138142
private OtlpPropertiesConfigAdapter createAdapter() {
139-
return new OtlpPropertiesConfigAdapter(this.properties, this.openTelemetryProperties, this.environment);
143+
return new OtlpPropertiesConfigAdapter(this.properties, this.openTelemetryProperties, this.connectionDetails,
144+
this.environment);
140145
}
141146

142147
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpAutoConfigurationTests.java

+30
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
2020
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
2121
import io.opentelemetry.sdk.trace.export.SpanExporter;
22+
import okhttp3.HttpUrl;
2223
import org.junit.jupiter.api.Test;
2324

2425
import org.springframework.boot.autoconfigure.AutoConfigurations;
@@ -34,6 +35,7 @@
3435
*
3536
* @author Jonatan Ivanov
3637
* @author Moritz Halbritter
38+
* @author Eddú Meléndez
3739
*/
3840
class OtlpAutoConfigurationTests {
3941

@@ -106,6 +108,24 @@ void shouldNotSupplyOtlpHttpSpanExporterIfTracingIsDisabled() {
106108
.run((context) -> assertThat(context).doesNotHaveBean(OtlpHttpSpanExporter.class));
107109
}
108110

111+
@Test
112+
void definesPropertiesBasedConnectionDetailsByDefault() {
113+
this.contextRunner.withPropertyValues("management.otlp.tracing.endpoint=http://localhost:4318/v1/traces")
114+
.run((context) -> assertThat(context)
115+
.hasSingleBean(OtlpAutoConfiguration.PropertiesOtlpTracingConnectionDetails.class));
116+
}
117+
118+
@Test
119+
void testConnectionFactoryWithOverridesWhenUsingCustomConnectionDetails() {
120+
this.contextRunner.withUserConfiguration(ConnectionDetailsConfiguration.class).run((context) -> {
121+
assertThat(context).hasSingleBean(OtlpTracingConnectionDetails.class)
122+
.doesNotHaveBean(OtlpAutoConfiguration.PropertiesOtlpTracingConnectionDetails.class);
123+
OtlpHttpSpanExporter otlpHttpSpanExporter = context.getBean(OtlpHttpSpanExporter.class);
124+
assertThat(otlpHttpSpanExporter).extracting("delegate.httpSender.url")
125+
.isEqualTo(HttpUrl.get("http://localhost:12345/v1/traces"));
126+
});
127+
}
128+
109129
@Configuration(proxyBeanMethods = false)
110130
private static class CustomHttpExporterConfiguration {
111131

@@ -126,4 +146,14 @@ OtlpGrpcSpanExporter customOtlpGrpcSpanExporter() {
126146

127147
}
128148

149+
@Configuration(proxyBeanMethods = false)
150+
static class ConnectionDetailsConfiguration {
151+
152+
@Bean
153+
OtlpTracingConnectionDetails otlpTracingConnectionDetails() {
154+
return () -> "http://localhost:12345/v1/traces";
155+
}
156+
157+
}
158+
129159
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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.docker.compose.service.connection.otlp;
18+
19+
import org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpConnectionDetails;
20+
import org.springframework.boot.docker.compose.core.RunningService;
21+
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;
22+
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;
23+
24+
/**
25+
* {@link DockerComposeConnectionDetailsFactory} to create {@link OtlpConnectionDetails}
26+
* for a {@code otlp} service.
27+
*
28+
* @author Eddú Meléndez
29+
*/
30+
class OpenTelemetryDockerComposeConnectionDetailsFactory
31+
extends DockerComposeConnectionDetailsFactory<OtlpConnectionDetails> {
32+
33+
private static final int OTLP_PORT = 4318;
34+
35+
OpenTelemetryDockerComposeConnectionDetailsFactory() {
36+
super("otel/opentelemetry-collector-contrib",
37+
"org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsExportAutoConfiguration");
38+
}
39+
40+
@Override
41+
protected OtlpConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {
42+
return new OpenTelemetryContainerConnectionDetails(source.getRunningService());
43+
}
44+
45+
private static final class OpenTelemetryContainerConnectionDetails extends DockerComposeConnectionDetails
46+
implements OtlpConnectionDetails {
47+
48+
private final String host;
49+
50+
private final int port;
51+
52+
private OpenTelemetryContainerConnectionDetails(RunningService source) {
53+
super(source);
54+
this.host = source.host();
55+
this.port = source.ports().get(OTLP_PORT);
56+
}
57+
58+
@Override
59+
public String getUrl() {
60+
return "http://" + this.host + ":" + this.port + "/v1/metrics";
61+
}
62+
63+
}
64+
65+
}

0 commit comments

Comments
 (0)