-
Notifications
You must be signed in to change notification settings - Fork 2.9k
feat(spanner): Update OpenTelemetry OTLP trace sample to use Google C… #10251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,7 @@ | |
|
|
||
| package com.example.spanner; | ||
|
|
||
| import com.google.auth.oauth2.GoogleCredentials; | ||
| import com.google.cloud.opentelemetry.trace.TraceConfiguration; | ||
| import com.google.cloud.opentelemetry.trace.TraceExporter; | ||
| import com.google.cloud.spanner.DatabaseClient; | ||
|
|
@@ -32,10 +33,13 @@ | |
| import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; | ||
| import io.opentelemetry.sdk.trace.export.SpanExporter; | ||
| import io.opentelemetry.sdk.trace.samplers.Sampler; | ||
| import java.io.IOException; | ||
| import java.util.Collections; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| /** | ||
| * This sample demonstrates how to configure OpenTelemetry and inject via Spanner Options. | ||
| */ | ||
| /** This sample demonstrates how to configure OpenTelemetry and inject via Spanner Options. */ | ||
| public class OpenTelemetryUsage { | ||
|
|
||
| static SdkTracerProvider sdkTracerProvider; | ||
|
|
@@ -46,20 +50,20 @@ public class OpenTelemetryUsage { | |
| static String instanceId = "my-instance"; | ||
| static String databaseId = "my-database"; | ||
|
|
||
| // Replace these variables to use OTLP Exporter | ||
| static boolean useCloudTraceExporter = true; // Replace to false for OTLP | ||
| static String otlpEndpoint = "http://localhost:4317"; // Replace with your OTLP endpoint | ||
| static boolean useCloudTraceExporter = false; // Replace to true for Cloud Trace exporter | ||
| static String otlpEndpoint = | ||
| "https://telemetry.googleapis.com"; // Replace with your OTLP endpoint | ||
|
|
||
| public static void main(String[] args) { | ||
| public static void main(String[] args) throws IOException { | ||
|
|
||
| if (useCloudTraceExporter) { | ||
| spanner = getSpannerWithCloudTraceExporter(); | ||
| } else { | ||
| spanner = getSpannerWithOtlpExporter(); | ||
| } | ||
|
|
||
| DatabaseClient dbClient = spanner | ||
| .getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId)); | ||
| DatabaseClient dbClient = | ||
| spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId)); | ||
|
|
||
| try (ResultSet resultSet = | ||
| dbClient | ||
|
|
@@ -74,15 +78,37 @@ public static void main(String[] args) { | |
| sdkTracerProvider.forceFlush(); | ||
| } | ||
|
|
||
| public static Spanner getSpannerWithOtlpExporter() { | ||
| public static Spanner getSpannerWithOtlpExporter() throws IOException { | ||
| // [START spanner_opentelemetry_traces_otlp_usage] | ||
| Resource resource = Resource | ||
| .getDefault().merge(Resource.builder().put("service.name", "My App").build()); | ||
|
|
||
| Resource resource = | ||
| Resource.getDefault() | ||
| .merge( | ||
| Resource.builder() | ||
| .put("service.name", "My App") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why "My App"? The service name really ought to be supplied by the program, either through an explicit parameter or through environment variables. Note that there are standard OTel environment variables that are typically used to supply this.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed |
||
| .put("gcp.project_id", projectId) | ||
| .build()); | ||
|
|
||
| GoogleCredentials credentials = | ||
| GoogleCredentials.getApplicationDefault() | ||
| .createScoped(Collections.singleton("https://www.googleapis.com/auth/trace.append")); | ||
| OtlpGrpcSpanExporter otlpGrpcSpanExporter = | ||
| OtlpGrpcSpanExporter | ||
| .builder() | ||
| .setEndpoint(otlpEndpoint) // Replace with your OTLP endpoint | ||
| OtlpGrpcSpanExporter.builder() | ||
| .setEndpoint(otlpEndpoint) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The credentials and header logic should be conditioned on the endpoint matching the GCP Telemetry API. But that endpoint should not be hardcoded. It should be easy for customers to use the library with a collector of their choice.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added this as a conditional logic for "telemetry.googleapis.com" |
||
| .setHeaders( | ||
| () -> { | ||
| try { | ||
| credentials.refreshIfExpired(); | ||
| Map<String, List<String>> metadata = credentials.getRequestMetadata(); | ||
| Map<String, String> headers = new HashMap<>(); | ||
| if (metadata != null) { | ||
| metadata.forEach((key, values) -> headers.put(key, String.join(",", values))); | ||
| } | ||
| return headers; | ||
| } catch (Exception e) { | ||
| // Handle error fetching credentials | ||
| return Collections.emptyMap(); | ||
| } | ||
| }) // Replace with your OTLP endpoint | ||
| .build(); | ||
|
|
||
| // Using a batch span processor | ||
|
|
@@ -92,24 +118,23 @@ public static Spanner getSpannerWithOtlpExporter() { | |
| BatchSpanProcessor.builder(otlpGrpcSpanExporter).build(); | ||
|
|
||
| // Create a new tracer provider | ||
| sdkTracerProvider = SdkTracerProvider.builder() | ||
| // Use Otlp exporter or any other exporter of your choice. | ||
| .addSpanProcessor(otlpGrpcSpanProcessor) | ||
| .setResource(resource) | ||
| .setSampler(Sampler.traceIdRatioBased(0.1)) | ||
| .build(); | ||
| sdkTracerProvider = | ||
| SdkTracerProvider.builder() | ||
| // Use Otlp exporter or any other exporter of your choice. | ||
| .addSpanProcessor(otlpGrpcSpanProcessor) | ||
| .setResource(resource) | ||
| .setSampler(Sampler.traceIdRatioBased(0.1)) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use the https://opentelemetry.io/docs/languages/sdk-configuration/general/#otel_traces_sampler |
||
| .build(); | ||
|
|
||
| // Export to a collector that is expecting OTLP using gRPC. | ||
| OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() | ||
| .setTracerProvider(sdkTracerProvider).build(); | ||
| OpenTelemetry openTelemetry = | ||
| OpenTelemetrySdk.builder().setTracerProvider(sdkTracerProvider).build(); | ||
|
|
||
| // Enable OpenTelemetry traces before Injecting OpenTelemetry | ||
| SpannerOptions.enableOpenTelemetryTraces(); | ||
|
|
||
| // Inject OpenTelemetry object via Spanner options or register as GlobalOpenTelemetry. | ||
| SpannerOptions options = SpannerOptions.newBuilder() | ||
| .setOpenTelemetry(openTelemetry) | ||
| .build(); | ||
| SpannerOptions options = SpannerOptions.newBuilder().setOpenTelemetry(openTelemetry).build(); | ||
| Spanner spanner = options.getService(); | ||
| // [END spanner_opentelemetry_traces_otlp_usage] | ||
|
|
||
|
|
@@ -118,40 +143,38 @@ public static Spanner getSpannerWithOtlpExporter() { | |
|
|
||
| public static Spanner getSpannerWithCloudTraceExporter() { | ||
| // [START spanner_opentelemetry_traces_cloudtrace_usage] | ||
| Resource resource = Resource | ||
| .getDefault().merge(Resource.builder().put("service.name", "My App").build()); | ||
| Resource resource = | ||
| Resource.getDefault().merge(Resource.builder().put("service.name", "My App").build()); | ||
|
|
||
| SpanExporter traceExporter = TraceExporter.createWithConfiguration( | ||
| TraceConfiguration.builder().setProjectId(projectId).build() | ||
| ); | ||
| SpanExporter traceExporter = | ||
| TraceExporter.createWithConfiguration( | ||
| TraceConfiguration.builder().setProjectId(projectId).build()); | ||
|
|
||
| // Using a batch span processor | ||
| // You can use `.setScheduleDelay()`, `.setExporterTimeout()`, | ||
| // `.setMaxQueueSize`(), and `.setMaxExportBatchSize()` to further customize. | ||
| BatchSpanProcessor otlpGrpcSpanProcessor = | ||
| BatchSpanProcessor.builder(traceExporter).build(); | ||
| BatchSpanProcessor otlpGrpcSpanProcessor = BatchSpanProcessor.builder(traceExporter).build(); | ||
|
|
||
| // Create a new tracer provider | ||
| sdkTracerProvider = SdkTracerProvider.builder() | ||
| // Use Otlp exporter or any other exporter of your choice. | ||
| .addSpanProcessor(otlpGrpcSpanProcessor) | ||
| .setResource(resource) | ||
| .setSampler(Sampler.traceIdRatioBased(0.1)) | ||
| .build(); | ||
| sdkTracerProvider = | ||
| SdkTracerProvider.builder() | ||
| // Use Otlp exporter or any other exporter of your choice. | ||
| .addSpanProcessor(otlpGrpcSpanProcessor) | ||
| .setResource(resource) | ||
| .setSampler(Sampler.traceIdRatioBased(0.1)) | ||
| .build(); | ||
|
|
||
| // Export to a collector that is expecting OTLP using gRPC. | ||
| OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() | ||
| .setTracerProvider(sdkTracerProvider).build(); | ||
| OpenTelemetry openTelemetry = | ||
| OpenTelemetrySdk.builder().setTracerProvider(sdkTracerProvider).build(); | ||
|
|
||
| // Enable OpenTelemetry traces before Injecting OpenTelemetry | ||
| SpannerOptions.enableOpenTelemetryTraces(); | ||
|
|
||
| // Inject OpenTelemetry object via Spanner options or register it as global object. | ||
| // To register as the global OpenTelemetry object, | ||
| // use "OpenTelemetrySdk.builder()....buildAndRegisterGlobal()". | ||
| SpannerOptions options = SpannerOptions.newBuilder() | ||
| .setOpenTelemetry(openTelemetry) | ||
| .build(); | ||
| SpannerOptions options = SpannerOptions.newBuilder().setOpenTelemetry(openTelemetry).build(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we remove this change? This looks more cleaner There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. similarly in other places. |
||
| Spanner spanner = options.getService(); | ||
| // [END spanner_opentelemetry_traces_cloudtrace_usage] | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The customer's OTLP configuration should be respected (see relevant OTel environment variables configuring the exporter). However, auth and project ID should get automatically injected/added if the endpoint is the Telemetry API or one of its regional variants.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure changed it to fetch from OTEL_EXPORTER_OTLP_ENDPOINT/OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
Have used google telemetry endpoint as default.