Skip to content

Commit a08a050

Browse files
authored
Add OpenTelemetry Spring Boot Starter Sample (#386)
* Setup new module for spring-boot-starter example * Sample app exports to console * Generate native executable image * Export traces to GCP * Export metrics to GCP * Update comment with correct reasoning * Set toolchain version to Java 17 * Update README.md * Conditionally include Java 17 projects This allows to keep using Java 11 to build the project. Keeping Java 11 to build the project allows us to keep using the existing CI that is built around Java 11. * Fix CodeQL CI failure
1 parent c19b136 commit a08a050

File tree

7 files changed

+294
-0
lines changed

7 files changed

+294
-0
lines changed

build.gradle

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ subprojects {
123123
java {
124124
googleJavaFormat("1.10.0")
125125
licenseHeaderFile rootProject.file('buildscripts/spotless.license.java'), '(package|import|class|// Includes work from:)'
126+
// ignore generated code for spotlessCheck & spotlessApply
127+
targetExclude '**/build/generated/**/*.*'
126128
}
127129
groovyGradle {
128130
target '*.gradle' // default target of groovyGradle
@@ -160,6 +162,7 @@ subprojects {
160162
cloudMonitoringVersion = '3.52.0'
161163
openTelemetryBomVersion = '1.42.1'
162164
openTelemetryVersion = '1.42.1'
165+
openTelemetryInstrumentationBomVersion = '2.8.0'
163166
openTelemetryInstrumentationVersion = '2.8.0'
164167
openTelemetrySemconvVersion = '1.27.0'
165168
openTelemetryContribVersion = '1.39.0'
@@ -169,6 +172,7 @@ subprojects {
169172
pubSubVersion = '1.133.0'
170173
testContainersVersion = '1.15.1'
171174
wiremockVersion = '2.35.0'
175+
springVersion = '2.7.18'
172176
springWebVersion = '2.4.5'
173177
springOpenFeignVersion = '3.0.0'
174178
springOtelVersion = '1.0.0-M8'
@@ -196,6 +200,7 @@ subprojects {
196200
slf4j : "org.slf4j:slf4j-api:${slf4jVersion}",
197201
opentelemetry_api : "io.opentelemetry:opentelemetry-api:${openTelemetryVersion}",
198202
opentelemetry_bom : "io.opentelemetry:opentelemetry-bom:${openTelemetryBomVersion}",
203+
opentelemetry_instrumetation_bom : "io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:${openTelemetryInstrumentationBomVersion}",
199204
opentelemetry_context : "io.opentelemetry:opentelemetry-context:${openTelemetryVersion}",
200205
opentelemetry_sdk : "io.opentelemetry:opentelemetry-sdk:${openTelemetryVersion}",
201206
opentelemetry_sdk_common : "io.opentelemetry:opentelemetry-sdk-common:${openTelemetryVersion}",
@@ -207,7 +212,9 @@ subprojects {
207212
opentelemetry_otlp_exporter : "io.opentelemetry:opentelemetry-exporter-otlp:${openTelemetryVersion}",
208213
opentelemetry_logging_exporter : "io.opentelemetry:opentelemetry-exporter-logging:${openTelemetryVersion}",
209214
opentelemetry_gcp_resources : "io.opentelemetry.contrib:opentelemetry-gcp-resources:${openTelemetryContribVersion}-alpha",
215+
spring_boot_starter : "org.springframework.boot:spring-boot-starter:${springVersion}",
210216
spring_boot_starter_web : "org.springframework.boot:spring-boot-starter-web:${springWebVersion}",
217+
spring_boot_starter_actuator : "org.springframework.boot:spring-boot-starter-actuator:${springVersion}",
211218
spring_cloud_starter_openfeign : "org.springframework.cloud:spring-cloud-starter-openfeign:${springOpenFeignVersion}",
212219
spring_cloud_sleuth_otel_autoconf: "org.springframework.cloud:spring-cloud-sleuth-otel-autoconfigure:${springOtelVersion}",
213220
]
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# Getting Started
2+
3+
This example shows a Java Spring Boot application running as GraalVM Native Image, auto-instrumented using OpenTelemetry Spring Boot Starter agent.
4+
The agent has been configured to export the telemetry to Google Cloud Platform.
5+
6+
There are two ways to build and run this example:
7+
- Lightweight Container with Cloud Native Buildpacks.
8+
- Executable with Native Build Tools
9+
10+
### Reference Documentation
11+
12+
For further reference, please consider the following sections:
13+
14+
* [OpenTelemetry Spring Boot Starter Agent](https://opentelemetry.io/docs/zero-code/java/spring-boot-starter/)
15+
* [Official Gradle documentation](https://docs.gradle.org)
16+
* [Spring Boot Gradle Plugin Reference Guide](https://docs.spring.io/spring-boot/3.3.5/gradle-plugin)
17+
* [Create an OCI image](https://docs.spring.io/spring-boot/3.3.5/gradle-plugin/packaging-oci-image.html)
18+
* [GraalVM Native Image Support](https://docs.spring.io/spring-boot/3.3.5/reference/packaging/native-image/introducing-graalvm-native-images.html)
19+
20+
### Additional Links
21+
22+
These additional references should also help you:
23+
24+
* [Gradle Build Scans – insights for your project's build](https://scans.gradle.com#gradle)
25+
* [Configure AOT settings in Build Plugin](https://docs.spring.io/spring-boot/3.3.5/how-to/aot.html)
26+
27+
### Prerequisites
28+
29+
> [!IMPORTANT]
30+
> This example requires Java 17 to build and run.
31+
32+
##### Get Google Cloud Credentials on your machine
33+
34+
```shell
35+
gcloud auth application-default login
36+
```
37+
Executing this command will save your application credentials to default path which will depend on the type of machine -
38+
- Linux, macOS: `$HOME/.config/gcloud/application_default_credentials.json`
39+
- Windows: `%APPDATA%\gcloud\application_default_credentials.json`
40+
41+
**NOTE: This method of authentication is not recommended for production environments.**
42+
43+
Next, export the credentials to `GOOGLE_APPLICATION_CREDENTIALS` environment variable -
44+
45+
For Linux & MacOS:
46+
```shell
47+
export GOOGLE_APPLICATION_CREDENTIALS=$HOME/.config/gcloud/application_default_credentials.json
48+
```
49+
50+
##### Export the Google Cloud Project ID to `GOOGLE_CLOUD_PROJECT` environment variable:
51+
52+
```shell
53+
export GOOGLE_CLOUD_PROJECT="my-awesome-gcp-project-id"
54+
```
55+
56+
### Lightweight Container with Cloud Native Buildpacks
57+
58+
If you're already familiar with Spring Boot container images support, this is
59+
the easiest way to get started.
60+
Docker should be installed and configured on your machine prior to creating the
61+
image.
62+
63+
To create the image, run the following goal:
64+
65+
```shell
66+
gradle bootBuildImage
67+
```
68+
69+
Then, you can run the app like any other container:
70+
71+
```shell
72+
docker run \
73+
--rm \
74+
-e "GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT}" \
75+
-e "GOOGLE_APPLICATION_CREDENTIALS=${GOOGLE_APPLICATION_CREDENTIALS}" \
76+
-v "${GOOGLE_APPLICATION_CREDENTIALS}:${GOOGLE_APPLICATION_CREDENTIALS}:ro" \
77+
-u $(id -u ${USER}) \
78+
-p 8080:8080 \
79+
"examples-spring-boot-starter:0.1.0"
80+
```
81+
82+
### Executable with Native Build Tools
83+
84+
Use this option if you want to explore more options such as running your tests
85+
in a native image.
86+
The GraalVM `native-image` compiler should be installed and configured on your
87+
machine.
88+
89+
To create the executable, run the following goal:
90+
91+
```shell
92+
gradle nativeCompile
93+
```
94+
95+
Then, you can run the app as follows:
96+
97+
```shell
98+
./build/native/nativeCompile/spring-native-example
99+
```
100+
101+
### Interacting with the running Spring Applications
102+
103+
You can interact with the running Spring application by making cURL requests at
104+
localhost:8080 to interact with the deployed Spring application.
105+
106+
```shell
107+
# Call the home endpoint
108+
curl http://localhost:8080/
109+
# Call the ping endpoint
110+
curl http://localhost:8080/ping
111+
```
112+
Make a few requests on these endpoints to generate some traces and metrics.
113+
114+
### Viewing the generated telemetry
115+
116+
After making a few requests to the deployed Spring application, the metrics and
117+
traces generated using the OpenTelemetry Spring Boot Starter agent should be
118+
visible in the configured project in Google Cloud Platform UI.
119+
120+
* To view the generated traces, use the [Trace Explorer](https://cloud.google.com/trace/docs/finding-traces)
121+
* To view the generated metrics, select the metrics in the [Metrics Selector](https://cloud.google.com/monitoring/charts/metrics-selector)
122+
123+
Some known metrics produced by Spring Boot Starter Agent include
124+
`processedSpans`, `http.server.request.duration` and `queueSize`.
125+
126+
For more details on out-of-the-box instrumentation provided by the OpenTelemetry
127+
Spring Boot Starter Agent, see [here](https://opentelemetry.io/docs/zero-code/java/spring-boot-starter/out-of-the-box-instrumentation/).
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright 2024 Google LLC
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+
* http://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+
plugins {
17+
id 'java'
18+
id 'org.springframework.boot' version '3.4.0'
19+
id 'org.graalvm.buildtools.native' version '0.10.4'
20+
}
21+
import org.springframework.boot.gradle.plugin.SpringBootPlugin
22+
23+
group = 'com.google.cloud.opentelemetry.example'
24+
// examples are not published, so version can be hardcoded
25+
version = '0.1.0'
26+
27+
repositories {
28+
mavenCentral()
29+
}
30+
31+
description = 'Java Spring Boot application running as GraalVM Native Image, instrumented using OpenTelemetry Spring Boot Starter'
32+
33+
java {
34+
targetCompatibility = JavaVersion.VERSION_17
35+
}
36+
37+
// Required for fixing CodeQL issues - CodeQL is configured to run with Java 17.
38+
java {
39+
toolchain {
40+
languageVersion = JavaLanguageVersion.of(17)
41+
}
42+
}
43+
44+
compileJava {
45+
// This is only possible since the toolchain guarantees Java 17 presence.
46+
// Toolchain is set in the root build.gradle file.
47+
it.options.release = 17
48+
}
49+
50+
graalvmNative {
51+
binaries {
52+
main {
53+
imageName = 'spring-native-example'
54+
mainClass = 'com.google.cloud.opentelemetry.example.springbootstarter.SpringBootStarterApplication'
55+
// generates executable instead of shared-library
56+
// graalvm native buildtools plugin sets this to false by default if 'java-library' plugin is not
57+
// included. This project is configured to apply java-library plugin to all subprojects by default.
58+
// This configuration is supplied in the project level build.gradle file.
59+
// Removing this will cause nativeCompile task to generate a .so file instead.
60+
sharedLibrary = false
61+
}
62+
}
63+
}
64+
65+
dependencies {
66+
// Spring dependencies
67+
implementation platform(SpringBootPlugin.BOM_COORDINATES)
68+
implementation 'org.springframework.boot:spring-boot-starter-web'
69+
implementation 'org.springframework.boot:spring-boot-starter-actuator'
70+
71+
// OpenTelemetry dependencies
72+
implementation platform(libraries.opentelemetry_instrumetation_bom)
73+
implementation 'io.opentelemetry.instrumentation:opentelemetry-spring-boot-starter'
74+
75+
// auto exporter makes Google Cloud exporters available to autoconfigure module
76+
implementation project(':exporter-auto')
77+
implementation project(':exporter-trace')
78+
implementation project(':exporter-metrics')
79+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2024 Google LLC
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+
* http://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+
package com.google.cloud.opentelemetry.example.springbootstarter;
17+
18+
import org.springframework.web.bind.annotation.GetMapping;
19+
import org.springframework.web.bind.annotation.RestController;
20+
21+
@RestController
22+
public class AppController {
23+
24+
private static final String DESCRIPTION_MESSAGE =
25+
"Sample Spring Boot Application instrumented with OpenTelemetry Spring Boot Starter";
26+
27+
@GetMapping("/ping")
28+
public String ping() {
29+
return "Hello World!";
30+
}
31+
32+
@GetMapping("/")
33+
public String home() {
34+
return DESCRIPTION_MESSAGE;
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright 2024 Google LLC
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+
* http://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+
package com.google.cloud.opentelemetry.example.springbootstarter;
17+
18+
import org.springframework.boot.SpringApplication;
19+
import org.springframework.boot.autoconfigure.SpringBootApplication;
20+
21+
@SpringBootApplication
22+
public class SpringBootStarterApplication {
23+
24+
public static void main(String[] args) {
25+
SpringApplication.run(SpringBootStarterApplication.class, args);
26+
}
27+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
spring.application.name=spring-boot-native-app
2+
otel.traces.exporter=google_cloud_trace
3+
otel.metrics.exporter=google_cloud_monitoring
4+
otel.logs.exporter=none
5+
otel.resource.attributes.service.name=sample-native-app
6+
otel.resource.attributes.service.namespace=gcp-otel-samples
7+
otel.resource.providers.gcp.enabled=true

settings.gradle

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16+
import org.gradle.internal.jvm.Jvm
1617
pluginManagement {
1718
plugins {
1819
id "com.diffplug.spotless" version "6.18.0"
@@ -43,6 +44,16 @@ include ":examples-spring"
4344
include ":propagators-gcp"
4445
include ":shared-resourcemapping"
4546

47+
def javaVersion = Jvm.current().javaVersion
48+
49+
if (javaVersion.isCompatibleWith(JavaVersion.VERSION_17)) {
50+
include ":examples-spring-boot-starter"
51+
project(':examples-spring-boot-starter').projectDir =
52+
"$rootDir/examples/spring-boot-starter" as File
53+
} else {
54+
println "Excluding subproject ':examples-spring-boot-starter' because Java version is less than 17"
55+
}
56+
4657
project(':exporter-trace').projectDir =
4758
"$rootDir/exporters/trace" as File
4859

0 commit comments

Comments
 (0)