Skip to content

Commit 3da45aa

Browse files
committed
Merge pull request #41551 from eddumelendez
* pr/41551: Polish "Add support for Grafana LGTM stack" Add support for Grafana LGTM stack Closes gh-41551
2 parents f11dc54 + dabc833 commit 3da45aa

File tree

16 files changed

+419
-12
lines changed

16 files changed

+419
-12
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2012-2024 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.OtlpMetricsConnectionDetails;
20+
import org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;
21+
import org.springframework.boot.testsupport.container.TestImage;
22+
23+
import static org.assertj.core.api.Assertions.assertThat;
24+
25+
/**
26+
* Integration tests for {@link OpenTelemetryMetricsDockerComposeConnectionDetailsFactory}
27+
* using {@link TestImage#GRAFANA_OTEL_LGTM}.
28+
*
29+
* @author Eddú Meléndez
30+
*/
31+
class GrafanaOpenTelemetryMetricsDockerComposeConnectionDetailsFactoryIntegrationTests {
32+
33+
@DockerComposeTest(composeFile = "otlp-compose.yaml", image = TestImage.GRAFANA_OTEL_LGTM)
34+
void runCreatesConnectionDetails(OtlpMetricsConnectionDetails connectionDetails) {
35+
assertThat(connectionDetails.getUrl()).startsWith("http://").endsWith("/v1/metrics");
36+
}
37+
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2012-2024 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.tracing.otlp.OtlpTracingConnectionDetails;
20+
import org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;
21+
import org.springframework.boot.testsupport.container.TestImage;
22+
23+
import static org.assertj.core.api.Assertions.assertThat;
24+
25+
/**
26+
* Integration tests for {@link OpenTelemetryTracingDockerComposeConnectionDetailsFactory}
27+
* using {@link TestImage#GRAFANA_OTEL_LGTM}.
28+
*
29+
* @author Eddú Meléndez
30+
*/
31+
class GrafanaOpenTelemetryTracingDockerComposeConnectionDetailsFactoryIntegrationTests {
32+
33+
@DockerComposeTest(composeFile = "otlp-compose.yaml", image = TestImage.GRAFANA_OTEL_LGTM)
34+
void runCreatesConnectionDetails(OtlpTracingConnectionDetails connectionDetails) {
35+
assertThat(connectionDetails.getUrl()).startsWith("http://").endsWith("/v1/traces");
36+
}
37+
38+
}

spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryMetricsDockerComposeConnectionDetailsFactoryIntegrationTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
import static org.assertj.core.api.Assertions.assertThat;
2424

2525
/**
26-
* Integration tests for
27-
* {@link OpenTelemetryMetricsDockerComposeConnectionDetailsFactory}.
26+
* Integration tests for {@link OpenTelemetryMetricsDockerComposeConnectionDetailsFactory}
27+
* using {@link TestImage#OPENTELEMETRY}.
2828
*
2929
* @author Eddú Meléndez
3030
*/

spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryTracingDockerComposeConnectionDetailsFactoryIntegrationTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
import static org.assertj.core.api.Assertions.assertThat;
2424

2525
/**
26-
* Integration tests for
27-
* {@link OpenTelemetryTracingDockerComposeConnectionDetailsFactory}.
26+
* Integration tests for {@link OpenTelemetryTracingDockerComposeConnectionDetailsFactory}
27+
* using {@link TestImage#OPENTELEMETRY}.
2828
*
2929
* @author Eddú Meléndez
3030
*/

spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryMetricsDockerComposeConnectionDetailsFactory.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 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.
@@ -30,10 +30,13 @@
3030
class OpenTelemetryMetricsDockerComposeConnectionDetailsFactory
3131
extends DockerComposeConnectionDetailsFactory<OtlpMetricsConnectionDetails> {
3232

33+
private static final String[] OPENTELEMETRY_IMAGE_NAMES = { "otel/opentelemetry-collector-contrib",
34+
"grafana/otel-lgtm" };
35+
3336
private static final int OTLP_PORT = 4318;
3437

3538
OpenTelemetryMetricsDockerComposeConnectionDetailsFactory() {
36-
super("otel/opentelemetry-collector-contrib",
39+
super(OPENTELEMETRY_IMAGE_NAMES,
3740
"org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsExportAutoConfiguration");
3841
}
3942

spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/otlp/OpenTelemetryTracingDockerComposeConnectionDetailsFactory.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 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.
@@ -30,10 +30,13 @@
3030
class OpenTelemetryTracingDockerComposeConnectionDetailsFactory
3131
extends DockerComposeConnectionDetailsFactory<OtlpTracingConnectionDetails> {
3232

33+
private static final String[] OPENTELEMETRY_IMAGE_NAMES = { "otel/opentelemetry-collector-contrib",
34+
"grafana/otel-lgtm" };
35+
3336
private static final int OTLP_PORT = 4318;
3437

3538
OpenTelemetryTracingDockerComposeConnectionDetailsFactory() {
36-
super("otel/opentelemetry-collector-contrib",
39+
super(OPENTELEMETRY_IMAGE_NAMES,
3740
"org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpAutoConfiguration");
3841
}
3942

spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/dev-services.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,10 @@ The following service connections are currently supported:
108108
| Containers named "neo4j" or "bitnami/neo4j"
109109

110110
| `OtlpMetricsConnectionDetails`
111-
| Containers named "otel/opentelemetry-collector-contrib"
111+
| Containers named "otel/opentelemetry-collector-contrib", "grafana/otel-lgtm"
112112

113113
| `OtlpTracingConnectionDetails`
114-
| Containers named "otel/opentelemetry-collector-contrib"
114+
| Containers named "otel/opentelemetry-collector-contrib", "grafana/otel-lgtm"
115115

116116
| `PulsarConnectionDetails`
117117
| Containers named "apachepulsar/pulsar"

spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,10 @@ The following service connection factories are provided in the `spring-boot-test
7272
| Containers of type `Neo4jContainer`
7373

7474
| `OtlpMetricsConnectionDetails`
75-
| Containers named "otel/opentelemetry-collector-contrib"
75+
| Containers named "otel/opentelemetry-collector-contrib" or of type `LgtmStackContainer`
7676

7777
| `OtlpTracingConnectionDetails`
78-
| Containers named "otel/opentelemetry-collector-contrib"
78+
| Containers named "otel/opentelemetry-collector-contrib" or of type `LgtmStackContainer`
7979

8080
| `PulsarConnectionDetails`
8181
| Containers of type `PulsarContainer`

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ dependencies {
6666
optional("org.testcontainers:cassandra")
6767
optional("org.testcontainers:couchbase")
6868
optional("org.testcontainers:elasticsearch")
69+
optional("org.testcontainers:grafana")
6970
optional("org.testcontainers:jdbc")
7071
optional("org.testcontainers:kafka")
7172
optional("org.testcontainers:mariadb")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*
2+
* Copyright 2012-2024 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 java.time.Duration;
20+
21+
import io.micrometer.core.instrument.Clock;
22+
import io.micrometer.core.instrument.Counter;
23+
import io.micrometer.core.instrument.DistributionSummary;
24+
import io.micrometer.core.instrument.Gauge;
25+
import io.micrometer.core.instrument.MeterRegistry;
26+
import io.micrometer.core.instrument.Timer;
27+
import io.restassured.RestAssured;
28+
import io.restassured.response.Response;
29+
import org.awaitility.Awaitility;
30+
import org.junit.jupiter.api.Test;
31+
import org.testcontainers.grafana.LgtmStackContainer;
32+
import org.testcontainers.junit.jupiter.Container;
33+
import org.testcontainers.junit.jupiter.Testcontainers;
34+
35+
import org.springframework.beans.factory.annotation.Autowired;
36+
import org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsExportAutoConfiguration;
37+
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
38+
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
39+
import org.springframework.boot.testsupport.container.TestImage;
40+
import org.springframework.context.annotation.Bean;
41+
import org.springframework.context.annotation.Configuration;
42+
import org.springframework.test.context.TestPropertySource;
43+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
44+
45+
import static org.assertj.core.api.Assertions.assertThat;
46+
47+
/**
48+
* Tests for {@link GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactory}.
49+
*
50+
* @author Eddú Meléndez
51+
*/
52+
@SpringJUnitConfig
53+
@TestPropertySource(properties = { "management.otlp.metrics.export.resource-attributes.service.name=test",
54+
"management.otlp.metrics.export.step=1s" })
55+
@Testcontainers(disabledWithoutDocker = true)
56+
class GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactoryIntegrationTests {
57+
58+
@Container
59+
@ServiceConnection
60+
static final LgtmStackContainer container = TestImage.container(LgtmStackContainer.class);
61+
62+
@Autowired
63+
private MeterRegistry meterRegistry;
64+
65+
@Test
66+
void connectionCanBeMadeToOpenTelemetryCollectorContainer() {
67+
Counter.builder("test.counter").register(this.meterRegistry).increment(42);
68+
Gauge.builder("test.gauge", () -> 12).register(this.meterRegistry);
69+
Timer.builder("test.timer").register(this.meterRegistry).record(Duration.ofMillis(123));
70+
DistributionSummary.builder("test.distributionsummary").register(this.meterRegistry).record(24);
71+
72+
Awaitility.given()
73+
.pollInterval(Duration.ofSeconds(2))
74+
.atMost(Duration.ofSeconds(10))
75+
.ignoreExceptions()
76+
.untilAsserted(() -> {
77+
Response response = RestAssured.given()
78+
.queryParam("query", "{job=\"test\"}")
79+
.get("%s/api/v1/query".formatted(container.getPromehteusHttpUrl()))
80+
.prettyPeek()
81+
.thenReturn();
82+
assertThat(response.getStatusCode()).isEqualTo(200);
83+
assertThat(response.body()
84+
.jsonPath()
85+
.getList("data.result.find { it.metric.__name__ == 'test_counter_total' }.value")).contains("42");
86+
assertThat(response.body()
87+
.jsonPath()
88+
.getList("data.result.find { it.metric.__name__ == 'test_gauge' }.value")).contains("12");
89+
assertThat(response.body()
90+
.jsonPath()
91+
.getList("data.result.find { it.metric.__name__ == 'test_timer_milliseconds_count' }.value"))
92+
.contains("1");
93+
assertThat(response.body()
94+
.jsonPath()
95+
.getList("data.result.find { it.metric.__name__ == 'test_timer_milliseconds_sum' }.value"))
96+
.contains("123");
97+
assertThat(response.body()
98+
.jsonPath()
99+
.getList(
100+
"data.result.find { it.metric.__name__ == 'test_timer_milliseconds_bucket' & it.metric.le == '+Inf' }.value"))
101+
.contains("1");
102+
assertThat(response.body()
103+
.jsonPath()
104+
.getList("data.result.find { it.metric.__name__ == 'test_distributionsummary_count' }.value"))
105+
.contains("1");
106+
assertThat(response.body()
107+
.jsonPath()
108+
.getList("data.result.find { it.metric.__name__ == 'test_distributionsummary_sum' }.value"))
109+
.contains("24");
110+
assertThat(response.body()
111+
.jsonPath()
112+
.getList(
113+
"data.result.find { it.metric.__name__ == 'test_distributionsummary_bucket' & it.metric.le == '+Inf' }.value"))
114+
.contains("1");
115+
});
116+
}
117+
118+
@Configuration(proxyBeanMethods = false)
119+
@ImportAutoConfiguration(OtlpMetricsExportAutoConfiguration.class)
120+
static class TestConfiguration {
121+
122+
@Bean
123+
Clock customClock() {
124+
return Clock.SYSTEM;
125+
}
126+
127+
}
128+
129+
}

0 commit comments

Comments
 (0)