From 95e7a6842a088d7e6b3679a48e9fa9d2d94979dd Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 30 Nov 2023 15:53:41 -0800 Subject: [PATCH 1/5] use GlobalAttributeSpanAppender via upstream mechanism --- .../main/java/com/splunk/rum/SplunkRum.java | 8 ++-- .../internal/GlobalAttributesSupplier.java | 38 +++++++++++++++++++ .../java/com/splunk/rum/SplunkRumTest.java | 7 +++- .../GlobalAttributesSupplierTest.java | 27 +++++++++++++ 4 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 splunk-otel-android/src/main/java/com/splunk/rum/internal/GlobalAttributesSupplier.java create mode 100644 splunk-otel-android/src/test/java/com/splunk/rum/internal/GlobalAttributesSupplierTest.java diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkRum.java b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkRum.java index d6861718..e90e8f8e 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkRum.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkRum.java @@ -26,7 +26,9 @@ import android.util.Log; import android.webkit.WebView; import androidx.annotation.Nullable; -import io.opentelemetry.android.GlobalAttributesSpanAppender; + +import com.splunk.rum.internal.GlobalAttributesSupplier; + import io.opentelemetry.android.OpenTelemetryRum; import io.opentelemetry.android.instrumentation.network.CurrentNetworkProvider; import io.opentelemetry.android.instrumentation.startup.AppStartupTimer; @@ -73,14 +75,14 @@ public class SplunkRum { @Nullable private static SplunkRum INSTANCE; private final OpenTelemetryRum openTelemetryRum; - private final GlobalAttributesSpanAppender globalAttributes; + private final GlobalAttributesSupplier globalAttributes; static { Handler handler = new Handler(Looper.getMainLooper()); startupTimer.detectBackgroundStart(handler); } - SplunkRum(OpenTelemetryRum openTelemetryRum, GlobalAttributesSpanAppender globalAttributes) { + SplunkRum(OpenTelemetryRum openTelemetryRum, GlobalAttributesSupplier globalAttributes) { this.openTelemetryRum = openTelemetryRum; this.globalAttributes = globalAttributes; } diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/internal/GlobalAttributesSupplier.java b/splunk-otel-android/src/main/java/com/splunk/rum/internal/GlobalAttributesSupplier.java new file mode 100644 index 00000000..5087a779 --- /dev/null +++ b/splunk-otel-android/src/main/java/com/splunk/rum/internal/GlobalAttributesSupplier.java @@ -0,0 +1,38 @@ +package com.splunk.rum.internal; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.AttributesBuilder; + +/** + * Class to hold and update the set of global attributes that are appended to each + * span. This is used as the supplier to the GlobalAttributesSpanAppender. We need this + * because SplunkRum exposes a topmost update() method, and we can't break that contract, + * and there's no way to get a reference to the GlobalAttributesSpanAppender created by OtelRum. + * + *

+ * When global attributes are more fleshed out in upstream, this will hopefully improve or go away. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public class GlobalAttributesSupplier implements Supplier { + private Attributes attributes; + + public GlobalAttributesSupplier(Attributes globalAttributes) { + this.attributes = globalAttributes; + } + + @Override + public Attributes get() { + return attributes; + } + + public void update(Consumer attributesUpdater) { + AttributesBuilder builder = attributes.toBuilder(); + attributesUpdater.accept(builder); + attributes = builder.build(); + } +} diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/SplunkRumTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/SplunkRumTest.java index f43812bb..26707286 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/SplunkRumTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/SplunkRumTest.java @@ -36,6 +36,9 @@ import android.content.Context; import android.location.Location; import android.webkit.WebView; + +import com.splunk.rum.internal.GlobalAttributesSupplier; + import io.opentelemetry.android.GlobalAttributesSpanAppender; import io.opentelemetry.android.OpenTelemetryRum; import io.opentelemetry.android.instrumentation.network.CurrentNetworkProvider; @@ -69,7 +72,7 @@ public class SplunkRumTest { private Tracer tracer; @Mock private OpenTelemetryRum openTelemetryRum; - @Mock private GlobalAttributesSpanAppender globalAttributes; + @Mock private GlobalAttributesSupplier globalAttributes; @BeforeEach public void setup() { @@ -255,7 +258,7 @@ void integrateWithBrowserRum() { @Test void updateLocation() { AtomicReference updatedAttributes = new AtomicReference<>(); - GlobalAttributesSpanAppender globalAttributes = mock(GlobalAttributesSpanAppender.class); + GlobalAttributesSupplier globalAttributes = mock(GlobalAttributesSupplier.class); doAnswer( invocation -> { Consumer updater = invocation.getArgument(0); diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/internal/GlobalAttributesSupplierTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/internal/GlobalAttributesSupplierTest.java new file mode 100644 index 00000000..e9bc9251 --- /dev/null +++ b/splunk-otel-android/src/test/java/com/splunk/rum/internal/GlobalAttributesSupplierTest.java @@ -0,0 +1,27 @@ +package com.splunk.rum.internal; + +import static org.junit.jupiter.api.Assertions.*; + +import static io.opentelemetry.api.common.AttributeKey.stringKey; + +import org.junit.jupiter.api.Test; + +import io.opentelemetry.api.common.Attributes; + +class GlobalAttributesSupplierTest { + + @Test + void update(){ + Attributes initial = Attributes.of(stringKey("foo"), "bar", stringKey("bar"), "baz"); + GlobalAttributesSupplier testClass = new GlobalAttributesSupplier(initial); + testClass.update(builder -> { + builder.put("jimbo", "hutch"); + builder.remove(stringKey("bar")); + }); + Attributes result = testClass.get(); + assertEquals("bar", result.get(stringKey("foo"))); + assertEquals("hutch", result.get(stringKey("jimbo"))); + assertNull(result.get(stringKey("bar"))); + } + +} \ No newline at end of file From e4e1a3e6d8c7e69401bc8ffbf9af9445244ad8e5 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 30 Nov 2023 17:08:58 -0800 Subject: [PATCH 2/5] let upstream handle global attributes --- .../java/com/splunk/rum/RumInitializer.java | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/RumInitializer.java b/splunk-otel-android/src/main/java/com/splunk/rum/RumInitializer.java index 3da85465..cbcfa7aa 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/RumInitializer.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/RumInitializer.java @@ -22,20 +22,28 @@ import static com.splunk.rum.SplunkRum.COMPONENT_KEY; import static com.splunk.rum.SplunkRum.COMPONENT_UI; import static com.splunk.rum.SplunkRum.RUM_TRACER_NAME; +import static java.util.Objects.requireNonNull; import static io.opentelemetry.android.RumConstants.APP_START_SPAN_NAME; import static io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor.constant; import static io.opentelemetry.semconv.ResourceAttributes.DEPLOYMENT_ENVIRONMENT; -import static java.util.Objects.requireNonNull; import android.app.Application; import android.os.Looper; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.splunk.rum.internal.UInt32QuadXorTraceIdRatioSampler; -import io.opentelemetry.android.GlobalAttributesSpanAppender; +import com.splunk.rum.internal.GlobalAttributesSupplier; +import java.time.Duration; +import java.util.Collection; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.logging.Level; import io.opentelemetry.android.OpenTelemetryRum; import io.opentelemetry.android.OpenTelemetryRumBuilder; import io.opentelemetry.android.RuntimeDetailsExtractor; +import io.opentelemetry.android.config.OtelRumConfig; import io.opentelemetry.android.instrumentation.activity.VisibleScreenTracker; import io.opentelemetry.android.instrumentation.anr.AnrDetector; import io.opentelemetry.android.instrumentation.crash.CrashReporter; @@ -58,12 +66,6 @@ import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; import io.opentelemetry.sdk.trace.export.SpanExporter; import io.opentelemetry.sdk.trace.samplers.Sampler; -import java.time.Duration; -import java.util.Collection; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.logging.Level; import zipkin2.reporter.Sender; import zipkin2.reporter.okhttp3.OkHttpSender; @@ -92,7 +94,12 @@ SplunkRum initialize( VisibleScreenTracker visibleScreenTracker = new VisibleScreenTracker(); initializationEvents.begin(); - OpenTelemetryRumBuilder otelRumBuilder = OpenTelemetryRum.builder(application); + + OtelRumConfig config = new OtelRumConfig(); + GlobalAttributesSupplier globalAttributeSupplier = new GlobalAttributesSupplier(builder.globalAttributes); + config.setGlobalAttributes(globalAttributeSupplier); + + OpenTelemetryRumBuilder otelRumBuilder = OpenTelemetryRum.builder(application, config); otelRumBuilder.mergeResource(createSplunkResource()); initializationEvents.emit("resourceInitialized"); @@ -104,14 +111,6 @@ SplunkRum initialize( // TODO: How truly important is the order of these span processors? The location of event // generation should probably not be altered... - GlobalAttributesSpanAppender globalAttributesSpanAppender = - GlobalAttributesSpanAppender.create(builder.globalAttributes); - - // Add span processor that appends global attributes. - otelRumBuilder.addTracerProviderCustomizer( - (tracerProviderBuilder, app) -> - tracerProviderBuilder.addSpanProcessor(globalAttributesSpanAppender)); - // Add span processor that appends network attributes. otelRumBuilder.addTracerProviderCustomizer( (tracerProviderBuilder, app) -> { @@ -225,7 +224,7 @@ SplunkRum initialize( builder.getConfigFlags(), openTelemetryRum.getOpenTelemetry().getTracer(RUM_TRACER_NAME)); - return new SplunkRum(openTelemetryRum, globalAttributesSpanAppender); + return new SplunkRum(openTelemetryRum, globalAttributeSupplier); } @NonNull From 6eb03304e6f19206c41911cae6f3a2c0bccefa17 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 1 Dec 2023 14:34:08 -0800 Subject: [PATCH 3/5] let upstream handle screen attributes --- .../src/main/java/com/splunk/rum/RumInitializer.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/RumInitializer.java b/splunk-otel-android/src/main/java/com/splunk/rum/RumInitializer.java index cbcfa7aa..81bc9d38 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/RumInitializer.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/RumInitializer.java @@ -119,15 +119,6 @@ SplunkRum initialize( return tracerProviderBuilder.addSpanProcessor(networkAttributesSpanAppender); }); - // Add span processor that appends screen attributes and generate init event. - otelRumBuilder.addTracerProviderCustomizer( - (tracerProviderBuilder, app) -> { - ScreenAttributesAppender screenAttributesAppender = - new ScreenAttributesAppender(visibleScreenTracker); - initializationEvents.emit("attributeAppenderInitialized"); - return tracerProviderBuilder.addSpanProcessor(screenAttributesAppender); - }); - // Add batch span processor otelRumBuilder.addTracerProviderCustomizer( (tracerProviderBuilder, app) -> { From 598efc9827f34693751f7d2ca9d3b8b70ad6cc22 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Mon, 4 Dec 2023 09:59:07 -0800 Subject: [PATCH 4/5] spotless --- .../java/com/splunk/rum/RumInitializer.java | 6 +-- .../main/java/com/splunk/rum/SplunkRum.java | 2 - .../internal/GlobalAttributesSupplier.java | 37 +++++++++++++------ .../java/com/splunk/rum/SplunkRumTest.java | 3 -- .../GlobalAttributesSupplierTest.java | 36 ++++++++++++------ 5 files changed, 54 insertions(+), 30 deletions(-) diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/RumInitializer.java b/splunk-otel-android/src/main/java/com/splunk/rum/RumInitializer.java index 81bc9d38..2215df8b 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/RumInitializer.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/RumInitializer.java @@ -22,14 +22,13 @@ import static com.splunk.rum.SplunkRum.COMPONENT_KEY; import static com.splunk.rum.SplunkRum.COMPONENT_UI; import static com.splunk.rum.SplunkRum.RUM_TRACER_NAME; -import static java.util.Objects.requireNonNull; import static io.opentelemetry.android.RumConstants.APP_START_SPAN_NAME; import static io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor.constant; import static io.opentelemetry.semconv.ResourceAttributes.DEPLOYMENT_ENVIRONMENT; +import static java.util.Objects.requireNonNull; import android.app.Application; import android.os.Looper; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.splunk.rum.internal.UInt32QuadXorTraceIdRatioSampler; @@ -96,7 +95,8 @@ SplunkRum initialize( initializationEvents.begin(); OtelRumConfig config = new OtelRumConfig(); - GlobalAttributesSupplier globalAttributeSupplier = new GlobalAttributesSupplier(builder.globalAttributes); + GlobalAttributesSupplier globalAttributeSupplier = + new GlobalAttributesSupplier(builder.globalAttributes); config.setGlobalAttributes(globalAttributeSupplier); OpenTelemetryRumBuilder otelRumBuilder = OpenTelemetryRum.builder(application, config); diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkRum.java b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkRum.java index e90e8f8e..5a9922f7 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkRum.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkRum.java @@ -26,9 +26,7 @@ import android.util.Log; import android.webkit.WebView; import androidx.annotation.Nullable; - import com.splunk.rum.internal.GlobalAttributesSupplier; - import io.opentelemetry.android.OpenTelemetryRum; import io.opentelemetry.android.instrumentation.network.CurrentNetworkProvider; import io.opentelemetry.android.instrumentation.startup.AppStartupTimer; diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/internal/GlobalAttributesSupplier.java b/splunk-otel-android/src/main/java/com/splunk/rum/internal/GlobalAttributesSupplier.java index 5087a779..4a4db6e4 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/internal/GlobalAttributesSupplier.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/internal/GlobalAttributesSupplier.java @@ -1,22 +1,37 @@ -package com.splunk.rum.internal; +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -import java.util.function.Consumer; -import java.util.function.Supplier; +package com.splunk.rum.internal; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.AttributesBuilder; +import java.util.function.Consumer; +import java.util.function.Supplier; /** - * Class to hold and update the set of global attributes that are appended to each - * span. This is used as the supplier to the GlobalAttributesSpanAppender. We need this - * because SplunkRum exposes a topmost update() method, and we can't break that contract, - * and there's no way to get a reference to the GlobalAttributesSpanAppender created by OtelRum. + * Class to hold and update the set of global attributes that are appended to each span. This is + * used as the supplier to the GlobalAttributesSpanAppender. We need this because SplunkRum exposes + * a topmost update() method, and we can't break that contract, and there's no way to get a + * reference to the GlobalAttributesSpanAppender created by OtelRum. * - *

- * When global attributes are more fleshed out in upstream, this will hopefully improve or go away. + *

When global attributes are more fleshed out in upstream, this will hopefully improve or go + * away. * - *

This class is internal and is hence not for public use. Its APIs are unstable and can change - * at any time. + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. */ public class GlobalAttributesSupplier implements Supplier { private Attributes attributes; diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/SplunkRumTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/SplunkRumTest.java index 26707286..b80abf2c 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/SplunkRumTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/SplunkRumTest.java @@ -36,10 +36,7 @@ import android.content.Context; import android.location.Location; import android.webkit.WebView; - import com.splunk.rum.internal.GlobalAttributesSupplier; - -import io.opentelemetry.android.GlobalAttributesSpanAppender; import io.opentelemetry.android.OpenTelemetryRum; import io.opentelemetry.android.instrumentation.network.CurrentNetworkProvider; import io.opentelemetry.api.common.Attributes; diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/internal/GlobalAttributesSupplierTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/internal/GlobalAttributesSupplierTest.java index e9bc9251..1ab811df 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/internal/GlobalAttributesSupplierTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/internal/GlobalAttributesSupplierTest.java @@ -1,27 +1,41 @@ -package com.splunk.rum.internal; +/* + * Copyright Splunk Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -import static org.junit.jupiter.api.Assertions.*; +package com.splunk.rum.internal; import static io.opentelemetry.api.common.AttributeKey.stringKey; - -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import io.opentelemetry.api.common.Attributes; +import org.junit.jupiter.api.Test; class GlobalAttributesSupplierTest { @Test - void update(){ + void update() { Attributes initial = Attributes.of(stringKey("foo"), "bar", stringKey("bar"), "baz"); GlobalAttributesSupplier testClass = new GlobalAttributesSupplier(initial); - testClass.update(builder -> { - builder.put("jimbo", "hutch"); - builder.remove(stringKey("bar")); - }); + testClass.update( + builder -> { + builder.put("jimbo", "hutch"); + builder.remove(stringKey("bar")); + }); Attributes result = testClass.get(); assertEquals("bar", result.get(stringKey("foo"))); assertEquals("hutch", result.get(stringKey("jimbo"))); assertNull(result.get(stringKey("bar"))); } - -} \ No newline at end of file +} From 0e66cab1c6f6024ac937ec1efcd543fea71f1030 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 7 Dec 2023 15:55:57 -0800 Subject: [PATCH 5/5] spotless --- .../main/java/com/splunk/rum/RumInitializer.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/RumInitializer.java b/splunk-otel-android/src/main/java/com/splunk/rum/RumInitializer.java index 2215df8b..b8e05336 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/RumInitializer.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/RumInitializer.java @@ -31,14 +31,8 @@ import android.os.Looper; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.splunk.rum.internal.UInt32QuadXorTraceIdRatioSampler; import com.splunk.rum.internal.GlobalAttributesSupplier; -import java.time.Duration; -import java.util.Collection; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.logging.Level; +import com.splunk.rum.internal.UInt32QuadXorTraceIdRatioSampler; import io.opentelemetry.android.OpenTelemetryRum; import io.opentelemetry.android.OpenTelemetryRumBuilder; import io.opentelemetry.android.RuntimeDetailsExtractor; @@ -65,6 +59,12 @@ import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; import io.opentelemetry.sdk.trace.export.SpanExporter; import io.opentelemetry.sdk.trace.samplers.Sampler; +import java.time.Duration; +import java.util.Collection; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.logging.Level; import zipkin2.reporter.Sender; import zipkin2.reporter.okhttp3.OkHttpSender;