diff --git a/examples/autoconf-auth-extension/README.md b/examples/autoconf-auth-extension/README.md new file mode 100644 index 00000000..36615e9b --- /dev/null +++ b/examples/autoconf-auth-extension/README.md @@ -0,0 +1,40 @@ +# OTLP Trace and Metrics with Google Auth Extension Example + +This sample demonstrates how to use the [OpenTelemetry GCP Auth Extension](https://github.com/open-telemetry/opentelemetry-java-contrib/tree/main/gcp-auth-extension) to configure the OpenTelemetry SDK in a manually instrumented application and export telemetry to Google Cloud using OTLP exporters for both traces and metrics. + +## Prerequisites + +First, ensure you have Google Cloud credentials available on your machine: + +```shell +gcloud auth application-default login +``` + +Executing this command will save your application credentials to the default path: + - Linux, macOS: `$HOME/.config/gcloud/application_default_credentials.json` + - Windows: `%APPDATA%\gcloud\application_default_credentials.json` + +Next, set the `GOOGLE_CLOUD_PROJECT` environment variable to your GCP project ID: +```shell +export GOOGLE_CLOUD_PROJECT="your-gcp-project-id" +``` +This environment variable is used by the GCP Auth Extension to identify the project. + +## Running the Sample + +To run the sample from the repository root, use the following Gradle command: + +```shell +./gradlew :examples-autoconf-auth-extension:run +``` + +Running this sample will generate traces and metrics and export them to Google Cloud via OTLP. + +## Configuration Details + +The sample uses OpenTelemetry SDK Autoconfigure. The following system properties are configured in `build.gradle` and can be overridden or set as environment variables: + +- `otel.exporter.otlp.endpoint`: Set to `https://telemetry.googleapis.com` for Google Cloud OTLP receiver. +- `otel.traces.exporter`: Set to `otlp` to use OTLP exporter for traces. +- `otel.metrics.exporter`: Set to `otlp` to use OTLP exporter for metrics. +- `otel.exporter.otlp.protocol`: Set to `http/protobuf` as required by Google Cloud OTLP receiver. diff --git a/examples/autoconf-auth-extension/build.gradle b/examples/autoconf-auth-extension/build.gradle new file mode 100644 index 00000000..8d1f8feb --- /dev/null +++ b/examples/autoconf-auth-extension/build.gradle @@ -0,0 +1,47 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +plugins { + id 'java' + id 'application' +} + +// examples are not published, so version can be hardcoded +version = '0.1.0' + +description = 'Example showing OTLP exporter with GCP Auth Extension for traces and metrics' + +dependencies { + implementation(libraries.opentelemetry_api) + implementation(libraries.opentelemetry_sdk) + implementation(libraries.opentelemetry_otlp_exporter) + implementation(libraries.opentelemetry_sdk_autoconf) + implementation(libraries.opentelemetry_gcp_auth_extension) + implementation(libraries.opentelemetry_gcp_resources) +} + +def autoconf_config = [ + '-Dotel.exporter.otlp.endpoint=https://telemetry.googleapis.com', + '-Dotel.traces.exporter=otlp', + '-Dotel.metrics.exporter=otlp', + '-Dotel.logs.exporter=none', + '-Dotel.service.name=autoconf-auth-extension-example', + '-Dotel.exporter.otlp.protocol=http/protobuf', +] + +application { + mainClassName = 'com.google.cloud.opentelemetry.example.autoconfauthextension.AutoconfAuthExtensionExample' + applicationDefaultJvmArgs = autoconf_config +} diff --git a/examples/autoconf-auth-extension/src/main/java/com/google/cloud/opentelemetry/example/autoconfauthextension/AutoconfAuthExtensionExample.java b/examples/autoconf-auth-extension/src/main/java/com/google/cloud/opentelemetry/example/autoconfauthextension/AutoconfAuthExtensionExample.java new file mode 100644 index 00000000..4cec6790 --- /dev/null +++ b/examples/autoconf-auth-extension/src/main/java/com/google/cloud/opentelemetry/example/autoconfauthextension/AutoconfAuthExtensionExample.java @@ -0,0 +1,100 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.cloud.opentelemetry.example.autoconfauthextension; + +import io.opentelemetry.api.metrics.LongCounter; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Scope; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; +import io.opentelemetry.sdk.common.CompletableResultCode; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +public class AutoconfAuthExtensionExample { + private static final String INSTRUMENTATION_SCOPE_NAME = + AutoconfAuthExtensionExample.class.getName(); + private static final Random RANDOM = new Random(); + + private static OpenTelemetrySdk openTelemetrySdk; + + private static void myUseCase(String description, LongCounter counter) { + // Generate a span + Span span = + openTelemetrySdk.getTracer(INSTRUMENTATION_SCOPE_NAME).spanBuilder(description).startSpan(); + try (Scope scope = span.makeCurrent()) { + span.addEvent("Event A"); + // Do some work for the use case + for (int i = 0; i < 3; i++) { + String work = String.format("%s - Work #%d", description, (i + 1)); + doWork(work, counter); + } + span.addEvent("Event B"); + } finally { + span.end(); + } + } + + private static void doWork(String description, LongCounter counter) { + // Child span + Span span = + openTelemetrySdk.getTracer(INSTRUMENTATION_SCOPE_NAME).spanBuilder(description).startSpan(); + try (Scope scope = span.makeCurrent()) { + // Simulate work: this could be simulating a network request or an expensive disk operation + int randomSleep = RANDOM.nextInt(5) * 100; + span.setAttribute("RandomSleep", randomSleep); + Thread.sleep(100 + randomSleep); + + // Record a metric + counter.add(1); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } finally { + span.end(); + } + } + + public static void main(String[] args) { + // Configure the OpenTelemetry pipeline with Auto configuration + // The gcp-auth-extension is picked up automatically via SPI if present on classpath + openTelemetrySdk = AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk(); + + // Create a counter + LongCounter counter = + openTelemetrySdk + .getMeter(INSTRUMENTATION_SCOPE_NAME) + .counterBuilder("example_work_counter") + .setDescription("Counts the number of work items processed") + .setUnit("1") + .build(); + + // Application-specific logic + myUseCase("One", counter); + myUseCase("Two", counter); + + System.out.println("Telemetry generated. Shutting down SDK..."); + + // Flush all buffered telemetry + CompletableResultCode traceShutdown = openTelemetrySdk.getSdkTracerProvider().shutdown(); + CompletableResultCode meterShutdown = openTelemetrySdk.getSdkMeterProvider().shutdown(); + + // Wait for export to finish + traceShutdown.join(10000, TimeUnit.MILLISECONDS); + meterShutdown.join(10000, TimeUnit.MILLISECONDS); + + System.out.println("SDK shut down complete."); + } +} diff --git a/settings.gradle b/settings.gradle index 43d85e45..ef924770 100644 --- a/settings.gradle +++ b/settings.gradle @@ -43,6 +43,7 @@ include ":examples-spring" include ":propagators-gcp" include ":shared-resourcemapping" include ":examples-autoinstrument-auth-extension" +include ":examples-autoconf-auth-extension" def javaVersion = Jvm.current().javaVersion @@ -107,3 +108,6 @@ project(':examples-otlpmetric').projectDir = project(':examples-autoinstrument-auth-extension').projectDir = "$rootDir/examples/autoinstrument-auth-extension" as File + +project(':examples-autoconf-auth-extension').projectDir = + "$rootDir/examples/autoconf-auth-extension" as File