2626import com .google .auto .service .AutoService ;
2727import io .opentelemetry .api .common .Attributes ;
2828import io .opentelemetry .exporter .otlp .http .metrics .OtlpHttpMetricExporter ;
29- import io .opentelemetry .exporter .otlp .http .metrics .OtlpHttpMetricExporterBuilder ;
3029import io .opentelemetry .exporter .otlp .http .trace .OtlpHttpSpanExporter ;
31- import io .opentelemetry .exporter .otlp .http .trace .OtlpHttpSpanExporterBuilder ;
3230import io .opentelemetry .exporter .otlp .metrics .OtlpGrpcMetricExporter ;
33- import io .opentelemetry .exporter .otlp .metrics .OtlpGrpcMetricExporterBuilder ;
3431import io .opentelemetry .exporter .otlp .trace .OtlpGrpcSpanExporter ;
35- import io .opentelemetry .exporter .otlp .trace .OtlpGrpcSpanExporterBuilder ;
3632import io .opentelemetry .sdk .autoconfigure .spi .AutoConfigurationCustomizer ;
3733import io .opentelemetry .sdk .autoconfigure .spi .AutoConfigurationCustomizerProvider ;
3834import io .opentelemetry .sdk .autoconfigure .spi .ConfigProperties ;
4541import java .util .Map ;
4642import java .util .Objects ;
4743import java .util .Optional ;
48- import java .util .logging .Level ;
49- import java .util .logging .Logger ;
5044import javax .annotation .Nonnull ;
45+ import javax .annotation .Nullable ;
5146import org .apache .beam .sdk .extensions .opentelemetry .gcp .auth .GoogleAuthException .Reason ;
5247
5348/**
7065public class GcpAuthAutoConfigurationCustomizerProvider
7166 implements AutoConfigurationCustomizerProvider {
7267
73- private static final Logger logger =
74- Logger .getLogger (GcpAuthAutoConfigurationCustomizerProvider .class .getName ());
75- private static final String SIGNAL_TARGET_WARNING_FIX_SUGGESTION =
76- String .format (
77- "You may safely ignore this warning if it is intentional, otherwise please configure the '%s' by exporting valid values to environment variable: %s or by setting valid values in system property: %s." ,
78- ConfigurableOption .GOOGLE_OTEL_AUTH_TARGET_SIGNALS .getUserReadableName (),
79- ConfigurableOption .GOOGLE_OTEL_AUTH_TARGET_SIGNALS .getEnvironmentVariable (),
80- ConfigurableOption .GOOGLE_OTEL_AUTH_TARGET_SIGNALS .getSystemProperty ());
81-
8268 static final String QUOTA_USER_PROJECT_HEADER = "x-goog-user-project" ;
8369 static final String GCP_USER_PROJECT_ID_KEY = "gcp.project_id" ;
8470
8571 static final String SIGNAL_TYPE_TRACES = "traces" ;
8672 static final String SIGNAL_TYPE_METRICS = "metrics" ;
8773 static final String SIGNAL_TYPE_ALL = "all" ;
8874
75+ private @ Nullable GoogleCredentials credentials ;
76+
8977 /**
9078 * Customizes the provided {@link AutoConfigurationCustomizer} such that authenticated exports to
9179 * GCP Telemetry API are possible from the configured OTLP exporter.
9280 *
93- * <p>This method attempts to retrieve Google Application Default Credentials (ADC) and performs
94- * the following:
81+ * <p>This method performs the following:
9582 *
9683 * <ul>
9784 * <li>Verifies whether the configured OTLP endpoint (base or signal specific) is a known GCP
@@ -114,53 +101,40 @@ public class GcpAuthAutoConfigurationCustomizerProvider
114101 */
115102 @ Override
116103 public void customize (@ Nonnull AutoConfigurationCustomizer autoConfiguration ) {
117- GoogleCredentials credentials ;
118- try {
119- credentials = GoogleCredentials .getApplicationDefault ();
120- } catch (IOException e ) {
121- throw new GoogleAuthException (Reason .FAILED_ADC_RETRIEVAL , e );
122- }
123104 autoConfiguration
124- .addSpanExporterCustomizer (
125- (spanExporter , configProperties ) ->
126- customizeSpanExporter (spanExporter , credentials , configProperties ))
127- .addMetricExporterCustomizer (
128- (metricExporter , configProperties ) ->
129- customizeMetricExporter (metricExporter , credentials , configProperties ))
130- .addResourceCustomizer (
131- (resource , configProperties ) ->
132- customizeResource (resource , credentials , configProperties ));
105+ .addSpanExporterCustomizer (this ::customizeSpanExporter )
106+ .addMetricExporterCustomizer (this ::customizeMetricExporter )
107+ .addResourceCustomizer (this ::customizeResource );
133108 }
134109
135110 @ Override
136111 public int order () {
137112 return Integer .MAX_VALUE - 1 ;
138113 }
139114
140- private static SpanExporter customizeSpanExporter (
141- SpanExporter exporter , GoogleCredentials credentials , ConfigProperties configProperties ) {
115+ private synchronized GoogleCredentials getCredentials () {
116+ if (credentials == null ) {
117+ try {
118+ credentials = GoogleCredentials .getApplicationDefault ();
119+ } catch (IOException e ) {
120+ throw new GoogleAuthException (Reason .FAILED_ADC_RETRIEVAL , e );
121+ }
122+ }
123+ return credentials ;
124+ }
125+
126+ private SpanExporter customizeSpanExporter (
127+ SpanExporter exporter , ConfigProperties configProperties ) {
142128 if (isSignalTargeted (SIGNAL_TYPE_TRACES , configProperties )) {
143- return addAuthorizationHeaders (exporter , credentials , configProperties );
144- } else {
145- String [] params = {SIGNAL_TYPE_TRACES , SIGNAL_TARGET_WARNING_FIX_SUGGESTION };
146- logger .log (
147- Level .WARNING ,
148- "GCP Authentication Extension is not configured for signal type: {0}. {1}" ,
149- params );
129+ return addAuthorizationHeaders (exporter , configProperties );
150130 }
151131 return exporter ;
152132 }
153133
154- private static MetricExporter customizeMetricExporter (
155- MetricExporter exporter , GoogleCredentials credentials , ConfigProperties configProperties ) {
134+ private MetricExporter customizeMetricExporter (
135+ MetricExporter exporter , ConfigProperties configProperties ) {
156136 if (isSignalTargeted (SIGNAL_TYPE_METRICS , configProperties )) {
157- return addAuthorizationHeaders (exporter , credentials , configProperties );
158- } else {
159- String [] params = {SIGNAL_TYPE_METRICS , SIGNAL_TARGET_WARNING_FIX_SUGGESTION };
160- logger .log (
161- Level .WARNING ,
162- "GCP Authentication Extension is not configured for signal type: {0}. {1}" ,
163- params );
137+ return addAuthorizationHeaders (exporter , configProperties );
164138 }
165139 return exporter ;
166140 }
@@ -186,57 +160,74 @@ private static boolean isSignalTargeted(String checkSignal, ConfigProperties con
186160 targetedSignal .equals (checkSignal ) || targetedSignal .equals (SIGNAL_TYPE_ALL ));
187161 }
188162
163+ private boolean isAnySignalTargeted (ConfigProperties configProperties ) {
164+ return isSignalTargeted (SIGNAL_TYPE_TRACES , configProperties )
165+ || isSignalTargeted (SIGNAL_TYPE_METRICS , configProperties );
166+ }
167+
189168 // Adds authorization headers to the calls made by the OtlpGrpcSpanExporter and
190169 // OtlpHttpSpanExporter.
191- private static SpanExporter addAuthorizationHeaders (
192- SpanExporter exporter , GoogleCredentials credentials , ConfigProperties configProperties ) {
170+ private SpanExporter addAuthorizationHeaders (
171+ SpanExporter exporter , ConfigProperties configProperties ) {
193172 if (exporter instanceof OtlpHttpSpanExporter ) {
194- OtlpHttpSpanExporterBuilder builder =
173+ SpanExporter result =
195174 ((OtlpHttpSpanExporter ) exporter )
196175 .toBuilder ()
197- .setHeaders (() -> getRequiredHeaderMap (credentials , configProperties ));
198- return builder .build ();
176+ .setHeaders (() -> getRequiredHeaderMap (configProperties ))
177+ .build ();
178+ exporter .shutdown ();
179+ return result ;
199180 } else if (exporter instanceof OtlpGrpcSpanExporter ) {
200- OtlpGrpcSpanExporterBuilder builder =
181+ SpanExporter result =
201182 ((OtlpGrpcSpanExporter ) exporter )
202183 .toBuilder ()
203- .setHeaders (() -> getRequiredHeaderMap (credentials , configProperties ));
204- return builder .build ();
184+ .setHeaders (() -> getRequiredHeaderMap (configProperties ))
185+ .build ();
186+ exporter .shutdown ();
187+ return result ;
205188 }
206189 return exporter ;
207190 }
208191
209192 // Adds authorization headers to the calls made by the OtlpGrpcMetricExporter and
210193 // OtlpHttpMetricExporter.
211- private static MetricExporter addAuthorizationHeaders (
212- MetricExporter exporter , GoogleCredentials credentials , ConfigProperties configProperties ) {
194+ private MetricExporter addAuthorizationHeaders (
195+ MetricExporter exporter , ConfigProperties configProperties ) {
213196 if (exporter instanceof OtlpHttpMetricExporter ) {
214- OtlpHttpMetricExporterBuilder builder =
197+ MetricExporter result =
215198 ((OtlpHttpMetricExporter ) exporter )
216199 .toBuilder ()
217- .setHeaders (() -> getRequiredHeaderMap (credentials , configProperties ));
218- return builder .build ();
200+ .setHeaders (() -> getRequiredHeaderMap (configProperties ))
201+ .build ();
202+ exporter .shutdown ();
203+ return result ;
219204 } else if (exporter instanceof OtlpGrpcMetricExporter ) {
220- OtlpGrpcMetricExporterBuilder builder =
205+ MetricExporter result =
221206 ((OtlpGrpcMetricExporter ) exporter )
222207 .toBuilder ()
223- .setHeaders (() -> getRequiredHeaderMap (credentials , configProperties ));
224- return builder .build ();
208+ .setHeaders (() -> getRequiredHeaderMap (configProperties ))
209+ .build ();
210+ exporter .shutdown ();
211+ return result ;
225212 }
226213 return exporter ;
227214 }
228215
229- private static Map <String , String > getRequiredHeaderMap (
230- GoogleCredentials credentials , ConfigProperties configProperties ) {
216+ private Map <String , String > getRequiredHeaderMap (ConfigProperties configProperties ) {
217+ GoogleCredentials creds = getCredentials ();
231218 Map <String , List <String >> gcpHeaders ;
232219 try {
233220 // this also refreshes the credentials, if required
234- gcpHeaders = credentials .getRequestMetadata ();
221+ gcpHeaders = creds .getRequestMetadata ();
235222 } catch (IOException e ) {
236223 throw new GoogleAuthException (Reason .FAILED_ADC_REFRESH , e );
237224 }
225+ if (gcpHeaders == null ) {
226+ return Map .of ();
227+ }
238228 Map <String , String > flattenedHeaders =
239229 gcpHeaders .entrySet ().stream ()
230+ .filter (entry -> entry .getKey () != null && entry .getValue () != null )
240231 .collect (
241232 toMap (
242233 Map .Entry ::getKey ,
@@ -259,13 +250,16 @@ private static Map<String, String> getRequiredHeaderMap(
259250 }
260251
261252 // Updates the current resource with the attributes required for ingesting OTLP data on GCP.
262- private static Resource customizeResource (
263- Resource resource , GoogleCredentials credentials , ConfigProperties configProperties ) {
253+ private Resource customizeResource (Resource resource , ConfigProperties configProperties ) {
254+ if (!isAnySignalTargeted (configProperties )) {
255+ return resource ;
256+ }
257+
264258 String gcpProjectId ;
265259 try {
266260 gcpProjectId = ConfigurableOption .GOOGLE_CLOUD_PROJECT .getConfiguredValue (configProperties );
267261 } catch (ConfigurationException e ) {
268- gcpProjectId = credentials .getProjectId ();
262+ gcpProjectId = getCredentials () .getProjectId ();
269263 if (gcpProjectId == null || gcpProjectId .isEmpty ()) {
270264 throw e ;
271265 }
0 commit comments