1717package com .google .cloud .storage ;
1818
1919import com .google .api .core .ApiFunction ;
20- import com .google .api .gax .grpc .InstantiatingGrpcChannelProvider ;
2120import com .google .api .gax .rpc .PermissionDeniedException ;
2221import com .google .api .gax .rpc .UnavailableException ;
2322import com .google .cloud .opentelemetry .metric .GoogleCloudMetricExporter ;
5958import java .util .concurrent .atomic .AtomicBoolean ;
6059import java .util .logging .Logger ;
6160import java .util .stream .Collectors ;
61+ import org .checkerframework .checker .nullness .qual .NonNull ;
62+ import org .checkerframework .checker .nullness .qual .Nullable ;
6263
6364final class OpenTelemetryBootstrappingUtils {
6465 private static final Collection <String > METRICS_TO_ENABLE =
@@ -88,15 +89,41 @@ final class OpenTelemetryBootstrappingUtils {
8889
8990 static final Logger log = Logger .getLogger (OpenTelemetryBootstrappingUtils .class .getName ());
9091
91- static void enableGrpcMetrics (
92- InstantiatingGrpcChannelProvider .Builder channelProviderBuilder ,
92+ @ NonNull
93+ static ChannelConfigurator enableGrpcMetrics (
94+ @ Nullable ChannelConfigurator channelConfigurator ,
9395 String endpoint ,
94- String projectId ,
96+ @ Nullable String projectId ,
9597 String universeDomain ,
9698 boolean shouldSuppressExceptions ) {
99+ GCPResourceProvider resourceProvider = new GCPResourceProvider ();
100+ Attributes detectedAttributes = resourceProvider .getAttributes ();
101+
102+ @ Nullable String detectedProjectId =
103+ detectedAttributes .get (AttributeKey .stringKey ("cloud.account.id" ));
104+ if (projectId == null && detectedProjectId == null ) {
105+ log .warning (
106+ "Unable to determine the Project ID in order to report metrics. No gRPC client metrics will be reported." );
107+ return channelConfigurator != null ? channelConfigurator : ChannelConfigurator .identity ();
108+ }
109+
110+ String projectIdToUse = detectedProjectId == null ? projectId : detectedProjectId ;
111+ if (!projectIdToUse .equals (projectId )) {
112+ log .warning (
113+ "The Project ID configured for gRPC client metrics is "
114+ + projectIdToUse
115+ + ", but the Project ID of the storage client is "
116+ + projectId
117+ + ". Make sure that the service account in use has the required metric writing role "
118+ + "(roles/monitoring.metricWriter) in the project "
119+ + projectIdToUse
120+ + ", or metrics will not be written." );
121+ }
122+
97123 String metricServiceEndpoint = getCloudMonitoringEndpoint (endpoint , universeDomain );
98124 SdkMeterProvider provider =
99- createMeterProvider (metricServiceEndpoint , projectId , shouldSuppressExceptions );
125+ createMeterProvider (
126+ metricServiceEndpoint , projectIdToUse , detectedAttributes , shouldSuppressExceptions );
100127
101128 OpenTelemetrySdk openTelemetrySdk =
102129 OpenTelemetrySdk .builder ().setMeterProvider (provider ).build ();
@@ -106,16 +133,48 @@ static void enableGrpcMetrics(
106133 .addOptionalLabel ("grpc.lb.locality" )
107134 .enableMetrics (METRICS_TO_ENABLE )
108135 .build ();
109- ApiFunction <ManagedChannelBuilder , ManagedChannelBuilder > channelConfigurator =
110- channelProviderBuilder .getChannelConfigurator ();
111- channelProviderBuilder .setChannelConfigurator (
136+ ChannelConfigurator otelConfigurator =
112137 b -> {
113138 grpcOpenTelemetry .configureChannelBuilder (b );
114- if (channelConfigurator != null ) {
115- return channelConfigurator .apply (b );
116- }
117139 return b ;
118- });
140+ };
141+ return otelConfigurator .andThen (channelConfigurator );
142+ }
143+
144+ @ SuppressWarnings ("rawtypes" ) // ManagedChannelBuilder
145+ @ FunctionalInterface
146+ interface ChannelConfigurator extends ApiFunction <ManagedChannelBuilder , ManagedChannelBuilder > {
147+ @ NonNull
148+ default ChannelConfigurator andThen (@ Nullable ChannelConfigurator then ) {
149+ if (then == null ) {
150+ return this ;
151+ }
152+ return b -> then .apply (this .apply (b ));
153+ }
154+
155+ static ChannelConfigurator identity () {
156+ return IdentityChannelConfigurator .INSTANCE ;
157+ }
158+
159+ static ChannelConfigurator lift (
160+ @ Nullable ApiFunction <ManagedChannelBuilder , ManagedChannelBuilder > f ) {
161+ if (f == null ) {
162+ return identity ();
163+ }
164+ return f ::apply ;
165+ }
166+ }
167+
168+ @ SuppressWarnings ("rawtypes" ) // ManagedChannelBuilder
169+ private static final class IdentityChannelConfigurator implements ChannelConfigurator {
170+ private static final IdentityChannelConfigurator INSTANCE = new IdentityChannelConfigurator ();
171+
172+ private IdentityChannelConfigurator () {}
173+
174+ @ Override
175+ public ManagedChannelBuilder apply (ManagedChannelBuilder input ) {
176+ return input ;
177+ }
119178 }
120179
121180 @ VisibleForTesting
@@ -147,24 +206,10 @@ static String getCloudMonitoringEndpoint(String endpoint, String universeDomain)
147206
148207 @ VisibleForTesting
149208 static SdkMeterProvider createMeterProvider (
150- String metricServiceEndpoint , String projectId , boolean shouldSuppressExceptions ) {
151- GCPResourceProvider resourceProvider = new GCPResourceProvider ();
152- Attributes detectedAttributes = resourceProvider .getAttributes ();
153-
154- String detectedProjectId = detectedAttributes .get (AttributeKey .stringKey ("cloud.account.id" ));
155- String projectIdToUse = detectedProjectId == null ? projectId : detectedProjectId ;
156-
157- if (!projectIdToUse .equals (projectId )) {
158- log .warning (
159- "The Project ID configured for metrics is "
160- + projectIdToUse
161- + ", but the Project ID of the storage client is "
162- + projectId
163- + ". Make sure that the service account in use has the required metric writing role "
164- + "(roles/monitoring.metricWriter) in the project "
165- + projectIdToUse
166- + ", or metrics will not be written." );
167- }
209+ String metricServiceEndpoint ,
210+ String projectIdToUse ,
211+ Attributes detectedAttributes ,
212+ boolean shouldSuppressExceptions ) {
168213
169214 MonitoredResourceDescription monitoredResourceDescription =
170215 new MonitoredResourceDescription (
0 commit comments