Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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 =
Copy link
Copy Markdown

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.

Copy link
Copy Markdown
Contributor Author

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.

"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
Expand All @@ -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")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The 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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The 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)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The 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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The 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
Expand All @@ -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))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the OTEL_TRACES_SAMPLER flag to control sampling behavior?

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]

Expand All @@ -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();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove this change? This looks more cleaner

Copy link
Copy Markdown

Choose a reason for hiding this comment

The 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]

Expand Down
Loading