Skip to content

Commit d19be98

Browse files
authored
Update otlp-spring example to use auth extension (#392)
* Add required dependencies * Use auth extension for OTLP example * Make empty classifier name more apparent * Udpate otlp-spring sample to use GCP Auth extension * Update instructions to reflect auth extension usage * Add instructions for GKE workload identity * Add missing steps to update gradle file
1 parent aa3cdbd commit d19be98

6 files changed

Lines changed: 46 additions & 100 deletions

File tree

examples/otlp-spring/README.md

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ gcloud auth application-default login
1212

1313
##### Export the Google Cloud Project ID to `GOOGLE_CLOUD_PROJECT` environment variable:
1414

15+
This comes in handy when creating resources for deployment on Google Cloud.
16+
1517
```shell
1618
export GOOGLE_CLOUD_PROJECT="my-awesome-gcp-project-id"
1719
```
@@ -21,20 +23,12 @@ export GOOGLE_CLOUD_PROJECT="my-awesome-gcp-project-id"
2123
Update [`build.gradle`](build.grade) to set the following:
2224

2325
```
24-
'-Dotel.resource.attributes=gcp.project_id=<YOUR_PROJECT_ID>,
25-
'-Dotel.exporter.otlp.headers=X-Goog-User-Project=<YOUR_QUOTA_PROJECT>',
26-
# Optional - if you want to export using gRPC protocol
27-
'-Dotel.exporter.otlp.protocol=grpc',
26+
'-Dgoogle.cloud.project=your-gcp-project-id',
27+
'-Dotel.exporter.otlp.endpoint=https://your-api-endpoint:port',,
2828
```
2929

3030
## Running Locally on your machine
3131

32-
Setup your endpoint with the `OTEL_EXPORTER_OTLP_ENDPOINT` environment variable:
33-
34-
```shell
35-
export OTEL_EXPORTER_OTLP_ENDPOINT="http://your-endpoint:port"
36-
```
37-
3832
To run the spring boot application from project root:
3933

4034
```shell
@@ -61,7 +55,7 @@ gcloud auth configure-docker us-central1-docker.pkg.dev
6155

6256
Build and push your image to the Artifact Registry.
6357
```shell
64-
./gradlew :examples:otlp-spring:jib --image="us-central1-docker.pkg.dev/$GOOGLE_CLOUD_PROJECT/otlp-samples/spring-otlp-trace-example:v1"
58+
./gradlew :examples-otlp-spring:jib --image="us-central1-docker.pkg.dev/$GOOGLE_CLOUD_PROJECT/otlp-samples/spring-otlp-trace-example:v1"
6559
```
6660

6761
Deploy the image on your Kubernetes cluster and setup port forwarding to interact with your cluster:
@@ -78,6 +72,21 @@ After successfully setting up port-forwarding, you can send requests to your clu
7872
curl http://localhost:8080/work?desc=test
7973
```
8074

75+
> [!IMPORTANT]
76+
> If your cluster has GKE Workload Identity enabled, you will need to grant the `telemetry.traces.write` permission to the service account used by
77+
> the application deployment.
78+
79+
This running this command will bind the `telemetry-export` service account used by the application deployment to the `telemetry.tracesWriter` role that grants the `telemetry.traces.write`
80+
permission required to export traces to Google Cloud.
81+
82+
```shell
83+
# Replace the <GCP-PROJECT-NUMBER> with the project number of your GCP Project ID.
84+
gcloud projects add-iam-policy-binding projects/$GOOGLE_CLOUD_PROJECT \
85+
--role=roles/telemetry.tracesWriter \
86+
--member=principal://iam.googleapis.com/projects/<GCP-PROJECT-NUMBER>/locations/global/workloadIdentityPools/$GOOGLE_CLOUD_PROJECT.svc.id.goog/subject/ns/default/sa/telemetry-export \
87+
--condition=None
88+
```
89+
8190
### Sending continuous requests
8291

8392
The sample comes with a [client program](src/test/java/com/google/cloud/opentelemetry/examples/otlpspring/MainClient.java) which sends requests to deployed application on your cluster at a fixed rate.

examples/otlp-spring/build.gradle

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,23 @@ repositories {
2828
mavenCentral()
2929
}
3030

31+
// the shaded variant name for gcp auth extension is an empty string
32+
def gcp_auth_extension_shaded_classifier = ''
33+
3134
dependencies {
3235
implementation(libraries.opentelemetry_api)
3336
implementation(libraries.opentelemetry_sdk)
3437
implementation(libraries.opentelemetry_otlp_exporter)
3538
implementation(libraries.opentelemetry_sdk_autoconf)
36-
implementation(libraries.google_auth)
39+
implementation("${libraries.opentelemetry_gcp_auth_extension}:${gcp_auth_extension_shaded_classifier}")
40+
implementation(libraries.opentelemetry_gcp_resources)
3741

3842
implementation(libraries.spring_boot_starter_web)
3943
}
4044

41-
// Provide headers from env variable
42-
// export OTEL_EXPORTER_OTLP_ENDPOINT="http://path/to/yourendpoint:port"
4345
def autoconf_config = [
44-
'-Dotel.resource.attributes=gcp.project_id=<YOUR_PROJECT>',
45-
'-Dotel.exporter.otlp.headers=X-Goog-User-Project=<YOUR_QUOTA_PROJECT>',
46+
'-Dgoogle.cloud.project=your-gcp-project-id',
47+
'-Dotel.exporter.otlp.endpoint=https://your-api-endpoint:port',
4648
'-Dotel.traces.exporter=otlp',
4749
'-Dotel.metrics.exporter=none',
4850
'-Dotel.exporter.otlp.protocol=http/protobuf',
@@ -60,9 +62,6 @@ jib {
6062
containerizingMode = "packaged"
6163
container.jvmFlags = autoconf_config as List
6264
container.ports = ["8080"]
63-
container.environment = [
64-
"OTEL_EXPORTER_OTLP_ENDPOINT":"http://path/to/yourendpoint:port",
65-
]
6665
}
6766

6867
tasks.register('runClient', JavaExec) {

examples/otlp-spring/k8s/deployment.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
apiVersion: v1
2+
kind: ServiceAccount
3+
metadata:
4+
name: telemetry-export
5+
namespace: default
6+
---
17
apiVersion: apps/v1
28
kind: Deployment
39
metadata:
@@ -17,6 +23,7 @@ spec:
1723
app: spring-otlp-trace-example
1824
tier: backend
1925
spec:
26+
serviceAccountName: telemetry-export
2027
containers:
2128
- name: spring-otlp-trace-example
2229
image: us-central1-docker.pkg.dev/%GOOGLE_CLOUD_PROJECT%/otlp-samples/spring-otlp-trace-example:v1

examples/otlp-spring/src/main/java/com/google/cloud/opentelemetry/examples/otlpspring/ApplicationController.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,11 @@ public String simulateWork(@RequestParam(name = "desc") Optional<String> descrip
6060
span.addEvent("Event A");
6161
// Do some work for the use case
6262
// Simulate work: this could be simulating a network request or an expensive disk operation
63-
workDurationMillis = 100 + random.nextInt(5) * 100;
63+
int randomSleepDuration = random.nextInt(5) * 100;
64+
workDurationMillis = 100 + randomSleepDuration;
6465
Thread.sleep(workDurationMillis);
6566
span.addEvent("Event B");
67+
span.setAttribute("RandomSleep", randomSleepDuration);
6668
} catch (InterruptedException e) {
6769
logger.debug("Error while sleeping: {}", e.getMessage());
6870
throw new RuntimeException(e);

examples/otlp-spring/src/main/java/com/google/cloud/opentelemetry/examples/otlpspring/configuration/OpenTelemetryConfiguration.java

Lines changed: 2 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,8 @@
1515
*/
1616
package com.google.cloud.opentelemetry.examples.otlpspring.configuration;
1717

18-
import com.google.auth.oauth2.GoogleCredentials;
19-
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
20-
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder;
21-
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
22-
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder;
2318
import io.opentelemetry.sdk.OpenTelemetrySdk;
2419
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
25-
import io.opentelemetry.sdk.trace.export.SpanExporter;
26-
import java.io.IOException;
27-
import java.util.Map;
28-
import java.util.concurrent.ConcurrentHashMap;
2920
import org.slf4j.Logger;
3021
import org.slf4j.LoggerFactory;
3122
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
@@ -40,74 +31,8 @@ public class OpenTelemetryConfiguration {
4031
@Bean
4132
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
4233
public OpenTelemetrySdk getOpenTelemetrySdk() {
43-
GoogleCredentials googleCredentials = getCredentials();
44-
AutoConfiguredOpenTelemetrySdk autoConfOTelSdk =
45-
AutoConfiguredOpenTelemetrySdk.builder()
46-
.addSpanExporterCustomizer(
47-
(exporter, configProperties) ->
48-
addAuthorizationHeaders(exporter, googleCredentials))
49-
.build();
34+
logger.info("Initializing Autoconfigured OpenTelemetry SDK");
35+
AutoConfiguredOpenTelemetrySdk autoConfOTelSdk = AutoConfiguredOpenTelemetrySdk.initialize();
5036
return autoConfOTelSdk.getOpenTelemetrySdk();
5137
}
52-
53-
private GoogleCredentials getCredentials() {
54-
try {
55-
return GoogleCredentials.getApplicationDefault();
56-
} catch (IOException e) {
57-
throw new RuntimeException(e);
58-
}
59-
}
60-
61-
private SpanExporter addAuthorizationHeaders(
62-
SpanExporter exporter, GoogleCredentials credentials) {
63-
Map<String, String> authHeaders = new ConcurrentHashMap<>();
64-
if (exporter instanceof OtlpHttpSpanExporter) {
65-
try {
66-
credentials.refreshIfExpired();
67-
OtlpHttpSpanExporterBuilder builder =
68-
((OtlpHttpSpanExporter) exporter)
69-
.toBuilder()
70-
.setHeaders(
71-
() -> {
72-
authHeaders.put("Authorization", refreshToken(credentials));
73-
return authHeaders;
74-
});
75-
return builder.build();
76-
} catch (IOException e) {
77-
logger.error("Error while adding headers : {}", e.getMessage());
78-
throw new RuntimeException(e);
79-
}
80-
} else if (exporter instanceof OtlpGrpcSpanExporter) {
81-
try {
82-
credentials.refreshIfExpired();
83-
OtlpGrpcSpanExporterBuilder builder =
84-
((OtlpGrpcSpanExporter) exporter)
85-
.toBuilder()
86-
.setHeaders(
87-
() -> {
88-
authHeaders.put("Authorization", refreshToken(credentials));
89-
return authHeaders;
90-
});
91-
return builder.build();
92-
} catch (IOException e) {
93-
logger.error("Error while adding headers: {}", e.getMessage());
94-
throw new RuntimeException(e);
95-
}
96-
}
97-
return exporter;
98-
}
99-
100-
private String refreshToken(GoogleCredentials credentials) {
101-
logger.info("Refreshing Google Credentials");
102-
try {
103-
logger.info(
104-
"Current access token expires at {}", credentials.getAccessToken().getExpirationTime());
105-
credentials.refreshIfExpired();
106-
logger.info("Credential refresh check complete");
107-
return String.format("Bearer %s", credentials.getAccessToken().getTokenValue());
108-
} catch (IOException e) {
109-
logger.error("Error while refreshing credentials: {}", e.getMessage());
110-
throw new RuntimeException(e);
111-
}
112-
}
11338
}

examples/otlptrace/README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,14 @@ Executing this command will save your application credentials to default path wh
1111
- Linux, macOS: `$HOME/.config/gcloud/application_default_credentials.json`
1212
- Windows: `%APPDATA%\gcloud\application_default_credentials.json`
1313

14-
Next, set your endpoint with the `OTEL_EXPORTER_OTLP_ENDPOINT` environment variable:
14+
Next, update the `build.gradle` file to modify required JVM arguments:
1515

16-
```shell
17-
export OTEL_EXPORTER_OTLP_ENDPOINT="http://your-endpoint:port"
16+
```groovy
17+
def autoconf_config = [
18+
'-Dgoogle.cloud.project=your-gcp-project-id',
19+
'-Dotel.exporter.otlp.endpoint=https://your-api-endpoint:port',
20+
// other arguments
21+
]
1822
```
1923

2024
Finally, to run the sample from the project root:

0 commit comments

Comments
 (0)