diff --git a/gcp-auth-extension/README.md b/gcp-auth-extension/README.md
index bb2c32886..ba5e1be15 100644
--- a/gcp-auth-extension/README.md
+++ b/gcp-auth-extension/README.md
@@ -47,6 +47,10 @@ Here is a list of required and optional configuration available for the extensio
- Can also be configured using `google.cloud.quota.project` system property.
+- `GOOGLE_OTEL_AUTH_TARGET_SIGNALS`: Environment variable that specifies a comma-separated list of OpenTelemetry signals for which this authentication extension should be active. Valid values contain - `metrics`, `traces` or `all`. If left unspecified, `all` is assumed meaning the extension will attempt to apply authentication to exports for all signals.
+
+ - Can also be configured using `google.otel.auth.target.signals` system property.
+
## Usage
### With OpenTelemetry Java agent
diff --git a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/ConfigurableOption.java b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/ConfigurableOption.java
index 7928f9ab4..5f4a627e1 100644
--- a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/ConfigurableOption.java
+++ b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/ConfigurableOption.java
@@ -30,7 +30,27 @@ public enum ConfigurableOption {
* href="https://cloud.google.com/docs/quotas/set-quota-project">official GCP client
* libraries.
*/
- GOOGLE_CLOUD_QUOTA_PROJECT("Google Cloud Quota Project ID");
+ GOOGLE_CLOUD_QUOTA_PROJECT("Google Cloud Quota Project ID"),
+
+ /**
+ * Specifies a comma-separated list of OpenTelemetry signals for which this authentication
+ * extension should be active. The authentication mechanisms provided by this extension will only
+ * be applied to the listed signals. If not set, {@code all} is assumed to be set which means
+ * authentication is enabled for all supported signals.
+ *
+ *
Valid signal values are:
+ *
+ *
+ * - {@code metrics} - Enables authentication for metric exports.
+ *
- {@code traces} - Enables authentication for trace exports.
+ *
- {@code all} - Enables authentication for all exports.
+ *
+ *
+ * The values are case-sensitive. Whitespace around commas and values is ignored. Can be
+ * configured using the environment variable `GOOGLE_OTEL_AUTH_TARGET_SIGNALS` or the system
+ * property `google.otel.auth.target.signals`.
+ */
+ GOOGLE_OTEL_AUTH_TARGET_SIGNALS("Target Signals for Google Auth Extension");
private final String userReadableName;
private final String environmentVariableName;
diff --git a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProvider.java b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProvider.java
index 053aeef7d..d6c68e54f 100644
--- a/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProvider.java
+++ b/gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProvider.java
@@ -10,21 +10,28 @@
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.contrib.gcp.auth.GoogleAuthException.Reason;
+import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
+import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporterBuilder;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder;
+import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter;
+import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder;
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer;
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
+import io.opentelemetry.sdk.metrics.export.MetricExporter;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import java.io.IOException;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
/**
* An AutoConfigurationCustomizerProvider for Google Cloud Platform (GCP) OpenTelemetry (OTLP)
@@ -46,13 +53,29 @@ public class GcpAuthAutoConfigurationCustomizerProvider
static final String QUOTA_USER_PROJECT_HEADER = "x-goog-user-project";
static final String GCP_USER_PROJECT_ID_KEY = "gcp.project_id";
+ static final String SIGNAL_TYPE_TRACES = "traces";
+ static final String SIGNAL_TYPE_METRICS = "metrics";
+ static final String SIGNAL_TYPE_ALL = "all";
+
/**
- * Customizes the provided {@link AutoConfigurationCustomizer}.
+ * Customizes the provided {@link AutoConfigurationCustomizer} such that authenticated exports to
+ * GCP Telemetry API are possible from the configured OTLP exporter.
*
*
This method attempts to retrieve Google Application Default Credentials (ADC) and performs
- * the following: - Adds authorization headers to the configured {@link SpanExporter} based on the
- * retrieved credentials. - Adds default properties for OTLP endpoint and resource attributes for
- * GCP integration.
+ * the following:
+ *
+ *
+ * - Verifies whether the configured OTLP endpoint (base or signal specific) is a known GCP
+ * endpoint.
+ *
- If the configured base OTLP endpoint is a known GCP Telemetry API endpoint, customizes
+ * both the configured OTLP {@link SpanExporter} and {@link MetricExporter}.
+ *
- If the configured signal specific endpoint is a known GCP Telemetry API endpoint,
+ * customizes only the signal specific exporter.
+ *
+ *
+ * The 'customization' performed includes customizing the exporters by adding required headers to
+ * the export calls made and customizing the resource by adding required resource attributes to
+ * enable GCP integration.
*
* @param autoConfiguration the AutoConfigurationCustomizer to customize.
* @throws GoogleAuthException if there's an error retrieving Google Application Default
@@ -61,7 +84,7 @@ public class GcpAuthAutoConfigurationCustomizerProvider
* not configured through environment variables or system properties.
*/
@Override
- public void customize(AutoConfigurationCustomizer autoConfiguration) {
+ public void customize(@Nonnull AutoConfigurationCustomizer autoConfiguration) {
GoogleCredentials credentials;
try {
credentials = GoogleCredentials.getApplicationDefault();
@@ -70,7 +93,10 @@ public void customize(AutoConfigurationCustomizer autoConfiguration) {
}
autoConfiguration
.addSpanExporterCustomizer(
- (exporter, configProperties) -> addAuthorizationHeaders(exporter, credentials))
+ (spanExporter, configProperties) -> customizeSpanExporter(spanExporter, credentials))
+ .addMetricExporterCustomizer(
+ (metricExporter, configProperties) ->
+ customizeMetricExporter(metricExporter, credentials))
.addResourceCustomizer(GcpAuthAutoConfigurationCustomizerProvider::customizeResource);
}
@@ -79,6 +105,34 @@ public int order() {
return Integer.MAX_VALUE - 1;
}
+ private static SpanExporter customizeSpanExporter(
+ SpanExporter exporter, GoogleCredentials credentials) {
+ if (isSignalTargeted(SIGNAL_TYPE_TRACES)) {
+ return addAuthorizationHeaders(exporter, credentials);
+ }
+ return exporter;
+ }
+
+ private static MetricExporter customizeMetricExporter(
+ MetricExporter exporter, GoogleCredentials credentials) {
+ if (isSignalTargeted(SIGNAL_TYPE_METRICS)) {
+ return addAuthorizationHeaders(exporter, credentials);
+ }
+ return exporter;
+ }
+
+ // Checks if the auth extension is configured to target the passed signal for authentication.
+ private static boolean isSignalTargeted(String checkSignal) {
+ String userSpecifiedTargetedSignals =
+ ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getConfiguredValueWithFallback(
+ () -> SIGNAL_TYPE_ALL);
+ return Arrays.stream(userSpecifiedTargetedSignals.split(","))
+ .map(String::trim)
+ .anyMatch(
+ targetedSignal ->
+ targetedSignal.equals(checkSignal) || targetedSignal.equals(SIGNAL_TYPE_ALL));
+ }
+
// Adds authorization headers to the calls made by the OtlpGrpcSpanExporter and
// OtlpHttpSpanExporter.
private static SpanExporter addAuthorizationHeaders(
@@ -97,6 +151,24 @@ private static SpanExporter addAuthorizationHeaders(
return exporter;
}
+ // Adds authorization headers to the calls made by the OtlpGrpcMetricExporter and
+ // OtlpHttpMetricExporter.
+ private static MetricExporter addAuthorizationHeaders(
+ MetricExporter exporter, GoogleCredentials credentials) {
+ if (exporter instanceof OtlpHttpMetricExporter) {
+ OtlpHttpMetricExporterBuilder builder =
+ ((OtlpHttpMetricExporter) exporter)
+ .toBuilder().setHeaders(() -> getRequiredHeaderMap(credentials));
+ return builder.build();
+ } else if (exporter instanceof OtlpGrpcMetricExporter) {
+ OtlpGrpcMetricExporterBuilder builder =
+ ((OtlpGrpcMetricExporter) exporter)
+ .toBuilder().setHeaders(() -> getRequiredHeaderMap(credentials));
+ return builder.build();
+ }
+ return exporter;
+ }
+
private static Map getRequiredHeaderMap(GoogleCredentials credentials) {
Map> gcpHeaders;
try {
diff --git a/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProviderTest.java b/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProviderTest.java
index 5cbee0890..de96dc382 100644
--- a/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProviderTest.java
+++ b/gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProviderTest.java
@@ -7,6 +7,9 @@
import static io.opentelemetry.contrib.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.GCP_USER_PROJECT_ID_KEY;
import static io.opentelemetry.contrib.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.QUOTA_USER_PROJECT_HEADER;
+import static io.opentelemetry.contrib.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.SIGNAL_TYPE_ALL;
+import static io.opentelemetry.contrib.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.SIGNAL_TYPE_METRICS;
+import static io.opentelemetry.contrib.gcp.auth.GcpAuthAutoConfigurationCustomizerProvider.SIGNAL_TYPE_TRACES;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -17,10 +20,16 @@
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableMap;
import io.opentelemetry.api.common.AttributeKey;
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.metrics.LongCounter;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
+import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
+import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporterBuilder;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder;
+import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter;
+import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder;
import io.opentelemetry.sdk.OpenTelemetrySdk;
@@ -31,8 +40,15 @@
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
+import io.opentelemetry.sdk.autoconfigure.spi.metrics.ConfigurableMetricExporterProvider;
import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider;
import io.opentelemetry.sdk.common.CompletableResultCode;
+import io.opentelemetry.sdk.common.export.MemoryMode;
+import io.opentelemetry.sdk.metrics.Aggregation;
+import io.opentelemetry.sdk.metrics.InstrumentType;
+import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
+import io.opentelemetry.sdk.metrics.data.MetricData;
+import io.opentelemetry.sdk.metrics.export.MetricExporter;
import io.opentelemetry.sdk.trace.data.SpanData;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import java.io.IOException;
@@ -45,10 +61,12 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Stream;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -63,19 +81,24 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.stubbing.Answer;
@ExtendWith(MockitoExtension.class)
class GcpAuthAutoConfigurationCustomizerProviderTest {
private static final String DUMMY_GCP_RESOURCE_PROJECT_ID = "my-gcp-resource-project-id";
private static final String DUMMY_GCP_QUOTA_PROJECT_ID = "my-gcp-quota-project-id";
+ private static final Random TEST_RANDOM = new Random();
@Mock private GoogleCredentials mockedGoogleCredentials;
- @Captor private ArgumentCaptor>> headerSupplierCaptor;
+ @Captor private ArgumentCaptor>> traceHeaderSupplierCaptor;
+ @Captor private ArgumentCaptor>> metricHeaderSupplierCaptor;
- private static final ImmutableMap otelProperties =
+ private static final ImmutableMap defaultOtelPropertiesSpanExporter =
ImmutableMap.of(
+ "otel.exporter.otlp.traces.endpoint",
+ "https://telemetry.googleapis.com/v1/traces",
"otel.traces.exporter",
"otlp",
"otel.metrics.exporter",
@@ -85,16 +108,32 @@ class GcpAuthAutoConfigurationCustomizerProviderTest {
"otel.resource.attributes",
"foo=bar");
+ private static final ImmutableMap defaultOtelPropertiesMetricExporter =
+ ImmutableMap.of(
+ "otel.exporter.otlp.metrics.endpoint",
+ "https://telemetry.googleapis.com/v1/metrics",
+ "otel.traces.exporter",
+ "none",
+ "otel.metrics.exporter",
+ "otlp",
+ "otel.logs.exporter",
+ "none",
+ "otel.resource.attributes",
+ "foo=bar");
+
@BeforeEach
public void setup() {
MockitoAnnotations.openMocks(this);
}
+ // TODO: Use parameterized test for testing traces customizer for http & grpc.
@Test
- public void testCustomizerOtlpHttp() {
+ public void testTraceCustomizerOtlpHttp() {
// Set resource project system property
System.setProperty(
ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty(), DUMMY_GCP_RESOURCE_PROJECT_ID);
+ System.setProperty(
+ ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty(), SIGNAL_TYPE_TRACES);
// Prepare mocks
prepareMockBehaviorForGoogleCredentials();
OtlpHttpSpanExporter mockOtlpHttpSpanExporter = Mockito.mock(OtlpHttpSpanExporter.class);
@@ -113,6 +152,7 @@ public void testCustomizerOtlpHttp() {
});
Mockito.when(mockOtlpHttpSpanExporter.toBuilder()).thenReturn(spyOtlpHttpSpanExporterBuilder);
+ // begin assertions
try (MockedStatic googleCredentialsMockedStatic =
Mockito.mockStatic(GoogleCredentials.class)) {
googleCredentialsMockedStatic
@@ -127,9 +167,10 @@ public void testCustomizerOtlpHttp() {
Mockito.verify(mockOtlpHttpSpanExporter, Mockito.times(1)).toBuilder();
Mockito.verify(spyOtlpHttpSpanExporterBuilder, Mockito.times(1))
- .setHeaders(headerSupplierCaptor.capture());
- assertEquals(2, headerSupplierCaptor.getValue().get().size());
- assertThat(authHeadersQuotaProjectIsPresent(headerSupplierCaptor.getValue().get())).isTrue();
+ .setHeaders(traceHeaderSupplierCaptor.capture());
+ assertEquals(2, traceHeaderSupplierCaptor.getValue().get().size());
+ assertThat(authHeadersQuotaProjectIsPresent(traceHeaderSupplierCaptor.getValue().get()))
+ .isTrue();
Mockito.verify(mockOtlpHttpSpanExporter, Mockito.atLeast(1)).export(Mockito.anyCollection());
@@ -149,19 +190,22 @@ public void testCustomizerOtlpHttp() {
}
@Test
- public void testCustomizerOtlpGrpc() {
+ public void testTraceCustomizerOtlpGrpc() {
// Set resource project system property
System.setProperty(
ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty(), DUMMY_GCP_RESOURCE_PROJECT_ID);
+ System.setProperty(
+ ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty(), SIGNAL_TYPE_TRACES);
// Prepare mocks
prepareMockBehaviorForGoogleCredentials();
OtlpGrpcSpanExporter mockOtlpGrpcSpanExporter = Mockito.mock(OtlpGrpcSpanExporter.class);
OtlpGrpcSpanExporterBuilder spyOtlpGrpcSpanExporterBuilder =
Mockito.spy(OtlpGrpcSpanExporter.builder());
List exportedSpans = new ArrayList<>();
- configureGrpcMockExporters(
+ configureGrpcMockSpanExporter(
mockOtlpGrpcSpanExporter, spyOtlpGrpcSpanExporterBuilder, exportedSpans);
+ // begin assertions
try (MockedStatic googleCredentialsMockedStatic =
Mockito.mockStatic(GoogleCredentials.class)) {
googleCredentialsMockedStatic
@@ -176,9 +220,10 @@ public void testCustomizerOtlpGrpc() {
Mockito.verify(mockOtlpGrpcSpanExporter, Mockito.times(1)).toBuilder();
Mockito.verify(spyOtlpGrpcSpanExporterBuilder, Mockito.times(1))
- .setHeaders(headerSupplierCaptor.capture());
- assertEquals(2, headerSupplierCaptor.getValue().get().size());
- assertThat(authHeadersQuotaProjectIsPresent(headerSupplierCaptor.getValue().get())).isTrue();
+ .setHeaders(traceHeaderSupplierCaptor.capture());
+ assertEquals(2, traceHeaderSupplierCaptor.getValue().get().size());
+ assertThat(authHeadersQuotaProjectIsPresent(traceHeaderSupplierCaptor.getValue().get()))
+ .isTrue();
Mockito.verify(mockOtlpGrpcSpanExporter, Mockito.atLeast(1)).export(Mockito.anyCollection());
@@ -197,8 +242,133 @@ public void testCustomizerOtlpGrpc() {
}
}
+ // TODO: Use parameterized test for testing metrics customizer for http & grpc.
+ @Test
+ public void testMetricCustomizerOtlpHttp() {
+ // Set resource project system property
+ System.setProperty(
+ ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty(), DUMMY_GCP_RESOURCE_PROJECT_ID);
+ System.setProperty(
+ ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty(),
+ SIGNAL_TYPE_METRICS);
+ // Prepare mocks
+ prepareMockBehaviorForGoogleCredentials();
+ OtlpHttpMetricExporter mockOtlpHttpMetricExporter = Mockito.mock(OtlpHttpMetricExporter.class);
+ OtlpHttpMetricExporterBuilder otlpMetricExporterBuilder = OtlpHttpMetricExporter.builder();
+ OtlpHttpMetricExporterBuilder spyOtlpHttpMetricExporterBuilder =
+ Mockito.spy(otlpMetricExporterBuilder);
+ List exportedMetrics = new ArrayList<>();
+ configureHttpMockMetricExporter(
+ mockOtlpHttpMetricExporter, spyOtlpHttpMetricExporterBuilder, exportedMetrics);
+
+ // begin assertions
+ try (MockedStatic googleCredentialsMockedStatic =
+ Mockito.mockStatic(GoogleCredentials.class)) {
+ googleCredentialsMockedStatic
+ .when(GoogleCredentials::getApplicationDefault)
+ .thenReturn(mockedGoogleCredentials);
+
+ OpenTelemetrySdk sdk = buildOpenTelemetrySdkWithExporter(mockOtlpHttpMetricExporter);
+ generateTestMetric(sdk);
+ CompletableResultCode code = sdk.shutdown();
+ CompletableResultCode joinResult = code.join(10, TimeUnit.SECONDS);
+ assertTrue(joinResult.isSuccess());
+
+ Mockito.verify(mockOtlpHttpMetricExporter, Mockito.times(1)).toBuilder();
+ Mockito.verify(spyOtlpHttpMetricExporterBuilder, Mockito.times(1))
+ .setHeaders(metricHeaderSupplierCaptor.capture());
+ assertEquals(2, metricHeaderSupplierCaptor.getValue().get().size());
+ assertThat(authHeadersQuotaProjectIsPresent(metricHeaderSupplierCaptor.getValue().get()))
+ .isTrue();
+
+ Mockito.verify(mockOtlpHttpMetricExporter, Mockito.atLeast(1))
+ .export(Mockito.anyCollection());
+
+ assertThat(exportedMetrics)
+ .hasSizeGreaterThan(0)
+ .allSatisfy(
+ metricData -> {
+ assertThat(metricData.getResource().getAttributes().asMap())
+ .containsEntry(
+ AttributeKey.stringKey(GCP_USER_PROJECT_ID_KEY),
+ DUMMY_GCP_RESOURCE_PROJECT_ID)
+ .containsEntry(AttributeKey.stringKey("foo"), "bar");
+ assertThat(metricData.getLongSumData().getPoints())
+ .hasSizeGreaterThan(0)
+ .allSatisfy(
+ longPointData -> {
+ assertThat(longPointData.getAttributes().asMap())
+ .containsKey(AttributeKey.longKey("work_loop"));
+ });
+ });
+ }
+ }
+
+ @Test
+ public void testMetricCustomizerOtlpGrpc() {
+ // Set resource project system property
+ System.setProperty(
+ ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty(), DUMMY_GCP_RESOURCE_PROJECT_ID);
+ System.setProperty(
+ ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty(),
+ SIGNAL_TYPE_METRICS);
+ // Prepare mocks
+ prepareMockBehaviorForGoogleCredentials();
+ OtlpGrpcMetricExporter mockOtlpGrpcMetricExporter = Mockito.mock(OtlpGrpcMetricExporter.class);
+ OtlpGrpcMetricExporterBuilder otlpMetricExporterBuilder = OtlpGrpcMetricExporter.builder();
+ OtlpGrpcMetricExporterBuilder spyOtlpGrpcMetricExporterBuilder =
+ Mockito.spy(otlpMetricExporterBuilder);
+ List exportedMetrics = new ArrayList<>();
+ configureGrpcMockMetricExporter(
+ mockOtlpGrpcMetricExporter, spyOtlpGrpcMetricExporterBuilder, exportedMetrics);
+
+ // begin assertions
+ try (MockedStatic googleCredentialsMockedStatic =
+ Mockito.mockStatic(GoogleCredentials.class)) {
+ googleCredentialsMockedStatic
+ .when(GoogleCredentials::getApplicationDefault)
+ .thenReturn(mockedGoogleCredentials);
+
+ OpenTelemetrySdk sdk = buildOpenTelemetrySdkWithExporter(mockOtlpGrpcMetricExporter);
+ generateTestMetric(sdk);
+ CompletableResultCode code = sdk.shutdown();
+ CompletableResultCode joinResult = code.join(10, TimeUnit.SECONDS);
+ assertTrue(joinResult.isSuccess());
+
+ Mockito.verify(mockOtlpGrpcMetricExporter, Mockito.times(1)).toBuilder();
+ Mockito.verify(spyOtlpGrpcMetricExporterBuilder, Mockito.times(1))
+ .setHeaders(metricHeaderSupplierCaptor.capture());
+ assertEquals(2, metricHeaderSupplierCaptor.getValue().get().size());
+ assertThat(authHeadersQuotaProjectIsPresent(metricHeaderSupplierCaptor.getValue().get()))
+ .isTrue();
+
+ Mockito.verify(mockOtlpGrpcMetricExporter, Mockito.atLeast(1))
+ .export(Mockito.anyCollection());
+
+ assertThat(exportedMetrics)
+ .hasSizeGreaterThan(0)
+ .allSatisfy(
+ metricData -> {
+ assertThat(metricData.getResource().getAttributes().asMap())
+ .containsEntry(
+ AttributeKey.stringKey(GCP_USER_PROJECT_ID_KEY),
+ DUMMY_GCP_RESOURCE_PROJECT_ID)
+ .containsEntry(AttributeKey.stringKey("foo"), "bar");
+ assertThat(metricData.getLongSumData().getPoints())
+ .hasSizeGreaterThan(0)
+ .allSatisfy(
+ longPointData -> {
+ assertThat(longPointData.getAttributes().asMap())
+ .containsKey(AttributeKey.longKey("work_loop"));
+ });
+ });
+ }
+ }
+
@Test
public void testCustomizerFailWithMissingResourceProject() {
+ System.setProperty(
+ ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty(), SIGNAL_TYPE_ALL);
OtlpGrpcSpanExporter mockOtlpGrpcSpanExporter = Mockito.mock(OtlpGrpcSpanExporter.class);
try (MockedStatic googleCredentialsMockedStatic =
Mockito.mockStatic(GoogleCredentials.class)) {
@@ -219,6 +389,8 @@ public void testQuotaProjectBehavior(QuotaProjectIdTestBehavior testCase) throws
// Set resource project system property
System.setProperty(
ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty(), DUMMY_GCP_RESOURCE_PROJECT_ID);
+ System.setProperty(
+ ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty(), SIGNAL_TYPE_ALL);
// Prepare request metadata
AccessToken fakeAccessToken = new AccessToken("fake", Date.from(Instant.now()));
@@ -252,7 +424,7 @@ public void testQuotaProjectBehavior(QuotaProjectIdTestBehavior testCase) throws
OtlpGrpcSpanExporterBuilder spyOtlpGrpcSpanExporterBuilder =
Mockito.spy(OtlpGrpcSpanExporter.builder());
List exportedSpans = new ArrayList<>();
- configureGrpcMockExporters(
+ configureGrpcMockSpanExporter(
mockOtlpGrpcSpanExporter, spyOtlpGrpcSpanExporterBuilder, exportedSpans);
try (MockedStatic googleCredentialsMockedStatic =
@@ -268,10 +440,10 @@ public void testQuotaProjectBehavior(QuotaProjectIdTestBehavior testCase) throws
CompletableResultCode joinResult = code.join(10, TimeUnit.SECONDS);
assertTrue(joinResult.isSuccess());
Mockito.verify(spyOtlpGrpcSpanExporterBuilder, Mockito.times(1))
- .setHeaders(headerSupplierCaptor.capture());
+ .setHeaders(traceHeaderSupplierCaptor.capture());
// assert that the Authorization bearer token header is present
- Map exportHeaders = headerSupplierCaptor.getValue().get();
+ Map exportHeaders = traceHeaderSupplierCaptor.getValue().get();
assertThat(exportHeaders).containsEntry("Authorization", "Bearer fake");
if (testCase.getExpectedQuotaProjectInHeader() == null) {
@@ -285,6 +457,215 @@ public void testQuotaProjectBehavior(QuotaProjectIdTestBehavior testCase) throws
}
}
+ @ParameterizedTest
+ @MethodSource("provideTargetSignalBehaviorTestCases")
+ public void testTargetSignalsBehavior(TargetSignalBehavior testCase) {
+ // Set resource project system property
+ System.setProperty(
+ ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty(), DUMMY_GCP_RESOURCE_PROJECT_ID);
+ // Prepare mocks
+ // Prepare mocked credential
+ prepareMockBehaviorForGoogleCredentials();
+
+ // Prepare mocked span exporter
+ OtlpGrpcSpanExporter mockOtlpGrpcSpanExporter = Mockito.mock(OtlpGrpcSpanExporter.class);
+ OtlpGrpcSpanExporterBuilder spyOtlpGrpcSpanExporterBuilder =
+ Mockito.spy(OtlpGrpcSpanExporter.builder());
+ List exportedSpans = new ArrayList<>();
+ configureGrpcMockSpanExporter(
+ mockOtlpGrpcSpanExporter, spyOtlpGrpcSpanExporterBuilder, exportedSpans);
+ configureGrpcMockSpanExporter(
+ mockOtlpGrpcSpanExporter, spyOtlpGrpcSpanExporterBuilder, exportedSpans);
+
+ // Prepare mocked metrics exporter
+ OtlpGrpcMetricExporter mockOtlpGrpcMetricExporter = Mockito.mock(OtlpGrpcMetricExporter.class);
+ OtlpGrpcMetricExporterBuilder otlpMetricExporterBuilder = OtlpGrpcMetricExporter.builder();
+ OtlpGrpcMetricExporterBuilder spyOtlpGrpcMetricExporterBuilder =
+ Mockito.spy(otlpMetricExporterBuilder);
+ List exportedMetrics = new ArrayList<>();
+ configureGrpcMockMetricExporter(
+ mockOtlpGrpcMetricExporter, spyOtlpGrpcMetricExporterBuilder, exportedMetrics);
+
+ // configure environment according to test case
+ System.setProperty(
+ ConfigurableOption.GOOGLE_OTEL_AUTH_TARGET_SIGNALS.getSystemProperty(),
+ testCase.getConfiguredTargetSignals());
+
+ // Build Autoconfigured OpenTelemetry SDK using the mocks and send signals
+ try (MockedStatic googleCredentialsMockedStatic =
+ Mockito.mockStatic(GoogleCredentials.class)) {
+ googleCredentialsMockedStatic
+ .when(GoogleCredentials::getApplicationDefault)
+ .thenReturn(mockedGoogleCredentials);
+
+ OpenTelemetrySdk sdk =
+ buildOpenTelemetrySdkWithExporter(
+ mockOtlpGrpcSpanExporter,
+ mockOtlpGrpcMetricExporter,
+ testCase.getUserSpecifiedOtelProperties());
+ generateTestMetric(sdk);
+ generateTestSpan(sdk);
+ CompletableResultCode code = sdk.shutdown();
+ CompletableResultCode joinResult = code.join(10, TimeUnit.SECONDS);
+ assertTrue(joinResult.isSuccess());
+
+ // Check Traces modification conditions
+ if (testCase.getExpectedIsTraceSignalModified()) {
+ // If traces signal is expected to be modified, auth headers must be present
+ Mockito.verify(spyOtlpGrpcSpanExporterBuilder, Mockito.times(1))
+ .setHeaders(traceHeaderSupplierCaptor.capture());
+ assertEquals(2, traceHeaderSupplierCaptor.getValue().get().size());
+ assertThat(authHeadersQuotaProjectIsPresent(traceHeaderSupplierCaptor.getValue().get()))
+ .isTrue();
+ } else {
+ // If traces signals is not expected to be modified then no interaction with the builder
+ // should be made
+ Mockito.verifyNoInteractions(spyOtlpGrpcSpanExporterBuilder);
+ }
+
+ // Check Metric modification conditions
+ if (testCase.getExpectedIsMetricsSignalModified()) {
+ // If metrics signal is expected to be modified, auth headers must be present
+ Mockito.verify(spyOtlpGrpcMetricExporterBuilder, Mockito.times(1))
+ .setHeaders(metricHeaderSupplierCaptor.capture());
+ assertEquals(2, metricHeaderSupplierCaptor.getValue().get().size());
+ assertThat(authHeadersQuotaProjectIsPresent(metricHeaderSupplierCaptor.getValue().get()))
+ .isTrue();
+ } else {
+ // If metrics signals is not expected to be modified then no interaction with the builder
+ // should be made
+ Mockito.verifyNoInteractions(spyOtlpGrpcMetricExporterBuilder);
+ }
+ }
+ }
+
+ /** Test cases specifying expected behavior for GOOGLE_OTEL_AUTH_TARGET_SIGNALS */
+ private static Stream provideTargetSignalBehaviorTestCases() {
+ return Stream.of(
+ Arguments.of(
+ TargetSignalBehavior.builder()
+ .setConfiguredTargetSignals("traces")
+ .setUserSpecifiedOtelProperties(defaultOtelPropertiesSpanExporter)
+ .setExpectedIsMetricsSignalModified(false)
+ .setExpectedIsTraceSignalModified(true)
+ .build()),
+ Arguments.of(
+ TargetSignalBehavior.builder()
+ .setConfiguredTargetSignals("metrics")
+ .setUserSpecifiedOtelProperties(defaultOtelPropertiesMetricExporter)
+ .setExpectedIsMetricsSignalModified(true)
+ .setExpectedIsTraceSignalModified(false)
+ .build()),
+ Arguments.of(
+ TargetSignalBehavior.builder()
+ .setConfiguredTargetSignals("all")
+ .setUserSpecifiedOtelProperties(
+ ImmutableMap.of(
+ "otel.exporter.otlp.metrics.endpoint",
+ "https://localhost:4813/v1/metrics",
+ "otel.exporter.otlp.traces.endpoint",
+ "https://localhost:4813/v1/traces",
+ "otel.traces.exporter",
+ "otlp",
+ "otel.metrics.exporter",
+ "otlp",
+ "otel.logs.exporter",
+ "none"))
+ .setExpectedIsMetricsSignalModified(true)
+ .setExpectedIsTraceSignalModified(true)
+ .build()),
+ Arguments.of(
+ TargetSignalBehavior.builder()
+ .setConfiguredTargetSignals("metrics, traces")
+ .setUserSpecifiedOtelProperties(
+ ImmutableMap.of(
+ "otel.exporter.otlp.metrics.endpoint",
+ "https://localhost:4813/v1/metrics",
+ "otel.exporter.otlp.traces.endpoint",
+ "https://localhost:4813/v1/traces",
+ "otel.traces.exporter",
+ "otlp",
+ "otel.metrics.exporter",
+ "otlp",
+ "otel.logs.exporter",
+ "none"))
+ .setExpectedIsMetricsSignalModified(true)
+ .setExpectedIsTraceSignalModified(true)
+ .build()),
+ Arguments.of(
+ TargetSignalBehavior.builder()
+ .setConfiguredTargetSignals("")
+ .setUserSpecifiedOtelProperties(
+ ImmutableMap.of(
+ "otel.exporter.otlp.metrics.endpoint",
+ "https://localhost:4813/v1/metrics",
+ "otel.exporter.otlp.traces.endpoint",
+ "https://localhost:4813/v1/traces",
+ "otel.traces.exporter",
+ "otlp",
+ "otel.metrics.exporter",
+ "otlp",
+ "otel.logs.exporter",
+ "none"))
+ .setExpectedIsMetricsSignalModified(true)
+ .setExpectedIsTraceSignalModified(true)
+ .build()),
+ Arguments.of(
+ TargetSignalBehavior.builder()
+ .setConfiguredTargetSignals("all")
+ .setUserSpecifiedOtelProperties(
+ ImmutableMap.of(
+ "otel.exporter.otlp.metrics.endpoint",
+ "https://localhost:4813/v1/metrics",
+ "otel.exporter.otlp.traces.endpoint",
+ "https://localhost:4813/v1/traces",
+ "otel.traces.exporter",
+ "none",
+ "otel.metrics.exporter",
+ "none",
+ "otel.logs.exporter",
+ "none"))
+ .setExpectedIsMetricsSignalModified(false)
+ .setExpectedIsTraceSignalModified(false)
+ .build()),
+ Arguments.of(
+ TargetSignalBehavior.builder()
+ .setConfiguredTargetSignals("metric, trace")
+ .setUserSpecifiedOtelProperties(
+ ImmutableMap.of(
+ "otel.exporter.otlp.metrics.endpoint",
+ "https://localhost:4813/v1/metrics",
+ "otel.exporter.otlp.traces.endpoint",
+ "https://localhost:4813/v1/traces",
+ "otel.traces.exporter",
+ "otlp",
+ "otel.metrics.exporter",
+ "otlp",
+ "otel.logs.exporter",
+ "none"))
+ .setExpectedIsMetricsSignalModified(false)
+ .setExpectedIsTraceSignalModified(false)
+ .build()),
+ Arguments.of(
+ TargetSignalBehavior.builder()
+ .setConfiguredTargetSignals("metrics, trace")
+ .setUserSpecifiedOtelProperties(
+ ImmutableMap.of(
+ "otel.exporter.otlp.metrics.endpoint",
+ "https://localhost:4813/v1/metrics",
+ "otel.exporter.otlp.traces.endpoint",
+ "https://localhost:4813/v1/traces",
+ "otel.traces.exporter",
+ "otlp",
+ "otel.metrics.exporter",
+ "otlp",
+ "otel.logs.exporter",
+ "none"))
+ .setExpectedIsMetricsSignalModified(true)
+ .setExpectedIsTraceSignalModified(false)
+ .build()));
+ }
+
/**
* Test cases specifying expected value for the user quota project header given the user input and
* the current credentials state.
@@ -356,16 +737,20 @@ private static Stream provideQuotaBehaviorTestCases() {
.build()));
}
- // Configure necessary behavior on the Grpc mock exporters to work
- // TODO: Potential improvement - make this work for Http exporter as well.
- private static void configureGrpcMockExporters(
+ // Configure necessary behavior on the gRPC mock span exporters to work.
+ // Mockito.lenient is used here because this method is used with parameterized tests where based
+ // on certain inputs, certain stubbings may not be required.
+ private static void configureGrpcMockSpanExporter(
OtlpGrpcSpanExporter mockGrpcExporter,
OtlpGrpcSpanExporterBuilder spyGrpcExporterBuilder,
List exportedSpanContainer) {
- Mockito.when(spyGrpcExporterBuilder.build()).thenReturn(mockGrpcExporter);
- Mockito.when(mockGrpcExporter.shutdown()).thenReturn(CompletableResultCode.ofSuccess());
- Mockito.when(mockGrpcExporter.toBuilder()).thenReturn(spyGrpcExporterBuilder);
- Mockito.when(mockGrpcExporter.export(Mockito.anyCollection()))
+ Mockito.lenient().when(spyGrpcExporterBuilder.build()).thenReturn(mockGrpcExporter);
+ Mockito.lenient()
+ .when(mockGrpcExporter.shutdown())
+ .thenReturn(CompletableResultCode.ofSuccess());
+ Mockito.lenient().when(mockGrpcExporter.toBuilder()).thenReturn(spyGrpcExporterBuilder);
+ Mockito.lenient()
+ .when(mockGrpcExporter.export(Mockito.anyCollection()))
.thenAnswer(
invocationOnMock -> {
exportedSpanContainer.addAll(invocationOnMock.getArgument(0));
@@ -373,6 +758,88 @@ private static void configureGrpcMockExporters(
});
}
+ // Configure necessary behavior on the http mock metric exporters to work.
+ private static void configureHttpMockMetricExporter(
+ OtlpHttpMetricExporter mockOtlpHttpMetricExporter,
+ OtlpHttpMetricExporterBuilder spyOtlpHttpMetricExporterBuilder,
+ List exportedMetricContainer) {
+ Mockito.when(spyOtlpHttpMetricExporterBuilder.build()).thenReturn(mockOtlpHttpMetricExporter);
+ Mockito.when(mockOtlpHttpMetricExporter.shutdown())
+ .thenReturn(CompletableResultCode.ofSuccess());
+ Mockito.when(mockOtlpHttpMetricExporter.toBuilder())
+ .thenReturn(spyOtlpHttpMetricExporterBuilder);
+ Mockito.when(mockOtlpHttpMetricExporter.export(Mockito.anyCollection()))
+ .thenAnswer(
+ invocationOnMock -> {
+ exportedMetricContainer.addAll(invocationOnMock.getArgument(0));
+ return CompletableResultCode.ofSuccess();
+ });
+ // mock the get default aggregation and aggregation temporality - they're required for valid
+ // metric collection.
+ Mockito.when(mockOtlpHttpMetricExporter.getDefaultAggregation(Mockito.any()))
+ .thenAnswer(
+ (Answer)
+ invocationOnMock -> {
+ InstrumentType instrumentType = invocationOnMock.getArgument(0);
+ return OtlpHttpMetricExporter.getDefault().getDefaultAggregation(instrumentType);
+ });
+ Mockito.when(mockOtlpHttpMetricExporter.getAggregationTemporality(Mockito.any()))
+ .thenAnswer(
+ (Answer)
+ invocationOnMock -> {
+ InstrumentType instrumentType = invocationOnMock.getArgument(0);
+ return OtlpHttpMetricExporter.getDefault()
+ .getAggregationTemporality(instrumentType);
+ });
+ }
+
+ // Configure necessary behavior on the gRPC mock metrics exporters to work.
+ // Mockito.lenient is used here because this method is used with parameterized tests where based
+ // on certain inputs, certain stubbings may not be required.
+ private static void configureGrpcMockMetricExporter(
+ OtlpGrpcMetricExporter mockOtlpGrpcMetricExporter,
+ OtlpGrpcMetricExporterBuilder spyOtlpGrpcMetricExporterBuilder,
+ List exportedMetricContainer) {
+ Mockito.lenient()
+ .when(spyOtlpGrpcMetricExporterBuilder.build())
+ .thenReturn(mockOtlpGrpcMetricExporter);
+ Mockito.lenient()
+ .when(mockOtlpGrpcMetricExporter.shutdown())
+ .thenReturn(CompletableResultCode.ofSuccess());
+ Mockito.lenient()
+ .when(mockOtlpGrpcMetricExporter.toBuilder())
+ .thenReturn(spyOtlpGrpcMetricExporterBuilder);
+ Mockito.lenient()
+ .when(mockOtlpGrpcMetricExporter.export(Mockito.anyCollection()))
+ .thenAnswer(
+ invocationOnMock -> {
+ exportedMetricContainer.addAll(invocationOnMock.getArgument(0));
+ return CompletableResultCode.ofSuccess();
+ });
+ // mock the get default aggregation and aggregation temporality - they're required for valid
+ // metric collection.
+ Mockito.lenient()
+ .when(mockOtlpGrpcMetricExporter.getDefaultAggregation(Mockito.any()))
+ .thenAnswer(
+ (Answer)
+ invocationOnMock -> {
+ InstrumentType instrumentType = invocationOnMock.getArgument(0);
+ return OtlpGrpcMetricExporter.getDefault().getDefaultAggregation(instrumentType);
+ });
+ Mockito.lenient()
+ .when(mockOtlpGrpcMetricExporter.getAggregationTemporality(Mockito.any()))
+ .thenAnswer(
+ (Answer)
+ invocationOnMock -> {
+ InstrumentType instrumentType = invocationOnMock.getArgument(0);
+ return OtlpGrpcMetricExporter.getDefault()
+ .getAggregationTemporality(instrumentType);
+ });
+ Mockito.lenient()
+ .when(mockOtlpGrpcMetricExporter.getMemoryMode())
+ .thenReturn(MemoryMode.IMMUTABLE_DATA);
+ }
+
@AutoValue
abstract static class QuotaProjectIdTestBehavior {
// A null user specified quota represents the use case where user omits specifying quota
@@ -409,11 +876,48 @@ abstract static class Builder {
}
}
+ @AutoValue
+ abstract static class TargetSignalBehavior {
+ @Nonnull
+ abstract String getConfiguredTargetSignals();
+
+ @Nonnull
+ abstract ImmutableMap getUserSpecifiedOtelProperties();
+
+ abstract boolean getExpectedIsTraceSignalModified();
+
+ abstract boolean getExpectedIsMetricsSignalModified();
+
+ static Builder builder() {
+ return new AutoValue_GcpAuthAutoConfigurationCustomizerProviderTest_TargetSignalBehavior
+ .Builder();
+ }
+
+ @AutoValue.Builder
+ abstract static class Builder {
+ abstract Builder setConfiguredTargetSignals(String targetSignals);
+
+ abstract Builder setUserSpecifiedOtelProperties(Map oTelProperties);
+
+ // Set whether the combination of specified OTel properties and configured target signals
+ // should lead to modification of the OTLP trace exporters.
+ abstract Builder setExpectedIsTraceSignalModified(boolean expectedModified);
+
+ // Set whether the combination of specified OTel properties and configured target signals
+ // should lead to modification of the OTLP metrics exporters.
+ abstract Builder setExpectedIsMetricsSignalModified(boolean expectedModified);
+
+ abstract TargetSignalBehavior build();
+ }
+ }
+
+ // Mockito.lenient is used here because this method is used with parameterized tests where based
@SuppressWarnings("CannotMockMethod")
private void prepareMockBehaviorForGoogleCredentials() {
AccessToken fakeAccessToken = new AccessToken("fake", Date.from(Instant.now()));
try {
- Mockito.when(mockedGoogleCredentials.getRequestMetadata())
+ Mockito.lenient()
+ .when(mockedGoogleCredentials.getRequestMetadata())
.thenReturn(
ImmutableMap.of(
"Authorization",
@@ -426,10 +930,38 @@ private void prepareMockBehaviorForGoogleCredentials() {
}
private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter(SpanExporter spanExporter) {
+ return buildOpenTelemetrySdkWithExporter(
+ spanExporter, OtlpHttpMetricExporter.getDefault(), defaultOtelPropertiesSpanExporter);
+ }
+
+ @SuppressWarnings("UnusedMethod")
+ private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter(
+ SpanExporter spanExporter, ImmutableMap customOTelProperties) {
+ return buildOpenTelemetrySdkWithExporter(
+ spanExporter, OtlpHttpMetricExporter.getDefault(), customOTelProperties);
+ }
+
+ @SuppressWarnings("UnusedMethod")
+ private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter(MetricExporter metricExporter) {
+ return buildOpenTelemetrySdkWithExporter(
+ OtlpHttpSpanExporter.getDefault(), metricExporter, defaultOtelPropertiesMetricExporter);
+ }
+
+ @SuppressWarnings("UnusedMethod")
+ private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter(
+ MetricExporter metricExporter, ImmutableMap customOtelProperties) {
+ return buildOpenTelemetrySdkWithExporter(
+ OtlpHttpSpanExporter.getDefault(), metricExporter, customOtelProperties);
+ }
+
+ private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter(
+ SpanExporter spanExporter,
+ MetricExporter metricExporter,
+ ImmutableMap customOtelProperties) {
SpiHelper spiHelper =
SpiHelper.create(GcpAuthAutoConfigurationCustomizerProviderTest.class.getClassLoader());
AutoConfiguredOpenTelemetrySdkBuilder builder =
- AutoConfiguredOpenTelemetrySdk.builder().addPropertiesSupplier(() -> otelProperties);
+ AutoConfiguredOpenTelemetrySdk.builder().addPropertiesSupplier(() -> customOtelProperties);
AutoConfigureUtil.setComponentLoader(
builder,
new ComponentLoader() {
@@ -451,6 +983,21 @@ public String getName() {
}
});
}
+ if (spiClass == ConfigurableMetricExporterProvider.class) {
+ return Collections.singletonList(
+ (T)
+ new ConfigurableMetricExporterProvider() {
+ @Override
+ public MetricExporter createExporter(ConfigProperties configProperties) {
+ return metricExporter;
+ }
+
+ @Override
+ public String getName() {
+ return "otlp";
+ }
+ });
+ }
return spiHelper.load(spiClass);
}
});
@@ -476,6 +1023,19 @@ private static void generateTestSpan(OpenTelemetrySdk openTelemetrySdk) {
}
}
+ private static void generateTestMetric(OpenTelemetrySdk openTelemetrySdk) {
+ LongCounter longCounter =
+ openTelemetrySdk
+ .getMeter("test")
+ .counterBuilder("sample")
+ .setDescription("sample counter")
+ .setUnit("1")
+ .build();
+ long workOutput = busyloop();
+ long randomValue = TEST_RANDOM.nextInt(1000);
+ longCounter.add(randomValue, Attributes.of(AttributeKey.longKey("work_loop"), workOutput));
+ }
+
// loop to simulate work done
private static long busyloop() {
Instant start = Instant.now();