Skip to content

Commit 93ca602

Browse files
committed
support config bridge
1 parent e117b8a commit 93ca602

File tree

5 files changed

+170
-97
lines changed

5 files changed

+170
-97
lines changed

gcp-auth-extension/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ val agent: Configuration by configurations.creating {
1414
}
1515

1616
dependencies {
17+
implementation(project(":declarative-config-bridge"))
18+
1719
annotationProcessor("com.google.auto.service:auto-service")
1820
// We use `compileOnly` dependency because during runtime all necessary classes are provided by
1921
// javaagent itself.
@@ -36,6 +38,7 @@ dependencies {
3638
testImplementation("io.opentelemetry:opentelemetry-exporter-otlp")
3739
testImplementation("io.opentelemetry:opentelemetry-sdk-testing")
3840
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
41+
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator")
3942
testImplementation("io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations")
4043

4144
testImplementation("org.awaitility:awaitility")

gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/ConfigurableOption.java

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
1010
import java.util.Locale;
1111
import java.util.Optional;
12+
import java.util.function.BiFunction;
1213
import java.util.function.Supplier;
1314

1415
/**
@@ -99,9 +100,16 @@ String getUserReadableName() {
99100
* @throws ConfigurationException if neither the environment variable nor the system property is
100101
* set.
101102
*/
102-
String getConfiguredValue(ConfigProperties configProperties) {
103-
String configuredValue = configProperties.getString(this.getSystemProperty());
104-
if (configuredValue != null && !configuredValue.isEmpty()) {
103+
<T> T getConfiguredValue(ConfigProperties configProperties, BiFunction<ConfigProperties, String, T> extractor) {
104+
T configuredValue = extractor.apply(configProperties, this.getSystemProperty());
105+
if (configuredValue instanceof String) {
106+
String value = (String) configuredValue;
107+
if (value.isEmpty()) {
108+
configuredValue = null; // Treat empty string as not configured
109+
}
110+
}
111+
112+
if (configuredValue != null) {
105113
return configuredValue;
106114
} else {
107115
throw new ConfigurationException(
@@ -121,10 +129,10 @@ String getConfiguredValue(ConfigProperties configProperties) {
121129
* @return The configured value for the option, obtained from the environment variable, system
122130
* property, or the fallback function, in that order of precedence.
123131
*/
124-
String getConfiguredValueWithFallback(
125-
ConfigProperties configProperties, Supplier<String> fallback) {
132+
<T> T getConfiguredValueWithFallback(
133+
ConfigProperties configProperties, Supplier<T> fallback, BiFunction<ConfigProperties, String, T> extractor) {
126134
try {
127-
return this.getConfiguredValue(configProperties);
135+
return this.getConfiguredValue(configProperties, extractor);
128136
} catch (ConfigurationException e) {
129137
return fallback.get();
130138
}
@@ -140,7 +148,7 @@ String getConfiguredValueWithFallback(
140148
*/
141149
Optional<String> getConfiguredValueAsOptional(ConfigProperties configProperties) {
142150
try {
143-
return Optional.of(this.getConfiguredValue(configProperties));
151+
return Optional.of(this.getConfiguredValue(configProperties, ConfigProperties::getString));
144152
} catch (ConfigurationException e) {
145153
return Optional.empty();
146154
}

gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProvider.java

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import io.opentelemetry.sdk.resources.Resource;
2626
import io.opentelemetry.sdk.trace.export.SpanExporter;
2727
import java.io.IOException;
28-
import java.util.Arrays;
28+
import java.util.Collections;
2929
import java.util.List;
3030
import java.util.Map;
3131
import java.util.Objects;
@@ -83,7 +83,7 @@ public class GcpAuthAutoConfigurationCustomizerProvider
8383
* <li>If the configured signal specific endpoint is a known GCP Telemetry API endpoint,
8484
* customizes only the signal specific exporter.
8585
* </ul>
86-
*
86+
* <p>
8787
* The 'customization' performed includes customizing the exporters by adding required headers to
8888
* the export calls made and customizing the resource by adding required resource attributes to
8989
* enable GCP integration.
@@ -151,17 +151,20 @@ private static MetricExporter customizeMetricExporter(
151151
}
152152

153153
// Checks if the auth extension is configured to target the passed signal for authentication.
154-
private static boolean isSignalTargeted(String checkSignal, ConfigProperties configProperties) {
155-
String userSpecifiedTargetedSignals =
156-
ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getConfiguredValueWithFallback(
157-
configProperties, () -> SIGNAL_TYPE_ALL);
158-
return Arrays.stream(userSpecifiedTargetedSignals.split(","))
159-
.map(String::trim)
160-
.anyMatch(
154+
static boolean isSignalTargeted(String checkSignal, ConfigProperties configProperties) {
155+
return
156+
targetSignals(configProperties).stream().anyMatch(
161157
targetedSignal ->
162158
targetedSignal.equals(checkSignal) || targetedSignal.equals(SIGNAL_TYPE_ALL));
163159
}
164160

161+
static List<String> targetSignals(ConfigProperties configProperties) {
162+
return ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS
163+
.getConfiguredValueWithFallback(
164+
configProperties, () -> Collections.singletonList(SIGNAL_TYPE_ALL),
165+
ConfigProperties::getList);
166+
}
167+
165168
// Adds authorization headers to the calls made by the OtlpGrpcSpanExporter and
166169
// OtlpHttpSpanExporter.
167170
private static SpanExporter addAuthorizationHeaders(
@@ -221,23 +224,29 @@ static Map<String, String> getRequiredHeaderMap(
221224
// Add quota user project header if not detected by the auth library and user provided it via
222225
// system properties.
223226
if (!flattenedHeaders.containsKey(QUOTA_USER_PROJECT_HEADER)) {
224-
Optional<String> maybeConfiguredQuotaProjectId =
225-
ConfigurableOption.GOOGLE_CLOUD_QUOTA_PROJECT.getConfiguredValueAsOptional(
226-
configProperties);
227-
maybeConfiguredQuotaProjectId.ifPresent(
227+
getQuotaProjectId(configProperties).ifPresent(
228228
configuredQuotaProjectId ->
229229
flattenedHeaders.put(QUOTA_USER_PROJECT_HEADER, configuredQuotaProjectId));
230230
}
231231
return flattenedHeaders;
232232
}
233233

234+
static Optional<String> getQuotaProjectId(ConfigProperties configProperties) {
235+
return ConfigurableOption.GOOGLE_CLOUD_QUOTA_PROJECT.getConfiguredValueAsOptional(
236+
configProperties);
237+
}
238+
234239
// Updates the current resource with the attributes required for ingesting OTLP data on GCP.
235240
private static Resource customizeResource(Resource resource, ConfigProperties configProperties) {
236-
String gcpProjectId =
237-
ConfigurableOption.GOOGLE_CLOUD_PROJECT.getConfiguredValue(configProperties);
238241
Resource res =
239242
Resource.create(
240-
Attributes.of(AttributeKey.stringKey(GCP_USER_PROJECT_ID_KEY), gcpProjectId));
243+
Attributes.of(AttributeKey.stringKey(GCP_USER_PROJECT_ID_KEY),
244+
getProjectId(configProperties)));
241245
return resource.merge(res);
242246
}
247+
248+
static String getProjectId(ConfigProperties configProperties) {
249+
return ConfigurableOption.GOOGLE_CLOUD_PROJECT.getConfiguredValue(configProperties,
250+
ConfigProperties::getString);
251+
}
243252
}

gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthCustomizerProvider.java

Lines changed: 57 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@
55

66
package io.opentelemetry.contrib.gcp.auth;
77

8+
import static io.opentelemetry.contrib.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.SIGNAL_TYPE_TRACES;
9+
import static io.opentelemetry.contrib.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.isSignalTargeted;
10+
811
import com.google.auth.oauth2.GoogleCredentials;
912
import com.google.auto.service.AutoService;
13+
import io.opentelemetry.contrib.sdk.autoconfigure.ConfigPropertiesUtil;
14+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
1015
import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizer;
1116
import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider;
12-
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchLogRecordProcessorModel;
1317
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessorModel;
14-
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel;
15-
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordProcessorModel;
16-
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LoggerProviderModel;
1718
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MeterProviderModel;
1819
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricReaderModel;
1920
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel;
@@ -23,51 +24,76 @@
2324
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel;
2425
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpMetricExporterModel;
2526
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel;
26-
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SimpleLogRecordProcessorModel;
2727
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SimpleSpanProcessorModel;
2828
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterModel;
2929
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorModel;
3030
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TracerProviderModel;
3131
import java.util.ArrayList;
3232
import java.util.List;
3333
import java.util.Map;
34+
import javax.annotation.Nullable;
3435

3536
@AutoService(DeclarativeConfigurationCustomizerProvider.class)
3637
public class GcpAuthCustomizerProvider implements DeclarativeConfigurationCustomizerProvider {
3738

39+
// private static final String SIGNAL_TARGET_WARNING_FIX_SUGGESTION =
40+
// String.format(
41+
// "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.",
42+
// ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getUserReadableName(),
43+
// ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getEnvironmentVariable(),
44+
// ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty());
45+
46+
47+
3848
@Override
3949
public void customize(DeclarativeConfigurationCustomizer customizer) {
4050
customizer.addModelCustomizer(
4151
model -> {
52+
ConfigProperties configProperties = ConfigPropertiesUtil.resolveModel(model);
4253
GoogleCredentials credentials =
4354
GcpAuthAutoConfigurationCustomizerProvider.getCredentials();
44-
// todo pass config bridge
45-
Map<String, String> headerMap =
46-
GcpAuthAutoConfigurationCustomizerProvider.getRequiredHeaderMap(credentials, null);
47-
customizeMeter(model, headerMap);
48-
// todo are loggers supported now (not covered in old variant)?
49-
customizeLogger(model, headerMap);
50-
customizeTracer(model, headerMap);
55+
customize(model, credentials, configProperties);
5156

5257
return model;
5358
});
5459
}
5560

56-
private void customizeMeter(
57-
OpenTelemetryConfigurationModel model, Map<String, String> headerMap) {
61+
static void customize(OpenTelemetryConfigurationModel model,
62+
GoogleCredentials credentials, ConfigProperties configProperties) {
63+
Map<String, String> headerMap =
64+
GcpAuthAutoConfigurationCustomizerProvider.getRequiredHeaderMap(credentials,
65+
configProperties);
66+
customizeMeter(model, headerMap, configProperties);
67+
customizeTracer(model, headerMap, configProperties);
68+
}
69+
70+
private static void customizeMeter(
71+
OpenTelemetryConfigurationModel model, Map<String, String> headerMap,
72+
ConfigProperties configProperties) {
5873
MeterProviderModel meterProvider = model.getMeterProvider();
5974
if (meterProvider == null) {
6075
return;
6176
}
6277

78+
if (!isSignalTargeted(SIGNAL_TYPE_TRACES, configProperties)) {
79+
// todo
80+
// String[] params = {SIGNAL_TYPE_TRACES, SIGNAL_TARGET_WARNING_FIX_SUGGESTION};
81+
// logger.log(
82+
// Level.WARNING,
83+
// "GCP Authentication Extension is not configured for signal type: {0}. {1}",
84+
// params);
85+
return;
86+
}
87+
6388
for (MetricReaderModel reader : meterProvider.getReaders()) {
6489
if (reader.getPeriodic() != null) {
6590
addAuth(meterModelHeaders(reader.getPeriodic().getExporter()), headerMap);
6691
}
6792
}
6893
}
6994

70-
private List<List<NameStringValuePairModel>> meterModelHeaders(PushMetricExporterModel exporter) {
95+
private static List<List<NameStringValuePairModel>> meterModelHeaders(
96+
@Nullable PushMetricExporterModel exporter) {
7197
ArrayList<List<NameStringValuePairModel>> list = new ArrayList<>();
7298
if (exporter == null) {
7399
return list;
@@ -83,62 +109,23 @@ private List<List<NameStringValuePairModel>> meterModelHeaders(PushMetricExporte
83109
return list;
84110
}
85111

86-
private void customizeLogger(
87-
OpenTelemetryConfigurationModel model, Map<String, String> headerMap) {
88-
LoggerProviderModel loggerProvider = model.getLoggerProvider();
89-
if (loggerProvider == null) {
90-
return;
91-
}
92-
for (LogRecordProcessorModel processor : loggerProvider.getProcessors()) {
93-
BatchLogRecordProcessorModel batch = processor.getBatch();
94-
if (batch != null) {
95-
addAuth(logRecordModelHeaders(batch.getExporter()), headerMap);
96-
}
97-
SimpleLogRecordProcessorModel simple = processor.getSimple();
98-
if (simple != null) {
99-
addAuth(logRecordModelHeaders(simple.getExporter()), headerMap);
100-
}
101-
}
102-
}
103-
104-
private List<List<NameStringValuePairModel>> logRecordModelHeaders(
105-
LogRecordExporterModel exporter) {
106-
ArrayList<List<NameStringValuePairModel>> list = new ArrayList<>();
107-
108-
if (exporter == null) {
109-
return list;
110-
}
111-
OtlpGrpcExporterModel grpc = exporter.getOtlpGrpc();
112-
if (grpc != null) {
113-
list.add(grpc.getHeaders());
114-
}
115-
OtlpHttpExporterModel http = exporter.getOtlpHttp();
116-
if (http != null) {
117-
list.add(http.getHeaders());
118-
}
119-
return list;
120-
}
121-
122-
private void customizeTracer(
123-
OpenTelemetryConfigurationModel model, Map<String, String> headerMap) {
112+
private static void customizeTracer(
113+
OpenTelemetryConfigurationModel model, Map<String, String> headerMap,
114+
ConfigProperties configProperties) {
124115
TracerProviderModel tracerProvider = model.getTracerProvider();
125116
if (tracerProvider == null) {
126117
return;
127118
}
128119

129-
// todo here we would want a simplified version of the declarative config bridge
130-
// https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/DeclarativeConfigPropertiesBridge.java
131-
// googleNode(model)
132-
133-
// if (!isSignalTargeted(SIGNAL_TYPE_TRACES, configProperties)) {
134-
// todo
135-
// String[] params = {SIGNAL_TYPE_TRACES, SIGNAL_TARGET_WARNING_FIX_SUGGESTION};
136-
// logger.log(
137-
// Level.WARNING,
138-
// "GCP Authentication Extension is not configured for signal type: {0}. {1}",
139-
// params);
140-
// return;
141-
// }
120+
if (!isSignalTargeted(SIGNAL_TYPE_TRACES, configProperties)) {
121+
// todo
122+
// String[] params = {SIGNAL_TYPE_TRACES, SIGNAL_TARGET_WARNING_FIX_SUGGESTION};
123+
// logger.log(
124+
// Level.WARNING,
125+
// "GCP Authentication Extension is not configured for signal type: {0}. {1}",
126+
// params);
127+
return;
128+
}
142129

143130
for (SpanProcessorModel processor : tracerProvider.getProcessors()) {
144131
BatchSpanProcessorModel batch = processor.getBatch();
@@ -152,12 +139,8 @@ private void customizeTracer(
152139
}
153140
}
154141

155-
private void googleNode(OpenTelemetryConfigurationModel model) {
156-
// todo use declarative config bridge
157-
}
158-
159-
private List<List<NameStringValuePairModel>> spanExporterModelHeaders(
160-
SpanExporterModel exporter) {
142+
private static List<List<NameStringValuePairModel>> spanExporterModelHeaders(
143+
@Nullable SpanExporterModel exporter) {
161144
ArrayList<List<NameStringValuePairModel>> list = new ArrayList<>();
162145

163146
if (exporter == null) {
@@ -174,12 +157,12 @@ private List<List<NameStringValuePairModel>> spanExporterModelHeaders(
174157
return list;
175158
}
176159

177-
private void addAuth(
160+
private static void addAuth(
178161
List<List<NameStringValuePairModel>> headerConsumers, Map<String, String> headerMap) {
179162
headerConsumers.forEach(headers -> addHeaders(headers, headerMap));
180163
}
181164

182-
private void addHeaders(List<NameStringValuePairModel> headers, Map<String, String> add) {
165+
private static void addHeaders(List<NameStringValuePairModel> headers, Map<String, String> add) {
183166
add.forEach(
184167
(key, value) -> {
185168
if (headers.stream().noneMatch(header -> key.equals(header.getName()))) {

0 commit comments

Comments
 (0)