Skip to content

Commit

Permalink
Refactor Header Interceptor and modified the server timing header logic
Browse files Browse the repository at this point in the history
  • Loading branch information
surbhigarg92 committed Jan 7, 2025
1 parent 3b03055 commit 59459ae
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 119 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.google.cloud.opentelemetry.detection.AttributeKeys;
import com.google.cloud.opentelemetry.detection.DetectedPlatform;
import com.google.cloud.opentelemetry.detection.GCPPlatformDetector;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.hash.HashFunction;
Expand All @@ -44,72 +45,96 @@
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;

final class BuiltInOpenTelemetryMetricsProvider {

static BuiltInOpenTelemetryMetricsProvider INSTANCE = new BuiltInOpenTelemetryMetricsProvider();
public static BuiltInOpenTelemetryMetricsProvider INSTANCE =
new BuiltInOpenTelemetryMetricsProvider();

private static final Logger logger =
Logger.getLogger(BuiltInOpenTelemetryMetricsProvider.class.getName());

private final Cache<String, Map<String, String>> clientAttributesCache =
CacheBuilder.newBuilder().maximumSize(1000).build();

private static String taskId;

private OpenTelemetry openTelemetry;

private final Cache<String, Map<String, String>> clientAttributesCache =
CacheBuilder.newBuilder().maximumSize(1000).build();
private Map<String, String> clientAttributes;

private boolean isInitialized;

private BuiltInOpenTelemetryMetricsProvider() {}
private BuiltInOpenTelemetryMetricsRecorder builtInOpenTelemetryMetricsRecorder;

private BuiltInOpenTelemetryMetricsProvider() {};

void initialize(
String projectId,
String client_name,
@Nullable Credentials credentials,
@Nullable String monitoringHost) {

OpenTelemetry getOrCreateOpenTelemetry(
String projectId, @Nullable Credentials credentials, @Nullable String monitoringHost) {
try {
if (this.openTelemetry == null) {
SdkMeterProviderBuilder sdkMeterProviderBuilder = SdkMeterProvider.builder();
BuiltInOpenTelemetryMetricsView.registerBuiltinMetrics(
SpannerCloudMonitoringExporter.create(projectId, credentials, monitoringHost),
sdkMeterProviderBuilder);
SdkMeterProvider sdkMeterProvider = sdkMeterProviderBuilder.build();
this.openTelemetry = OpenTelemetrySdk.builder().setMeterProvider(sdkMeterProvider).build();
Runtime.getRuntime().addShutdownHook(new Thread(sdkMeterProvider::close));
if (!isInitialized) {
this.openTelemetry = createOpenTelemetry(projectId, credentials, monitoringHost);
this.clientAttributes = createClientAttributes(projectId, client_name);
this.builtInOpenTelemetryMetricsRecorder =
new BuiltInOpenTelemetryMetricsRecorder(openTelemetry, clientAttributes);
isInitialized = true;
}
return this.openTelemetry;
} catch (IOException ex) {
} catch (Exception ex) {
logger.log(
Level.WARNING,
"Unable to get OpenTelemetry object for client side metrics, will skip exporting client side metrics",
"Unable to initialize OpenTelemetry object or attributes for client side metrics, will skip exporting client side metrics",
ex);
return null;
}
}

Map<String, String> createOrGetClientAttributes(String projectId, String client_name) {
try {
String key = projectId + client_name;
return clientAttributesCache.get(
key,
() -> {
Map<String, String> clientAttributes = new HashMap<>();
clientAttributes.put(LOCATION_ID_KEY.getKey(), detectClientLocation());
clientAttributes.put(PROJECT_ID_KEY.getKey(), projectId);
clientAttributes.put(INSTANCE_CONFIG_ID_KEY.getKey(), "unknown");
clientAttributes.put(CLIENT_NAME_KEY.getKey(), client_name);
String clientUid = getDefaultTaskValue();
clientAttributes.put(CLIENT_UID_KEY.getKey(), clientUid);
clientAttributes.put(CLIENT_HASH_KEY.getKey(), generateClientHash(clientUid));
return clientAttributes;
});
} catch (ExecutionException executionException) {
logger.log(
Level.WARNING,
"Unable to get Client Attributes for client side metrics, will skip exporting client side metrics",
executionException);
return null;
}
OpenTelemetry getOpenTelemetry() {
return this.openTelemetry;
}

Map<String, String> getClientAttributes() {
return this.clientAttributes;
}

BuiltInOpenTelemetryMetricsRecorder getBuiltInOpenTelemetryMetricsRecorder() {
return this.builtInOpenTelemetryMetricsRecorder;
}

@VisibleForTesting
void reset() {
isInitialized = false;
}

private Map<String, String> createClientAttributes(String projectId, String client_name) {
Map<String, String> clientAttributes = new HashMap<>();
clientAttributes.put(LOCATION_ID_KEY.getKey(), detectClientLocation());
clientAttributes.put(PROJECT_ID_KEY.getKey(), projectId);
clientAttributes.put(INSTANCE_CONFIG_ID_KEY.getKey(), "unknown");
clientAttributes.put(CLIENT_NAME_KEY.getKey(), client_name);
String clientUid = getDefaultTaskValue();
clientAttributes.put(CLIENT_UID_KEY.getKey(), clientUid);
clientAttributes.put(CLIENT_HASH_KEY.getKey(), generateClientHash(clientUid));
return clientAttributes;
}

private OpenTelemetry createOpenTelemetry(
String projectId, @Nullable Credentials credentials, @Nullable String monitoringHost)
throws IOException {
OpenTelemetry openTelemetry;
SdkMeterProviderBuilder sdkMeterProviderBuilder = SdkMeterProvider.builder();
BuiltInOpenTelemetryMetricsView.registerBuiltinMetrics(
SpannerCloudMonitoringExporter.create(projectId, credentials, monitoringHost),
sdkMeterProviderBuilder);
SdkMeterProvider sdkMeterProvider = sdkMeterProviderBuilder.build();
openTelemetry = OpenTelemetrySdk.builder().setMeterProvider(sdkMeterProvider).build();
Runtime.getRuntime().addShutdownHook(new Thread(sdkMeterProvider::close));
return openTelemetry;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2024 Google LLC
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -44,10 +44,11 @@ public class BuiltInOpenTelemetryMetricsRecorder {
*/
public BuiltInOpenTelemetryMetricsRecorder(
OpenTelemetry openTelemetry, Map<String, String> clientAttributes) {
if (openTelemetry != null && clientAttributes != null) {
if (openTelemetry == null || clientAttributes == null) {
gfeLatencyRecorder = null;
return;
}

Meter meter =
openTelemetry
.meterBuilder(BuiltInMetricsConstant.SPANNER_METER_NAME)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1825,16 +1825,21 @@ public OpenTelemetry getOpenTelemetry() {
}
}

/** Returns an instance of OpenTelemetry object for Built-in Client metrics. */
public OpenTelemetry getBuiltInMetricsOpenTelemetry() {
return this.builtInOpenTelemetryMetricsProvider.getOrCreateOpenTelemetry(
this.getProjectId(), getCredentials());
/**
* Returns an instance of Built-In MetricsRecorder object. initializeBuiltInMetrics should be
* called first before this recorder can be fetched
*/
public BuiltInOpenTelemetryMetricsRecorder getBuiltInMetricsRecorder() {
return this.builtInOpenTelemetryMetricsProvider.getBuiltInOpenTelemetryMetricsRecorder();
}

/** Returns attributes for an instance of Built-in Client metrics. */
public Map<String, String> getBuiltInMetricsClientAttributes() {
return builtInOpenTelemetryMetricsProvider.createOrGetClientAttributes(
this.getProjectId(), "spanner-java/" + GaxProperties.getLibraryVersion(getClass()));
/** Initialize the built-in metrics provider */
public void initializeBuiltInMetrics() {
this.builtInOpenTelemetryMetricsProvider.initialize(
this.getProjectId(),
"spanner-java/" + GaxProperties.getLibraryVersion(getClass()),
getCredentials(),
this.getMonitoringHost());
}

@Override
Expand Down Expand Up @@ -1882,13 +1887,10 @@ private ApiTracerFactory getDefaultApiTracerFactory() {
}

private ApiTracerFactory createMetricsApiTracerFactory() {
OpenTelemetry openTelemetry =
this.builtInOpenTelemetryMetricsProvider.getOrCreateOpenTelemetry(
this.getProjectId(), getCredentials(), this.monitoringHost);
OpenTelemetry openTelemetry = this.builtInOpenTelemetryMetricsProvider.getOpenTelemetry();

Map<String, String> clientAttributes =
builtInOpenTelemetryMetricsProvider.createOrGetClientAttributes(
this.getProjectId(), "spanner-java/" + GaxProperties.getLibraryVersion(getClass()));
builtInOpenTelemetryMetricsProvider.getClientAttributes();
return openTelemetry != null && clientAttributes != null
? new MetricsTracerFactory(
new OpenTelemetryMetricsRecorder(openTelemetry, BuiltInMetricsConstant.METER_NAME),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ public GapicSpannerRpc(final SpannerOptions options) {
this.endToEndTracingEnabled = options.isEndToEndTracingEnabled();
this.numChannels = options.getNumChannels();
this.isGrpcGcpExtensionEnabled = options.isGrpcGcpExtensionEnabled();
options.initializeBuiltInMetrics();

if (initializeStubs) {
// First check if SpannerOptions provides a TransportChannelProvider. Create one
Expand All @@ -357,8 +358,7 @@ public GapicSpannerRpc(final SpannerOptions options) {
options.getInterceptorProvider(),
SpannerInterceptorProvider.createDefault(
options.getOpenTelemetry(),
options.getBuiltInMetricsOpenTelemetry(),
options.getBuiltInMetricsClientAttributes(),
options.getBuiltInMetricsRecorder(),
(() -> directPathEnabledSupplier.get()))))
// This sets the trace context headers.
.withTraceContext(endToEndTracingEnabled, options.getOpenTelemetry())
Expand Down
Loading

0 comments on commit 59459ae

Please sign in to comment.