From 167ca112ababd6e58c39fe960702635bc4aff31c Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 10 Apr 2024 14:36:29 -0700 Subject: [PATCH 01/29] placeholder for 2.x work --- .github/renovate.json5 | 2 +- .../java/com/splunk/android/sample/SecondFragment.java | 2 ++ .../com/splunk/rum/VolleyHttpClientAttributesGetter.java | 2 +- .../main/java/com/splunk/rum/VolleyTracingBuilder.java | 8 ++++---- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index bb4ce2e2..49d65cb0 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -9,7 +9,7 @@ "matchPackageNames": [ "io.opentelemetry:opentelemetry-api-incubator", "io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha", - "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-semconv", + "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-incubator", "io.opentelemetry.instrumentation:opentelemetry-okhttp-3.0" ], // Renovate's default behavior is only to update from unstable -> unstable if it's for the diff --git a/sample-app/src/main/java/com/splunk/android/sample/SecondFragment.java b/sample-app/src/main/java/com/splunk/android/sample/SecondFragment.java index d8d1370e..8a60ad1c 100644 --- a/sample-app/src/main/java/com/splunk/android/sample/SecondFragment.java +++ b/sample-app/src/main/java/com/splunk/android/sample/SecondFragment.java @@ -32,6 +32,8 @@ import io.opentelemetry.android.instrumentation.RumScreenName; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.incubator.events.EventLogger; +import io.opentelemetry.api.incubator.events.EventLogger; +import io.opentelemetry.api.incubator.events.EventLoggerProvider; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Scope; diff --git a/splunk-otel-android-volley/src/main/java/com/splunk/rum/VolleyHttpClientAttributesGetter.java b/splunk-otel-android-volley/src/main/java/com/splunk/rum/VolleyHttpClientAttributesGetter.java index 5b5860b4..b5803c10 100644 --- a/splunk-otel-android-volley/src/main/java/com/splunk/rum/VolleyHttpClientAttributesGetter.java +++ b/splunk-otel-android-volley/src/main/java/com/splunk/rum/VolleyHttpClientAttributesGetter.java @@ -23,7 +23,7 @@ import com.android.volley.Header; import com.android.volley.Request; import com.android.volley.toolbox.HttpResponse; -import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesGetter; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesGetter; import java.util.ArrayList; import java.util.List; import java.util.Map; diff --git a/splunk-otel-android-volley/src/main/java/com/splunk/rum/VolleyTracingBuilder.java b/splunk-otel-android-volley/src/main/java/com/splunk/rum/VolleyTracingBuilder.java index 0850c6b4..b270c737 100644 --- a/splunk-otel-android-volley/src/main/java/com/splunk/rum/VolleyTracingBuilder.java +++ b/splunk-otel-android-volley/src/main/java/com/splunk/rum/VolleyTracingBuilder.java @@ -22,10 +22,10 @@ import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; -import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor; -import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractorBuilder; -import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor; -import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractor; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.api.semconv.http.HttpSpanNameExtractor; +import io.opentelemetry.instrumentation.api.semconv.http.HttpSpanStatusExtractor; import java.util.ArrayList; import java.util.List; From 2dd5b25bf16d5b217e5bbf408e107a0b87d071b6 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 10 Apr 2024 15:05:31 -0700 Subject: [PATCH 02/29] start updating semconv --- .../com/splunk/rum/VolleyContentLengthAttributesExtractor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/splunk-otel-android-volley/src/main/java/com/splunk/rum/VolleyContentLengthAttributesExtractor.java b/splunk-otel-android-volley/src/main/java/com/splunk/rum/VolleyContentLengthAttributesExtractor.java index 03d17600..3315703e 100644 --- a/splunk-otel-android-volley/src/main/java/com/splunk/rum/VolleyContentLengthAttributesExtractor.java +++ b/splunk-otel-android-volley/src/main/java/com/splunk/rum/VolleyContentLengthAttributesExtractor.java @@ -24,6 +24,7 @@ import io.opentelemetry.context.Context; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.semconv.SemanticAttributes; +import io.opentelemetry.semconv.incubating.HttpIncubatingAttributes; /** * This class is responsible for extracting the Content-Length header and assigning the value to an @@ -52,7 +53,7 @@ private void onResponse(AttributesBuilder attributes, HttpResponse response) { String contentLength = getHeader(response, "Content-Length"); if (contentLength != null) { attributes.put( - SemanticAttributes.HTTP_RESPONSE_BODY_SIZE, Long.parseLong(contentLength)); + HttpIncubatingAttributes.HTTP_RESPONSE_BODY_SIZE, Long.parseLong(contentLength)); } } } From f6beb2524d75b8088ee46a12f6b1f99df23d907a Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 10 Apr 2024 15:29:32 -0700 Subject: [PATCH 03/29] update semconv --- ...olleyContentLengthAttributesExtractor.java | 4 +- .../rum/TracingHurlStackExceptionTest.java | 13 ++++--- .../com/splunk/rum/TracingHurlStackTest.java | 21 +++++++---- .../java/com/splunk/rum/LogToSpanBridge.java | 10 ++--- .../java/com/splunk/rum/RumInitializer.java | 2 +- .../splunk/rum/SplunkSpanDataModifier.java | 37 +++++++++++-------- .../com/splunk/rum/StandardAttributes.java | 4 +- .../com/splunk/rum/LogToSpanBridgeTest.java | 8 ++-- .../com/splunk/rum/RumInitializerTest.java | 10 ++--- 9 files changed, 60 insertions(+), 49 deletions(-) diff --git a/splunk-otel-android-volley/src/main/java/com/splunk/rum/VolleyContentLengthAttributesExtractor.java b/splunk-otel-android-volley/src/main/java/com/splunk/rum/VolleyContentLengthAttributesExtractor.java index 3315703e..40e6dfb4 100644 --- a/splunk-otel-android-volley/src/main/java/com/splunk/rum/VolleyContentLengthAttributesExtractor.java +++ b/splunk-otel-android-volley/src/main/java/com/splunk/rum/VolleyContentLengthAttributesExtractor.java @@ -23,7 +23,6 @@ import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.context.Context; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; -import io.opentelemetry.semconv.SemanticAttributes; import io.opentelemetry.semconv.incubating.HttpIncubatingAttributes; /** @@ -53,7 +52,8 @@ private void onResponse(AttributesBuilder attributes, HttpResponse response) { String contentLength = getHeader(response, "Content-Length"); if (contentLength != null) { attributes.put( - HttpIncubatingAttributes.HTTP_RESPONSE_BODY_SIZE, Long.parseLong(contentLength)); + HttpIncubatingAttributes.HTTP_RESPONSE_BODY_SIZE, + Long.parseLong(contentLength)); } } } diff --git a/splunk-otel-android-volley/src/test/java/com/splunk/rum/TracingHurlStackExceptionTest.java b/splunk-otel-android-volley/src/test/java/com/splunk/rum/TracingHurlStackExceptionTest.java index cefdf756..cd39b81f 100644 --- a/splunk-otel-android-volley/src/test/java/com/splunk/rum/TracingHurlStackExceptionTest.java +++ b/splunk-otel-android-volley/src/test/java/com/splunk/rum/TracingHurlStackExceptionTest.java @@ -16,6 +16,7 @@ package com.splunk.rum; +import static com.splunk.rum.StandardAttributes.EXCEPTION_EVENT_NAME; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -25,7 +26,10 @@ import com.android.volley.toolbox.StringRequest; import io.opentelemetry.sdk.testing.junit4.OpenTelemetryRule; import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.semconv.ExceptionAttributes; import io.opentelemetry.semconv.SemanticAttributes; +import io.opentelemetry.semconv.incubating.ExceptionIncubatingAttributes; + import java.util.List; import java.util.concurrent.TimeUnit; import org.junit.After; @@ -75,20 +79,19 @@ public void spanDecoration_error() { assertThat(span) .hasEventsSatisfyingExactly( e -> - e.hasName(SemanticAttributes.EXCEPTION_EVENT_NAME) + e.hasName(EXCEPTION_EVENT_NAME) .hasAttributesSatisfying( a -> assertThat(a) .containsEntry( - SemanticAttributes - .EXCEPTION_TYPE, + ExceptionAttributes.EXCEPTION_TYPE, "java.lang.RuntimeException") .containsEntry( - SemanticAttributes + ExceptionAttributes .EXCEPTION_MESSAGE, "Something went wrong") .containsKey( - SemanticAttributes + ExceptionAttributes .EXCEPTION_STACKTRACE))); } diff --git a/splunk-otel-android-volley/src/test/java/com/splunk/rum/TracingHurlStackTest.java b/splunk-otel-android-volley/src/test/java/com/splunk/rum/TracingHurlStackTest.java index 43132c29..830c58a9 100644 --- a/splunk-otel-android-volley/src/test/java/com/splunk/rum/TracingHurlStackTest.java +++ b/splunk-otel-android-volley/src/test/java/com/splunk/rum/TracingHurlStackTest.java @@ -16,6 +16,7 @@ package com.splunk.rum; +import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE; import static io.opentelemetry.semconv.SemanticAttributes.HTTP_RESPONSE_BODY_SIZE; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -36,7 +37,13 @@ import io.opentelemetry.sdk.testing.junit4.OpenTelemetryRule; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.data.StatusData; +import io.opentelemetry.semconv.HttpAttributes; +import io.opentelemetry.semconv.NetworkAttributes; import io.opentelemetry.semconv.SemanticAttributes; +import io.opentelemetry.semconv.ServerAttributes; +import io.opentelemetry.semconv.UrlAttributes; +import io.opentelemetry.semconv.incubating.HttpIncubatingAttributes; + import java.io.IOException; import java.net.ServerSocket; import java.net.URL; @@ -172,7 +179,7 @@ public void connectionError() throws IOException { .allSatisfy( e -> assertThat(e.getName()) - .isEqualTo(SemanticAttributes.EXCEPTION_EVENT_NAME)); + .isEqualTo(StandardAttributes.EXCEPTION_EVENT_NAME)); verifyAttributes(span, url, null, null); } @@ -260,13 +267,11 @@ private void verifyAttributes(SpanData span, URL url, Long status, String respon Attributes spanAttributes = span.getAttributes(); - // We continue using deprecated semconv for now. When 2.0.0 hits we will need to update - // these. - assertThat(spanAttributes.get(SemanticAttributes.HTTP_STATUS_CODE)).isEqualTo(status); - assertThat(spanAttributes.get(SemanticAttributes.NET_PEER_PORT)).isEqualTo(url.getPort()); - assertThat(spanAttributes.get(SemanticAttributes.NET_PEER_NAME)).isEqualTo(url.getHost()); - assertThat(spanAttributes.get(SemanticAttributes.HTTP_URL)).isEqualTo(url.toString()); - assertThat(spanAttributes.get(SemanticAttributes.HTTP_METHOD)).isEqualTo("GET"); + assertThat(spanAttributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(status); + assertThat(spanAttributes.get(ServerAttributes.SERVER_PORT)).isEqualTo(url.getPort()); + assertThat(spanAttributes.get(ServerAttributes.SERVER_ADDRESS)).isEqualTo(url.getHost()); + assertThat(spanAttributes.get(UrlAttributes.URL_FULL)).isEqualTo(url.toString()); + assertThat(spanAttributes.get(HttpAttributes.HTTP_REQUEST_METHOD)).isEqualTo("GET"); if (responseBody != null) { assertThat(span.getAttributes().get(HTTP_RESPONSE_BODY_SIZE)) diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/LogToSpanBridge.java b/splunk-otel-android/src/main/java/com/splunk/rum/LogToSpanBridge.java index 4a98b7d4..6885db52 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/LogToSpanBridge.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/LogToSpanBridge.java @@ -33,7 +33,7 @@ import io.opentelemetry.sdk.logs.ReadWriteLogRecord; import io.opentelemetry.sdk.logs.data.Body; import io.opentelemetry.sdk.logs.data.LogRecordData; -import io.opentelemetry.semconv.SemanticAttributes; +import io.opentelemetry.semconv.incubating.EventIncubatingAttributes; import java.util.concurrent.TimeUnit; final class LogToSpanBridge implements LogRecordProcessor { @@ -89,11 +89,9 @@ private static String getSpanName(LogRecordData log) { if (operationName != null) { return operationName; } - String eventDomain = log.getAttributes().get(SemanticAttributes.EVENT_DOMAIN); - String eventName = log.getAttributes().get(SemanticAttributes.EVENT_NAME); - if (eventDomain != null || eventName != null) { - return (eventDomain == null ? "" : eventDomain + "/") - + (eventName == null ? "" : eventName); + String eventName = log.getAttributes().get(EventIncubatingAttributes.EVENT_NAME); + if (eventName != null) { + return eventName; } return "Log"; } 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 8fed2b4e..e50b42dc 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 @@ -27,7 +27,7 @@ import static com.splunk.rum.SplunkRum.SPLUNK_OLLY_UUID_KEY; 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 io.opentelemetry.semconv.incubating.DeploymentIncubatingAttributes.DEPLOYMENT_ENVIRONMENT; import static java.util.Objects.requireNonNull; import android.app.Application; diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java index 6936135c..073f38d4 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java @@ -18,22 +18,23 @@ import static com.splunk.rum.SplunkRum.ERROR_MESSAGE_KEY; import static com.splunk.rum.SplunkRum.ERROR_TYPE_KEY; +import static com.splunk.rum.StandardAttributes.EXCEPTION_EVENT_NAME; import static io.opentelemetry.api.common.AttributeKey.stringKey; -import static io.opentelemetry.semconv.SemanticAttributes.EXCEPTION_MESSAGE; -import static io.opentelemetry.semconv.SemanticAttributes.EXCEPTION_STACKTRACE; -import static io.opentelemetry.semconv.SemanticAttributes.EXCEPTION_TYPE; -import static io.opentelemetry.semconv.SemanticAttributes.NETWORK_CARRIER_ICC; -import static io.opentelemetry.semconv.SemanticAttributes.NETWORK_CARRIER_MCC; -import static io.opentelemetry.semconv.SemanticAttributes.NETWORK_CARRIER_MNC; -import static io.opentelemetry.semconv.SemanticAttributes.NETWORK_CARRIER_NAME; -import static io.opentelemetry.semconv.SemanticAttributes.NETWORK_CONNECTION_SUBTYPE; -import static io.opentelemetry.semconv.SemanticAttributes.NETWORK_CONNECTION_TYPE; +import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_MESSAGE; +import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_STACKTRACE; +import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_TYPE; import static io.opentelemetry.semconv.SemanticAttributes.NET_HOST_CARRIER_ICC; import static io.opentelemetry.semconv.SemanticAttributes.NET_HOST_CARRIER_MCC; import static io.opentelemetry.semconv.SemanticAttributes.NET_HOST_CARRIER_MNC; import static io.opentelemetry.semconv.SemanticAttributes.NET_HOST_CARRIER_NAME; import static io.opentelemetry.semconv.SemanticAttributes.NET_HOST_CONNECTION_SUBTYPE; import static io.opentelemetry.semconv.SemanticAttributes.NET_HOST_CONNECTION_TYPE; +import static io.opentelemetry.semconv.incubating.NetworkIncubatingAttributes.NETWORK_CARRIER_ICC; +import static io.opentelemetry.semconv.incubating.NetworkIncubatingAttributes.NETWORK_CARRIER_MCC; +import static io.opentelemetry.semconv.incubating.NetworkIncubatingAttributes.NETWORK_CARRIER_MNC; +import static io.opentelemetry.semconv.incubating.NetworkIncubatingAttributes.NETWORK_CARRIER_NAME; +import static io.opentelemetry.semconv.incubating.NetworkIncubatingAttributes.NETWORK_CONNECTION_SUBTYPE; +import static io.opentelemetry.semconv.incubating.NetworkIncubatingAttributes.NETWORK_CONNECTION_TYPE; import static java.util.Arrays.asList; import static java.util.Collections.unmodifiableSet; @@ -49,6 +50,10 @@ import io.opentelemetry.sdk.trace.export.SpanExporter; import io.opentelemetry.semconv.ResourceAttributes; import io.opentelemetry.semconv.SemanticAttributes; +import io.opentelemetry.semconv.incubating.DeploymentIncubatingAttributes; +import io.opentelemetry.semconv.incubating.DeviceIncubatingAttributes; +import io.opentelemetry.semconv.incubating.OsIncubatingAttributes; + import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -68,12 +73,12 @@ final class SplunkSpanDataModifier implements SpanExporter { unmodifiableSet( new HashSet<>( asList( - ResourceAttributes.DEPLOYMENT_ENVIRONMENT, - ResourceAttributes.DEVICE_MODEL_NAME, - ResourceAttributes.DEVICE_MODEL_IDENTIFIER, - ResourceAttributes.OS_NAME, - ResourceAttributes.OS_TYPE, - ResourceAttributes.OS_VERSION, + DeploymentIncubatingAttributes.DEPLOYMENT_ENVIRONMENT, + DeviceIncubatingAttributes.DEVICE_MODEL_NAME, + DeviceIncubatingAttributes.DEVICE_MODEL_IDENTIFIER, + OsIncubatingAttributes.OS_NAME, + OsIncubatingAttributes.OS_TYPE, + OsIncubatingAttributes.OS_VERSION, RumConstants.RUM_SDK_VERSION, SplunkRum.APP_NAME_KEY, SplunkRum.RUM_VERSION_KEY))); @@ -131,7 +136,7 @@ private SpanData modify(SpanData original) { // zipkin eats the event attributes that are recorded by default, so we need to convert // the exception event to span attributes for (EventData event : original.getEvents()) { - if (event.getName().equals(SemanticAttributes.EXCEPTION_EVENT_NAME)) { + if (event.getName().equals(EXCEPTION_EVENT_NAME)) { modifiedAttributes.putAll(extractExceptionAttributes(event)); } else { // if it's not an exception, leave the event as it is diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/StandardAttributes.java b/splunk-otel-android/src/main/java/com/splunk/rum/StandardAttributes.java index 6d436097..8da64b09 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/StandardAttributes.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/StandardAttributes.java @@ -25,7 +25,7 @@ /** * This class hold {@link AttributeKey}s for standard RUM-related attributes that are not in the - * OpenTelemetry {@link io.opentelemetry.semconv.SemanticAttributes} definitions. + * OpenTelemetry semantic definitions. */ public final class StandardAttributes { /** @@ -35,6 +35,8 @@ public final class StandardAttributes { */ public static final AttributeKey APP_VERSION = stringKey("app.version"); + public final static String EXCEPTION_EVENT_NAME = "exception"; + /** * The build type of your app (typically one of debug or release). Useful for adding to global * attributes. diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/LogToSpanBridgeTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/LogToSpanBridgeTest.java index 9ab98f89..5e1ad39d 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/LogToSpanBridgeTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/LogToSpanBridgeTest.java @@ -28,7 +28,7 @@ import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; import io.opentelemetry.sdk.trace.data.SpanData; -import io.opentelemetry.semconv.SemanticAttributes; +import io.opentelemetry.semconv.incubating.EventIncubatingAttributes; import java.util.List; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -99,8 +99,7 @@ void event() { when(log.getAttributes()) .thenReturn( Attributes.builder() - .put(SemanticAttributes.EVENT_DOMAIN, "androidApp") - .put(SemanticAttributes.EVENT_NAME, "buttonClick") + .put(EventIncubatingAttributes.EVENT_NAME, "androidApp.buttonClick") .put("attr", "value") .build()); when(log.getTimestampEpochNanos()).thenReturn(epochNanos); @@ -120,8 +119,7 @@ void event() { .endsAt(epochNanos) .hasAttributes( Attributes.builder() - .put(SemanticAttributes.EVENT_DOMAIN, "androidApp") - .put(SemanticAttributes.EVENT_NAME, "buttonClick") + .put(EventIncubatingAttributes.EVENT_NAME, "androidApp.buttonClick") .put("attr", "value") .build()); } diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/RumInitializerTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/RumInitializerTest.java index 3ab11df3..ecb21a1a 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/RumInitializerTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/RumInitializerTest.java @@ -50,7 +50,7 @@ import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.data.StatusData; import io.opentelemetry.sdk.trace.export.SpanExporter; -import io.opentelemetry.semconv.SemanticAttributes; +import io.opentelemetry.semconv.ExceptionAttributes; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -115,7 +115,7 @@ SpanExporter buildFilteringExporter( initSpan.getAttributes().get(stringKey("config_settings"))); List events = initSpan.getEvents(); - assertTrue(events.size() > 0); + assertThat(events).isNotEmpty(); checkEventExists(events, "connectionUtilInitialized"); checkEventExists(events, "exporterInitialized"); checkEventExists(events, "tracerProviderInitialized"); @@ -310,21 +310,21 @@ SpanExporter getCoreSpanExporter() { stringKey("attribute"), "oh no!") .containsEntry( - SemanticAttributes + ExceptionAttributes .EXCEPTION_TYPE, "IllegalArgumentException") .containsEntry( SplunkRum.ERROR_TYPE_KEY, "IllegalArgumentException") .containsEntry( - SemanticAttributes + ExceptionAttributes .EXCEPTION_MESSAGE, "booom!") .containsEntry( SplunkRum.ERROR_MESSAGE_KEY, "booom!") .containsKey( - SemanticAttributes + ExceptionAttributes .EXCEPTION_STACKTRACE)) .hasEvents(emptyList())); } From 7940857c4b362027aef37f7f5fef0c7f3f1baf0b Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 10 Apr 2024 15:35:38 -0700 Subject: [PATCH 04/29] update semconv --- .../src/main/java/com/splunk/android/sample/DemoWorker.java | 2 +- .../java/com/splunk/rum/TracingHurlStackExceptionTest.java | 6 ++---- .../src/test/java/com/splunk/rum/TracingHurlStackTest.java | 6 +----- .../rum/VolleyContentLengthAttributesExtractorTest.java | 2 +- .../main/java/com/splunk/rum/SplunkScreenNameExtractor.java | 2 +- .../main/java/com/splunk/rum/SplunkSpanDataModifier.java | 3 --- .../src/main/java/com/splunk/rum/StandardAttributes.java | 2 +- 7 files changed, 7 insertions(+), 16 deletions(-) diff --git a/sample-app/src/main/java/com/splunk/android/sample/DemoWorker.java b/sample-app/src/main/java/com/splunk/android/sample/DemoWorker.java index 33691503..e7566ba8 100644 --- a/sample-app/src/main/java/com/splunk/android/sample/DemoWorker.java +++ b/sample-app/src/main/java/com/splunk/android/sample/DemoWorker.java @@ -27,7 +27,7 @@ public class DemoWorker extends Worker { - private Context context; + private final Context context; public static final String TAG = "SplunkRum"; public DemoWorker(@NonNull Context context, @NonNull WorkerParameters params) { diff --git a/splunk-otel-android-volley/src/test/java/com/splunk/rum/TracingHurlStackExceptionTest.java b/splunk-otel-android-volley/src/test/java/com/splunk/rum/TracingHurlStackExceptionTest.java index cd39b81f..2346f29b 100644 --- a/splunk-otel-android-volley/src/test/java/com/splunk/rum/TracingHurlStackExceptionTest.java +++ b/splunk-otel-android-volley/src/test/java/com/splunk/rum/TracingHurlStackExceptionTest.java @@ -27,9 +27,6 @@ import io.opentelemetry.sdk.testing.junit4.OpenTelemetryRule; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.semconv.ExceptionAttributes; -import io.opentelemetry.semconv.SemanticAttributes; -import io.opentelemetry.semconv.incubating.ExceptionIncubatingAttributes; - import java.util.List; import java.util.concurrent.TimeUnit; import org.junit.After; @@ -84,7 +81,8 @@ public void spanDecoration_error() { a -> assertThat(a) .containsEntry( - ExceptionAttributes.EXCEPTION_TYPE, + ExceptionAttributes + .EXCEPTION_TYPE, "java.lang.RuntimeException") .containsEntry( ExceptionAttributes diff --git a/splunk-otel-android-volley/src/test/java/com/splunk/rum/TracingHurlStackTest.java b/splunk-otel-android-volley/src/test/java/com/splunk/rum/TracingHurlStackTest.java index 830c58a9..ee49adfa 100644 --- a/splunk-otel-android-volley/src/test/java/com/splunk/rum/TracingHurlStackTest.java +++ b/splunk-otel-android-volley/src/test/java/com/splunk/rum/TracingHurlStackTest.java @@ -17,7 +17,7 @@ package com.splunk.rum; import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE; -import static io.opentelemetry.semconv.SemanticAttributes.HTTP_RESPONSE_BODY_SIZE; +import static io.opentelemetry.semconv.incubating.HttpIncubatingAttributes.HTTP_RESPONSE_BODY_SIZE; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Fail.fail; @@ -38,12 +38,8 @@ import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.data.StatusData; import io.opentelemetry.semconv.HttpAttributes; -import io.opentelemetry.semconv.NetworkAttributes; -import io.opentelemetry.semconv.SemanticAttributes; import io.opentelemetry.semconv.ServerAttributes; import io.opentelemetry.semconv.UrlAttributes; -import io.opentelemetry.semconv.incubating.HttpIncubatingAttributes; - import java.io.IOException; import java.net.ServerSocket; import java.net.URL; diff --git a/splunk-otel-android-volley/src/test/java/com/splunk/rum/VolleyContentLengthAttributesExtractorTest.java b/splunk-otel-android-volley/src/test/java/com/splunk/rum/VolleyContentLengthAttributesExtractorTest.java index 72748b01..4d294d73 100644 --- a/splunk-otel-android-volley/src/test/java/com/splunk/rum/VolleyContentLengthAttributesExtractorTest.java +++ b/splunk-otel-android-volley/src/test/java/com/splunk/rum/VolleyContentLengthAttributesExtractorTest.java @@ -16,7 +16,7 @@ package com.splunk.rum; -import static io.opentelemetry.semconv.SemanticAttributes.HTTP_RESPONSE_BODY_SIZE; +import static io.opentelemetry.semconv.incubating.HttpIncubatingAttributes.HTTP_RESPONSE_BODY_SIZE; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkScreenNameExtractor.java b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkScreenNameExtractor.java index 506f5c72..0b5728bf 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkScreenNameExtractor.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkScreenNameExtractor.java @@ -27,7 +27,7 @@ */ class SplunkScreenNameExtractor implements ScreenNameExtractor { - static ScreenNameExtractor INSTANCE = new SplunkScreenNameExtractor(); + static final ScreenNameExtractor INSTANCE = new SplunkScreenNameExtractor(); private SplunkScreenNameExtractor() {} diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java index 073f38d4..78be3fb1 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java @@ -48,12 +48,9 @@ import io.opentelemetry.sdk.trace.data.EventData; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.export.SpanExporter; -import io.opentelemetry.semconv.ResourceAttributes; -import io.opentelemetry.semconv.SemanticAttributes; import io.opentelemetry.semconv.incubating.DeploymentIncubatingAttributes; import io.opentelemetry.semconv.incubating.DeviceIncubatingAttributes; import io.opentelemetry.semconv.incubating.OsIncubatingAttributes; - import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/StandardAttributes.java b/splunk-otel-android/src/main/java/com/splunk/rum/StandardAttributes.java index 8da64b09..29b3fc2c 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/StandardAttributes.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/StandardAttributes.java @@ -35,7 +35,7 @@ public final class StandardAttributes { */ public static final AttributeKey APP_VERSION = stringKey("app.version"); - public final static String EXCEPTION_EVENT_NAME = "exception"; + public static final String EXCEPTION_EVENT_NAME = "exception"; /** * The build type of your app (typically one of debug or release). Useful for adding to global From 2f01dec3b91dc942c2d2b2a4a29822a89eb2cda6 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 10 Apr 2024 15:47:50 -0700 Subject: [PATCH 05/29] fix test --- .../src/test/java/com/splunk/rum/LogToSpanBridgeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/LogToSpanBridgeTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/LogToSpanBridgeTest.java index 5e1ad39d..6e5f6ca3 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/LogToSpanBridgeTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/LogToSpanBridgeTest.java @@ -114,7 +114,7 @@ void event() { assertThat(spans).hasSize(1); assertThat(spans.get(0)) .hasInstrumentationScopeInfo(InstrumentationScopeInfo.create("test")) - .hasName("androidApp/buttonClick") + .hasName("androidApp.buttonClick") .startsAt(epochNanos) .endsAt(epochNanos) .hasAttributes( From 548579a484e0aa881d00243284a99b381d5bfefe Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 12 Apr 2024 09:26:50 -0700 Subject: [PATCH 06/29] rebase and update --- gradle/libs.versions.toml | 14 +++++++------- splunk-otel-android-volley/build.gradle.kts | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 921310fc..5da010ad 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,9 +1,9 @@ [versions] opentelemetry-core = "1.42.1" opentelemetry-core-alpha = "1.42.1-alpha" -opentelemetry-inst = "1.33.6" -opentelemetry-inst-alpha = "1.33.6-alpha" -opentelemetry-android = "0.4.0-alpha" +opentelemetry-inst = "2.6.0" +opentelemetry-inst-alpha = "2.6.0-alpha" +opentelemetry-android = "0.7.0-alpha" mockito = "5.14.2" junit = "5.11.3" spotless = "6.25.0" @@ -16,12 +16,12 @@ navigationCompose = "2.7.7" [libraries] opentelemetry-instrumentation-bom = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom", version.ref = "opentelemetry-inst" } opentelemetry-bom = { module = "io.opentelemetry:opentelemetry-bom", version.ref = "opentelemetry-core" } -opentelemetry-sdk = { module = "io.opentelemetry:opentelemetry-sdk" } -opentelemetry-api = { module = "io.opentelemetry:opentelemetry-api" } -opentelemetry-api-incubator = { module = "io.opentelemetry:opentelemetry-api-incubator", version.ref = "opentelemetry-core-alpha" } +opentelemetry-sdk = { module = "io.opentelemetry:opentelemetry-sdk", version.ref = "opentelemetry-core" } +opentelemetry-api = { module = "io.opentelemetry:opentelemetry-api", version.ref = "opentelemetry-core" } +opentelemetry-api-events = { module = "io.opentelemetry:opentelemetry-api-events", version.ref = "opentelemetry-core-alpha" } opentelemetry-android = { module = "io.opentelemetry.android:instrumentation", version.ref = "opentelemetry-android" } opentelemetry-instrumenter-api = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api", version.ref = "opentelemetry-inst" } -opentelemetry-instrumenter-api-semconv = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-semconv", version.ref = "opentelemetry-inst-alpha" } +opentelemetry-instrumenter-api-incubator = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-incubator", version.ref = "opentelemetry-inst-alpha" } opentelemetry-instrumentation-okhttp = { module = "io.opentelemetry.instrumentation:opentelemetry-okhttp-3.0", version.ref = "opentelemetry-inst-alpha" } opentelemetry-exporter-zipkin = { module = "io.opentelemetry:opentelemetry-exporter-zipkin", version.ref = "opentelemetry-core" } opentelemetry-exporter-otlp = { module = "io.opentelemetry:opentelemetry-exporter-otlp", version.ref = "opentelemetry-core" } diff --git a/splunk-otel-android-volley/build.gradle.kts b/splunk-otel-android-volley/build.gradle.kts index a7fdf71b..daef9d14 100644 --- a/splunk-otel-android-volley/build.gradle.kts +++ b/splunk-otel-android-volley/build.gradle.kts @@ -50,7 +50,7 @@ dependencies { api(platform(libs.opentelemetry.bom)) compileOnly(libs.opentelemetry.api) implementation(libs.opentelemetry.instrumenter.api) - implementation(libs.opentelemetry.instrumenter.api.semconv) + implementation(libs.opentelemetry.instrumenter.api.incubator) compileOnly(libs.android.volley) implementation(libs.androidx.core) testImplementation(libs.mockwebserver) From 1f4fc8f9830584bf84d1cef2b21a24486121c5bc Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Mon, 12 Aug 2024 15:51:50 -0700 Subject: [PATCH 07/29] update to 0.7.0-alpha-snapshot and get lots of breakage --- build.gradle.kts | 2 ++ gradle.properties | 2 +- gradle/libs.versions.toml | 4 ++-- sample-app/build.gradle.kts | 11 ++++++++++- .../splunk/rum/SettableScreenAttributesAppender.java | 10 +++++----- 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index c97f9fbb..5719cd90 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -21,6 +21,8 @@ allprojects { repositories { google() mavenCentral() + // TODO: Remove after android-agent 0.7.0-alpha is released + maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") } } if (findProperty("release") != "true") { version = "$version-SNAPSHOT" diff --git a/gradle.properties b/gradle.properties index 73fdecd6..e5fab579 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,5 +17,5 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 android.useAndroidX=true # generate the BuildConfig class that contains the app version -version=1.8.0 +version=2.0.0-alpha group=com.splunk diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5da010ad..f577d208 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ opentelemetry-core = "1.42.1" opentelemetry-core-alpha = "1.42.1-alpha" opentelemetry-inst = "2.6.0" opentelemetry-inst-alpha = "2.6.0-alpha" -opentelemetry-android = "0.7.0-alpha" +opentelemetry-android = "0.7.0-alpha-SNAPSHOT" mockito = "5.14.2" junit = "5.11.3" spotless = "6.25.0" @@ -19,7 +19,7 @@ opentelemetry-bom = { module = "io.opentelemetry:opentelemetry-bom", version.ref opentelemetry-sdk = { module = "io.opentelemetry:opentelemetry-sdk", version.ref = "opentelemetry-core" } opentelemetry-api = { module = "io.opentelemetry:opentelemetry-api", version.ref = "opentelemetry-core" } opentelemetry-api-events = { module = "io.opentelemetry:opentelemetry-api-events", version.ref = "opentelemetry-core-alpha" } -opentelemetry-android = { module = "io.opentelemetry.android:instrumentation", version.ref = "opentelemetry-android" } +opentelemetry-android = { module = "io.opentelemetry.android:android-agent", version.ref = "opentelemetry-android" } opentelemetry-instrumenter-api = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api", version.ref = "opentelemetry-inst" } opentelemetry-instrumenter-api-incubator = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-incubator", version.ref = "opentelemetry-inst-alpha" } opentelemetry-instrumentation-okhttp = { module = "io.opentelemetry.instrumentation:opentelemetry-okhttp-3.0", version.ref = "opentelemetry-inst-alpha" } diff --git a/sample-app/build.gradle.kts b/sample-app/build.gradle.kts index 28144317..138fa348 100644 --- a/sample-app/build.gradle.kts +++ b/sample-app/build.gradle.kts @@ -7,6 +7,7 @@ plugins { alias(libs.plugins.compose) } + val localProperties = Properties() localProperties.load(FileInputStream(rootProject.file("local.properties"))) @@ -70,6 +71,14 @@ composeCompiler { enableStrongSkippingMode = true } +repositories { + // TODO: Remove after android-agent 0.7.0-alpha is released + maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") } +// mavenCentral() +// google() +// gradlePluginPortal() +} + dependencies { api(platform(libs.opentelemetry.instrumentation.bom)) @@ -95,7 +104,7 @@ dependencies { implementation(libs.android.volley) implementation(libs.androidx.work) implementation(libs.opentelemetry.sdk) - implementation(libs.opentelemetry.api.incubator) + implementation(libs.opentelemetry.instrumenter.api.incubator) testImplementation(libs.bundles.junit) testRuntimeOnly(libs.junit.platform.launcher) androidTestImplementation(libs.androidx.test.core) diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/SettableScreenAttributesAppender.java b/splunk-otel-android/src/main/java/com/splunk/rum/SettableScreenAttributesAppender.java index a62ee84f..ead381e3 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/SettableScreenAttributesAppender.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/SettableScreenAttributesAppender.java @@ -16,10 +16,10 @@ package com.splunk.rum; -import static io.opentelemetry.android.RumConstants.LAST_SCREEN_NAME_KEY; -import static io.opentelemetry.android.RumConstants.SCREEN_NAME_KEY; +import static io.opentelemetry.android.common.RumConstants.LAST_SCREEN_NAME_KEY; +import static io.opentelemetry.android.common.RumConstants.SCREEN_NAME_KEY; -import io.opentelemetry.android.instrumentation.activity.VisibleScreenTracker; +import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService; import io.opentelemetry.context.Context; import io.opentelemetry.sdk.trace.ReadWriteSpan; import io.opentelemetry.sdk.trace.ReadableSpan; @@ -28,11 +28,11 @@ public class SettableScreenAttributesAppender implements SpanProcessor { - private final VisibleScreenTracker visibleScreenTracker; + private final VisibleScreenService visibleScreenTracker; private final AtomicReference lastScreenName = new AtomicReference<>(); private final AtomicReference previouslyLastScreenName = new AtomicReference<>(); - public SettableScreenAttributesAppender(VisibleScreenTracker visibleScreenTracker) { + public SettableScreenAttributesAppender(VisibleScreenService visibleScreenTracker) { this.visibleScreenTracker = visibleScreenTracker; } From e104981a1d435fc30d2cacb971a40f4068e6de94 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Mon, 12 Aug 2024 16:25:11 -0700 Subject: [PATCH 08/29] fix up semconv --- gradle/libs.versions.toml | 3 +++ splunk-otel-android/build.gradle.kts | 2 ++ .../src/main/java/com/splunk/rum/RumInitializer.java | 12 +++++------- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f577d208..5e51a3ce 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,6 +4,7 @@ opentelemetry-core-alpha = "1.42.1-alpha" opentelemetry-inst = "2.6.0" opentelemetry-inst-alpha = "2.6.0-alpha" opentelemetry-android = "0.7.0-alpha-SNAPSHOT" +opentelemetry-semconv = "1.26.0-alpha" mockito = "5.14.2" junit = "5.11.3" spotless = "6.25.0" @@ -26,6 +27,8 @@ opentelemetry-instrumentation-okhttp = { module = "io.opentelemetry.instrumentat opentelemetry-exporter-zipkin = { module = "io.opentelemetry:opentelemetry-exporter-zipkin", version.ref = "opentelemetry-core" } opentelemetry-exporter-otlp = { module = "io.opentelemetry:opentelemetry-exporter-otlp", version.ref = "opentelemetry-core" } opentelemetry-exporter-logging = { module = "io.opentelemetry:opentelemetry-exporter-logging", version.ref = "opentelemetry-core" } +opentelemetry-semconv = { module = "io.opentelemetry.semconv:opentelemetry-semconv", version.ref = "opentelemetry-semconv" } +opentelemetry-semconv-incubating = { module = "io.opentelemetry.semconv:opentelemetry-semconv-incubating", version.ref = "opentelemetry-semconv" } opentelemetry-sdk-testing = { module = "io.opentelemetry:opentelemetry-sdk-testing", version.ref = "opentelemetry-core" } zipkin-sender-okhttp = "io.zipkin.reporter2:zipkin-sender-okhttp3:3.4.2" diff --git a/splunk-otel-android/build.gradle.kts b/splunk-otel-android/build.gradle.kts index 38b9f0ba..303b3aa6 100644 --- a/splunk-otel-android/build.gradle.kts +++ b/splunk-otel-android/build.gradle.kts @@ -49,6 +49,8 @@ dependencies { implementation(libs.opentelemetry.exporter.zipkin) implementation(libs.opentelemetry.exporter.otlp) implementation(libs.opentelemetry.exporter.logging) + implementation(libs.opentelemetry.semconv) + implementation(libs.opentelemetry.semconv.incubating) implementation(libs.androidx.core) implementation(libs.androidx.navigation.fragment) api(libs.zipkin.sender.okhttp) 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 e50b42dc..a7cb1c2c 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 @@ -189,9 +189,9 @@ SplunkRum initialize(Looper mainLooper) { // make sure the TracerProvider gets set as the very first thing, before any other // instrumentations otelRumBuilder.addInstrumentation( - instrumentedApplication -> + (app, otelRum) -> logBridge.setTracerProvider( - instrumentedApplication.getOpenTelemetrySdk().getTracerProvider())); + otelRum.getOpenTelemetry().getTracerProvider())); if (builder.isAnrDetectionEnabled()) { installAnrDetector(otelRumBuilder, mainLooper); @@ -315,7 +315,7 @@ private void installAnrDetector(OpenTelemetryRumBuilder otelRumBuilder, Looper m private void installCrashReporter(OpenTelemetryRumBuilder otelRumBuilder) { otelRumBuilder.addInstrumentation( - instrumentedApplication -> { + (app,otelRum) -> { ErrorIdentifierExtractor extractor = new ErrorIdentifierExtractor(application); ErrorIdentifierInfo errorIdentifierInfo = extractor.extractInfo(); String applicationId = errorIdentifierInfo.getApplicationId(); @@ -325,9 +325,7 @@ private void installCrashReporter(OpenTelemetryRumBuilder otelRumBuilder) { CrashReporterBuilder builder = CrashReporter.builder(); builder.addAttributesExtractor( RuntimeDetailsExtractor.create( - instrumentedApplication - .getApplication() - .getApplicationContext())) + app.getApplicationContext())) .addAttributesExtractor(new CrashComponentExtractor()); if (applicationId != null) @@ -350,7 +348,7 @@ private void installSlowRenderingDetector(OpenTelemetryRumBuilder otelRumBuilder .setSlowRenderingDetectionPollInterval( builder.slowRenderingDetectionPollInterval) .build() - .installOn(instrumentedApplication); + .installOn(app); initializationEvents.emit("slowRenderingDetectorInitialized"); }); } From f2dbb70e4a21beb5c26b9636094a90bd7f420e07 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Mon, 12 Aug 2024 16:29:58 -0700 Subject: [PATCH 09/29] fix up constants --- .../src/main/java/com/splunk/rum/RumInitializer.java | 4 +++- .../main/java/com/splunk/rum/ScreenAttributesAppender.java | 2 +- .../src/test/java/com/splunk/rum/RumInitializerTest.java | 4 ++-- .../java/com/splunk/rum/ScreenAttributesAppenderTest.java | 4 ++-- 4 files changed, 8 insertions(+), 6 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 a7cb1c2c..b1bf8a70 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 @@ -25,7 +25,7 @@ import static com.splunk.rum.SplunkRum.COMPONENT_UI; import static com.splunk.rum.SplunkRum.RUM_TRACER_NAME; import static com.splunk.rum.SplunkRum.SPLUNK_OLLY_UUID_KEY; -import static io.opentelemetry.android.RumConstants.APP_START_SPAN_NAME; +import static io.opentelemetry.android.common.RumConstants.APP_START_SPAN_NAME; import static io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor.constant; import static io.opentelemetry.semconv.incubating.DeploymentIncubatingAttributes.DEPLOYMENT_ENVIRONMENT; import static java.util.Objects.requireNonNull; @@ -387,6 +387,7 @@ private SpanExporter buildExporter( currentNetworkProvider, constructBacklogProvider(visibleScreenTracker)); } + //TODO: Make this use OTLP buffering via upstream private SpanExporter buildStorageBufferingExporter( CurrentNetworkProvider currentNetworkProvider, SpanStorage spanStorage) { Sender sender = buildCustomizedZipkinSender(); @@ -465,6 +466,7 @@ private Supplier supplyOtlpExporter() { .build(); } + //TODO: This needs to go away as part of 2.0, OTLP only @NonNull private Supplier supplyZipkinExporter() { String endpoint = getEndpointWithAuthTokenQueryParam(); diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/ScreenAttributesAppender.java b/splunk-otel-android/src/main/java/com/splunk/rum/ScreenAttributesAppender.java index 32d94fa2..2b9ec6f8 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/ScreenAttributesAppender.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/ScreenAttributesAppender.java @@ -16,7 +16,7 @@ package com.splunk.rum; -import static io.opentelemetry.android.RumConstants.SCREEN_NAME_KEY; +import static io.opentelemetry.android.common.RumConstants.SCREEN_NAME_KEY; import io.opentelemetry.android.instrumentation.activity.VisibleScreenTracker; import io.opentelemetry.context.Context; diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/RumInitializerTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/RumInitializerTest.java index ecb21a1a..7387620e 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/RumInitializerTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/RumInitializerTest.java @@ -17,8 +17,8 @@ package com.splunk.rum; import static com.splunk.rum.SplunkRum.COMPONENT_KEY; -import static io.opentelemetry.android.RumConstants.LAST_SCREEN_NAME_KEY; -import static io.opentelemetry.android.RumConstants.SCREEN_NAME_KEY; +import static io.opentelemetry.android.common.RumConstants.LAST_SCREEN_NAME_KEY; +import static io.opentelemetry.android.common.RumConstants.SCREEN_NAME_KEY; import static io.opentelemetry.api.common.AttributeKey.stringKey; import static java.util.Collections.emptyList; import static java.util.concurrent.TimeUnit.MILLISECONDS; diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/ScreenAttributesAppenderTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/ScreenAttributesAppenderTest.java index 832e233f..ccd67ff5 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/ScreenAttributesAppenderTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/ScreenAttributesAppenderTest.java @@ -16,8 +16,8 @@ package com.splunk.rum; -import static io.opentelemetry.android.RumConstants.LAST_SCREEN_NAME_KEY; -import static io.opentelemetry.android.RumConstants.SCREEN_NAME_KEY; +import static io.opentelemetry.android.common.RumConstants.LAST_SCREEN_NAME_KEY; +import static io.opentelemetry.android.common.RumConstants.SCREEN_NAME_KEY; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; From 3060aa5c069945329e97a0e103475f7bdc27cbfe Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Mon, 12 Aug 2024 16:38:22 -0700 Subject: [PATCH 10/29] fix import --- .../src/main/java/com/splunk/rum/SplunkSpanDataModifier.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java index 78be3fb1..f4f37f74 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java @@ -38,7 +38,7 @@ import static java.util.Arrays.asList; import static java.util.Collections.unmodifiableSet; -import io.opentelemetry.android.RumConstants; +import io.opentelemetry.android.common.RumConstants; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.AttributesBuilder; From 3cf7ad9412a9a3ed94d677fac5aac1412506804a Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Tue, 13 Aug 2024 09:36:54 -0700 Subject: [PATCH 11/29] more breakage and todos --- .../java/com/splunk/rum/RumInitializer.java | 18 +++++++++++------- 1 file changed, 11 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 b1bf8a70..48a7e964 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 @@ -100,9 +100,11 @@ SplunkRum initialize(Looper mainLooper) { GlobalAttributesSupplier globalAttributeSupplier = new GlobalAttributesSupplier(builder.globalAttributes); config.setGlobalAttributes(globalAttributeSupplier); - if (!builder.isNetworkMonitorEnabled()) { - config.disableNetworkChangeMonitoring(); - } + + // TODO: Note/document this instrumentation is now opt-in via application classpath via build settings +// if (!builder.isNetworkMonitorEnabled()) { +// config.disableNetworkChangeMonitoring(); +// } config.disableScreenAttributes(); OpenTelemetryRumBuilder otelRumBuilder = OpenTelemetryRum.builder(application, config); @@ -110,10 +112,12 @@ SplunkRum initialize(Looper mainLooper) { otelRumBuilder.mergeResource(createSplunkResource()); initializationEvents.emit("resourceInitialized"); - CurrentNetworkProvider currentNetworkProvider = - CurrentNetworkProvider.createAndStart(application); - otelRumBuilder.setCurrentNetworkProvider(currentNetworkProvider); - initializationEvents.emit("connectionUtilInitialized"); + // TODO: now spelled rum.sdk.init.net.provider and currently mixed up in network + // attributes enabled config in upstream +// CurrentNetworkProvider currentNetworkProvider = +// CurrentNetworkProvider.createAndStart(application); +// otelRumBuilder.setCurrentNetworkProvider(currentNetworkProvider); +// initializationEvents.emit("connectionUtilInitialized"); // TODO: How truly important is the order of these span processors? The location of event // generation should probably not be altered... From c7062aaad5380e3c9b196fb6c4d8253614283836 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Tue, 27 Aug 2024 11:26:15 -0700 Subject: [PATCH 12/29] work in progress around 2.x --- build.gradle.kts | 2 -- gradle/libs.versions.toml | 4 ++-- splunk-otel-android/build.gradle.kts | 2 +- .../src/main/java/com/splunk/rum/RumInitializer.java | 1 + 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 5719cd90..c97f9fbb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -21,8 +21,6 @@ allprojects { repositories { google() mavenCentral() - // TODO: Remove after android-agent 0.7.0-alpha is released - maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") } } if (findProperty("release") != "true") { version = "$version-SNAPSHOT" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5e51a3ce..4268e4d3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ opentelemetry-core = "1.42.1" opentelemetry-core-alpha = "1.42.1-alpha" opentelemetry-inst = "2.6.0" opentelemetry-inst-alpha = "2.6.0-alpha" -opentelemetry-android = "0.7.0-alpha-SNAPSHOT" +opentelemetry-android = "0.7.0-alpha" opentelemetry-semconv = "1.26.0-alpha" mockito = "5.14.2" junit = "5.11.3" @@ -20,7 +20,7 @@ opentelemetry-bom = { module = "io.opentelemetry:opentelemetry-bom", version.ref opentelemetry-sdk = { module = "io.opentelemetry:opentelemetry-sdk", version.ref = "opentelemetry-core" } opentelemetry-api = { module = "io.opentelemetry:opentelemetry-api", version.ref = "opentelemetry-core" } opentelemetry-api-events = { module = "io.opentelemetry:opentelemetry-api-events", version.ref = "opentelemetry-core-alpha" } -opentelemetry-android = { module = "io.opentelemetry.android:android-agent", version.ref = "opentelemetry-android" } +opentelemetry-android-agent = { module = "io.opentelemetry.android:android-agent", version.ref = "opentelemetry-android" } opentelemetry-instrumenter-api = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api", version.ref = "opentelemetry-inst" } opentelemetry-instrumenter-api-incubator = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-incubator", version.ref = "opentelemetry-inst-alpha" } opentelemetry-instrumentation-okhttp = { module = "io.opentelemetry.instrumentation:opentelemetry-okhttp-3.0", version.ref = "opentelemetry-inst-alpha" } diff --git a/splunk-otel-android/build.gradle.kts b/splunk-otel-android/build.gradle.kts index 303b3aa6..3c23e6e1 100644 --- a/splunk-otel-android/build.gradle.kts +++ b/splunk-otel-android/build.gradle.kts @@ -42,7 +42,7 @@ android { dependencies { api(platform(libs.opentelemetry.instrumentation.bom)) api(platform(libs.opentelemetry.bom)) - api(libs.opentelemetry.android) + api(libs.opentelemetry.android.agent) implementation(libs.opentelemetry.sdk) implementation(libs.opentelemetry.instrumentation.okhttp) 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 48a7e964..8a2de716 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 @@ -467,6 +467,7 @@ private Supplier supplyOtlpExporter() { OtlpHttpSpanExporter.builder() .setEndpoint(endpoint) .addHeader("X-SF-Token", builder.rumAccessToken) + . .build(); } From cc39d35d5fca8f8c300e89a3dbc7d8bff3b075a1 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 4 Sep 2024 09:49:20 -0700 Subject: [PATCH 13/29] work in progress --- gradle/libs.versions.toml | 1 + .../com/splunk/android/sample/DemoWorker.java | 2 +- .../splunk/android/sample/FirstFragment.java | 2 +- .../android/sample/MailDialogFragment.java | 2 +- .../splunk/android/sample/MainActivity.java | 3 +- .../splunk/android/sample/SecondFragment.java | 18 +- .../android/sample/WebViewFragment.java | 2 +- splunk-otel-android-volley/build.gradle.kts | 1 + splunk-otel-android/build.gradle.kts | 1 + .../com/splunk/rum/DiskToZipkinExporter.java | 163 ------ .../com/splunk/rum/InitializationEvents.java | 4 +- .../splunk/rum/MemoryBufferingExporter.java | 99 ---- .../java/com/splunk/rum/NoOpSplunkRum.java | 2 +- .../java/com/splunk/rum/RumInitializer.java | 552 +++++++++--------- .../java/com/splunk/rum/RumScreenName.java | 34 -- .../splunk/rum/ScreenAttributesAppender.java | 53 -- .../main/java/com/splunk/rum/SplunkRum.java | 27 +- .../splunk/rum/SplunkScreenNameExtractor.java | 4 +- .../rum/StartTypeAwareMemorySpanBuffer.java | 9 +- .../splunk/rum/StartTypeAwareSpanStorage.java | 25 +- .../splunk/rum/DiskToZipkinExporterTest.java | 140 ----- .../rum/MemoryBufferingExporterTest.java | 207 ------- .../com/splunk/rum/NoOpSplunkRumTest.java | 2 +- .../com/splunk/rum/RumInitializerTest.java | 171 +++--- .../rum/ScreenAttributesAppenderTest.java | 80 --- .../java/com/splunk/rum/SplunkRumTest.java | 21 +- .../rum/SplunkSpanDataModifierTest.java | 2 +- .../StartTypeAwareMemorySpanBufferTest.java | 4 +- .../rum/StartTypeAwareSpanStorageTest.java | 35 +- 29 files changed, 458 insertions(+), 1208 deletions(-) delete mode 100644 splunk-otel-android/src/main/java/com/splunk/rum/DiskToZipkinExporter.java delete mode 100644 splunk-otel-android/src/main/java/com/splunk/rum/MemoryBufferingExporter.java delete mode 100644 splunk-otel-android/src/main/java/com/splunk/rum/RumScreenName.java delete mode 100644 splunk-otel-android/src/main/java/com/splunk/rum/ScreenAttributesAppender.java delete mode 100644 splunk-otel-android/src/test/java/com/splunk/rum/DiskToZipkinExporterTest.java delete mode 100644 splunk-otel-android/src/test/java/com/splunk/rum/MemoryBufferingExporterTest.java delete mode 100644 splunk-otel-android/src/test/java/com/splunk/rum/ScreenAttributesAppenderTest.java diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4268e4d3..9344c434 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,6 +19,7 @@ opentelemetry-instrumentation-bom = { module = "io.opentelemetry.instrumentation opentelemetry-bom = { module = "io.opentelemetry:opentelemetry-bom", version.ref = "opentelemetry-core" } opentelemetry-sdk = { module = "io.opentelemetry:opentelemetry-sdk", version.ref = "opentelemetry-core" } opentelemetry-api = { module = "io.opentelemetry:opentelemetry-api", version.ref = "opentelemetry-core" } +opentelemetry-api-incubator = { module = "io.opentelemetry:opentelemetry-api-incubator" } opentelemetry-api-events = { module = "io.opentelemetry:opentelemetry-api-events", version.ref = "opentelemetry-core-alpha" } opentelemetry-android-agent = { module = "io.opentelemetry.android:android-agent", version.ref = "opentelemetry-android" } opentelemetry-instrumenter-api = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api", version.ref = "opentelemetry-inst" } diff --git a/sample-app/src/main/java/com/splunk/android/sample/DemoWorker.java b/sample-app/src/main/java/com/splunk/android/sample/DemoWorker.java index e7566ba8..0ca8eee6 100644 --- a/sample-app/src/main/java/com/splunk/android/sample/DemoWorker.java +++ b/sample-app/src/main/java/com/splunk/android/sample/DemoWorker.java @@ -39,7 +39,7 @@ public DemoWorker(@NonNull Context context, @NonNull WorkerParameters params) { @Override public Result doWork() { try { - SplunkRum.getInstance().addRumEvent("DemoWorker is doing work", Attributes.empty()); + SplunkRum.getInstance().emitEvent("DemoWorker is doing work", Attributes.empty()); Log.d(TAG, "DemoWorker Starting background Service"); startBackgroundService(); return Result.success(); diff --git a/sample-app/src/main/java/com/splunk/android/sample/FirstFragment.java b/sample-app/src/main/java/com/splunk/android/sample/FirstFragment.java index 6212f4d2..1d159b1d 100644 --- a/sample-app/src/main/java/com/splunk/android/sample/FirstFragment.java +++ b/sample-app/src/main/java/com/splunk/android/sample/FirstFragment.java @@ -131,7 +131,7 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { v -> { // Without being in a workflow, this will still show up in the UI but wil not be // grouped under the "Custom Events" tab. - splunkRum.addRumEvent( + splunkRum.emitEvent( "kustom", Attributes.of(longKey("counted"), customCount.incrementAndGet())); }); diff --git a/sample-app/src/main/java/com/splunk/android/sample/MailDialogFragment.java b/sample-app/src/main/java/com/splunk/android/sample/MailDialogFragment.java index c8551781..e03d8988 100644 --- a/sample-app/src/main/java/com/splunk/android/sample/MailDialogFragment.java +++ b/sample-app/src/main/java/com/splunk/android/sample/MailDialogFragment.java @@ -46,7 +46,7 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { R.string.cancel, (dialog, id) -> SplunkRum.getInstance() - .addRumEvent("User Rejected Help", HELPER_ATTRIBUTES)); + .emitEvent("User Rejected Help", HELPER_ATTRIBUTES)); return builder.create(); } } diff --git a/sample-app/src/main/java/com/splunk/android/sample/MainActivity.java b/sample-app/src/main/java/com/splunk/android/sample/MainActivity.java index 00c9367a..6196484f 100644 --- a/sample-app/src/main/java/com/splunk/android/sample/MainActivity.java +++ b/sample-app/src/main/java/com/splunk/android/sample/MainActivity.java @@ -43,7 +43,8 @@ import androidx.work.WorkManager; import com.splunk.android.sample.databinding.ActivityMainBinding; import com.splunk.rum.SplunkRum; -import io.opentelemetry.android.instrumentation.RumScreenName; + +import io.opentelemetry.android.instrumentation.annotations.RumScreenName; import io.opentelemetry.api.common.Attributes; import java.util.Arrays; import java.util.concurrent.TimeUnit; diff --git a/sample-app/src/main/java/com/splunk/android/sample/SecondFragment.java b/sample-app/src/main/java/com/splunk/android/sample/SecondFragment.java index 8a60ad1c..a03f2be1 100644 --- a/sample-app/src/main/java/com/splunk/android/sample/SecondFragment.java +++ b/sample-app/src/main/java/com/splunk/android/sample/SecondFragment.java @@ -29,11 +29,9 @@ import androidx.navigation.fragment.NavHostFragment; import com.splunk.android.sample.databinding.FragmentSecondBinding; import com.splunk.rum.SplunkRum; -import io.opentelemetry.android.instrumentation.RumScreenName; + +import io.opentelemetry.android.instrumentation.annotations.RumScreenName; import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.incubator.events.EventLogger; -import io.opentelemetry.api.incubator.events.EventLogger; -import io.opentelemetry.api.incubator.events.EventLoggerProvider; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Scope; @@ -104,8 +102,8 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { binding.buttonToWebview.setOnClickListener( v -> { SplunkRum.getInstance() - .addRumEvent("this span will be ignored", Attributes.empty()); - emitEvent(SplunkRum.getInstance(), "SecondFragment", "toWebViewClick"); + .emitEvent("this span will be ignored", Attributes.empty()); + emitEvent(SplunkRum.getInstance(), "SecondFragment.toWebViewClick"); NavHostFragment.findNavController(SecondFragment.this) .navigate(R.id.action_SecondFragment_to_webViewFragment); @@ -221,11 +219,7 @@ private void createSpamSpan() { updateLabel(); } - public static void emitEvent(SplunkRum splunkRum, String eventDomain, String eventName) { - SdkEventLoggerProvider eventEmitterProvider = - SdkEventLoggerProvider.create( - ((OpenTelemetrySdk) splunkRum.getOpenTelemetry()).getSdkLoggerProvider()); - EventLogger eventLogger = eventEmitterProvider.eventLoggerBuilder("test").build(); - eventLogger.builder(eventName).emit(); + public static void emitEvent(SplunkRum splunkRum, String eventName) { + splunkRum.emitEvent(eventName, Attributes.empty()); } } diff --git a/sample-app/src/main/java/com/splunk/android/sample/WebViewFragment.java b/sample-app/src/main/java/com/splunk/android/sample/WebViewFragment.java index f5973002..b9d95a24 100644 --- a/sample-app/src/main/java/com/splunk/android/sample/WebViewFragment.java +++ b/sample-app/src/main/java/com/splunk/android/sample/WebViewFragment.java @@ -98,7 +98,7 @@ public WebAppInterface(Context context) { @JavascriptInterface public void showToast(String toast) { - SplunkRum.getInstance().addRumEvent("WebViewButtonClicked", Attributes.empty()); + SplunkRum.getInstance().emitEvent("WebViewButtonClicked", Attributes.empty()); Toast.makeText(context, toast, Toast.LENGTH_LONG).show(); } diff --git a/splunk-otel-android-volley/build.gradle.kts b/splunk-otel-android-volley/build.gradle.kts index daef9d14..142666f1 100644 --- a/splunk-otel-android-volley/build.gradle.kts +++ b/splunk-otel-android-volley/build.gradle.kts @@ -51,6 +51,7 @@ dependencies { compileOnly(libs.opentelemetry.api) implementation(libs.opentelemetry.instrumenter.api) implementation(libs.opentelemetry.instrumenter.api.incubator) + implementation(libs.opentelemetry.semconv.incubating) compileOnly(libs.android.volley) implementation(libs.androidx.core) testImplementation(libs.mockwebserver) diff --git a/splunk-otel-android/build.gradle.kts b/splunk-otel-android/build.gradle.kts index 3c23e6e1..ba3ce209 100644 --- a/splunk-otel-android/build.gradle.kts +++ b/splunk-otel-android/build.gradle.kts @@ -45,6 +45,7 @@ dependencies { api(libs.opentelemetry.android.agent) implementation(libs.opentelemetry.sdk) + implementation(libs.opentelemetry.api.incubator) implementation(libs.opentelemetry.instrumentation.okhttp) implementation(libs.opentelemetry.exporter.zipkin) implementation(libs.opentelemetry.exporter.otlp) diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/DiskToZipkinExporter.java b/splunk-otel-android/src/main/java/com/splunk/rum/DiskToZipkinExporter.java deleted file mode 100644 index 58214e5b..00000000 --- a/splunk-otel-android/src/main/java/com/splunk/rum/DiskToZipkinExporter.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * 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. - */ - -package com.splunk.rum; - -import static com.splunk.rum.SplunkRum.LOG_TAG; -import static java.util.Collections.emptyList; -import static java.util.Objects.requireNonNull; - -import android.util.Log; -import androidx.annotation.Nullable; -import io.opentelemetry.android.instrumentation.network.CurrentNetworkProvider; -import java.io.File; -import java.util.Comparator; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -/** - * An exporter that pulls pre-encoded zipkin spans from storage and sends them via a sender. It is - * bandwidth sensitive and will throttle back if the limit is exceeded. - */ -class DiskToZipkinExporter { - - static final double DEFAULT_MAX_UNCOMPRESSED_BANDWIDTH = 15.0 * 1024; - - private final ScheduledExecutorService threadPool; - private final CurrentNetworkProvider currentNetworkProvider; - private final FileSender fileSender; - private final SpanStorage spanStorage; - private final BandwidthTracker bandwidthTracker; - private final double bandwidthLimit; - - DiskToZipkinExporter(Builder builder) { - this.threadPool = builder.threadPool; - this.currentNetworkProvider = requireNonNull(builder.currentNetworkProvider); - this.fileSender = requireNonNull(builder.fileSender); - this.spanStorage = requireNonNull(builder.spanStorage); - this.bandwidthTracker = requireNonNull(builder.bandwidthTracker); - this.bandwidthLimit = builder.bandwidthLimit; - } - - // the returned future is very unlikely to fail - @SuppressWarnings("FutureReturnValueIgnored") - void startPolling() { - threadPool.scheduleWithFixedDelay(this::doExportCycle, 5, 5, TimeUnit.SECONDS); - } - - // Visible for testing - void doExportCycle() { - try { - exportPendingFiles(); - } catch (Exception e) { - Log.w(LOG_TAG, "Error processing on-disk files", e); - } - } - - private void exportPendingFiles() { - if (!currentNetworkProvider.refreshNetworkStatus().isOnline()) { - Log.i( - SplunkRum.LOG_TAG, - "Network offline, leaving spans on disk for for eventual export."); - return; - } - - List pendingFiles = getPendingFiles(); - boolean sentAnything = false; - for (File file : pendingFiles) { - - double sustainedRate = bandwidthTracker.totalSustainedRate(); - if (sustainedRate > bandwidthLimit) { - Log.i( - SplunkRum.LOG_TAG, - String.format( - "Export rate %.2f exceeds limit of %.2f, backing off", - sustainedRate, bandwidthLimit)); - break; - } - - boolean dataWasSent = fileSender.handleFileOnDisk(file); - sentAnything |= dataWasSent; - if (!dataWasSent) { // Don't bother trying any remaining files if this one failed. - break; - } - } - if (!sentAnything) { - bandwidthTracker.tick(emptyList()); - } - } - - private List getPendingFiles() { - return spanStorage - .getPendingFiles() - .sorted(Comparator.comparing(File::getName)) - .collect(Collectors.toList()); - } - - void stop() { - threadPool.shutdown(); - } - - static Builder builder() { - return new Builder(); - } - - static class Builder { - @Nullable private FileSender fileSender; - @Nullable private BandwidthTracker bandwidthTracker; - private ScheduledExecutorService threadPool = Executors.newSingleThreadScheduledExecutor(); - @Nullable private CurrentNetworkProvider currentNetworkProvider; - @Nullable private SpanStorage spanStorage; - private double bandwidthLimit = DEFAULT_MAX_UNCOMPRESSED_BANDWIDTH; - - Builder threadPool(ScheduledExecutorService threadPool) { - this.threadPool = threadPool; - return this; - } - - Builder connectionUtil(CurrentNetworkProvider currentNetworkProvider) { - this.currentNetworkProvider = currentNetworkProvider; - return this; - } - - Builder bandwidthTracker(BandwidthTracker bandwidthTracker) { - this.bandwidthTracker = bandwidthTracker; - return this; - } - - Builder fileSender(FileSender fileSender) { - this.fileSender = fileSender; - return this; - } - - Builder bandwidthLimit(double limit) { - this.bandwidthLimit = limit; - return this; - } - - Builder spanFileProvider(SpanStorage spanStorage) { - this.spanStorage = spanStorage; - return this; - } - - DiskToZipkinExporter build() { - return new DiskToZipkinExporter(this); - } - } -} diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/InitializationEvents.java b/splunk-otel-android/src/main/java/com/splunk/rum/InitializationEvents.java index b95626f5..a3629ec3 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/InitializationEvents.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/InitializationEvents.java @@ -19,7 +19,7 @@ import static com.splunk.rum.SplunkRum.COMPONENT_APPSTART; import static com.splunk.rum.SplunkRum.COMPONENT_KEY; -import io.opentelemetry.android.instrumentation.startup.AppStartupTimer; +import io.opentelemetry.android.instrumentation.activity.startup.AppStartupTimer; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Context; @@ -27,6 +27,8 @@ import java.util.List; import java.util.concurrent.TimeUnit; +// TODO: See if we can remove this in favor of upstream InitializationEvents +// might need to map the events back to spans tho... class InitializationEvents { private final AppStartupTimer startupTimer; private final List events = new ArrayList<>(); diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/MemoryBufferingExporter.java b/splunk-otel-android/src/main/java/com/splunk/rum/MemoryBufferingExporter.java deleted file mode 100644 index b88b93c5..00000000 --- a/splunk-otel-android/src/main/java/com/splunk/rum/MemoryBufferingExporter.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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. - */ - -package com.splunk.rum; - -import android.util.Log; -import androidx.annotation.NonNull; -import io.opentelemetry.android.instrumentation.network.CurrentNetworkProvider; -import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.trace.data.SpanData; -import io.opentelemetry.sdk.trace.export.SpanExporter; -import java.util.Collection; -import java.util.List; - -class MemoryBufferingExporter implements SpanExporter { - - private static final int MAX_BACKLOG_SIZE = 100; - private final CurrentNetworkProvider currentNetworkProvider; - private final SpanExporter delegate; - - private final MemorySpanBuffer backlogProvider; - - MemoryBufferingExporter( - CurrentNetworkProvider currentNetworkProvider, - SpanExporter delegate, - MemorySpanBuffer backlogProvider) { - this.currentNetworkProvider = currentNetworkProvider; - this.delegate = delegate; - this.backlogProvider = backlogProvider; - } - - @Override - public CompletableResultCode export(Collection spans) { - backlogProvider.addAll(spans); - if (!currentNetworkProvider.refreshNetworkStatus().isOnline()) { - Log.i( - SplunkRum.LOG_TAG, - "Network offline, buffering " + spans.size() + " spans for eventual export."); - return CompletableResultCode.ofSuccess(); - } - List toExport = fillFromBacklog(); - Log.d(SplunkRum.LOG_TAG, "Sending " + toExport.size() + " spans for export"); - CompletableResultCode exportResult = delegate.export(toExport); - exportResult.whenComplete( - () -> { - if (exportResult.isSuccess()) { - return; - } - Log.i( - SplunkRum.LOG_TAG, - "Export failed. adding " + toExport.size() + " spans to the backlog"); - addFailedSpansToBacklog(toExport); - }); - return exportResult; - } - - // todo Should we favor saving certain kinds of span if we're out of space? Or favor recency? - private void addFailedSpansToBacklog(List toExport) { - for (SpanData spanData : toExport) { - if (backlogProvider.size() < MAX_BACKLOG_SIZE) { - backlogProvider.addFailedSpansToBacklog(spanData); - } - } - } - - @NonNull - private List fillFromBacklog() { - return backlogProvider.drain(); - } - - @Override - public CompletableResultCode flush() { - if (!backlogProvider.isEmpty()) { - // note: the zipkin exporter has a no-op flush() method, so no need to call it after - // this. - return export(fillFromBacklog()); - } - return delegate.flush(); - } - - @Override - public CompletableResultCode shutdown() { - backlogProvider.clear(); - return delegate.shutdown(); - } -} diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/NoOpSplunkRum.java b/splunk-otel-android/src/main/java/com/splunk/rum/NoOpSplunkRum.java index 7ca8d176..e42a33f3 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/NoOpSplunkRum.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/NoOpSplunkRum.java @@ -61,7 +61,7 @@ public String getRumSessionId() { } @Override - public void addRumEvent(String name, Attributes attributes) { + public void emitEvent(String name, Attributes attributes) { // no-op } 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 8a2de716..1b7e4d99 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 @@ -23,54 +23,53 @@ import static com.splunk.rum.SplunkRum.COMPONENT_ERROR; import static com.splunk.rum.SplunkRum.COMPONENT_KEY; import static com.splunk.rum.SplunkRum.COMPONENT_UI; +import static com.splunk.rum.SplunkRum.LOG_TAG; import static com.splunk.rum.SplunkRum.RUM_TRACER_NAME; import static com.splunk.rum.SplunkRum.SPLUNK_OLLY_UUID_KEY; +import static java.util.Objects.requireNonNull; import static io.opentelemetry.android.common.RumConstants.APP_START_SPAN_NAME; import static io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor.constant; import static io.opentelemetry.semconv.incubating.DeploymentIncubatingAttributes.DEPLOYMENT_ENVIRONMENT; -import static java.util.Objects.requireNonNull; import android.app.Application; import android.os.Looper; +import android.util.Log; + import androidx.annotation.NonNull; -import androidx.annotation.Nullable; + import com.splunk.rum.internal.GlobalAttributesSupplier; import com.splunk.rum.internal.NoOpSpanExporter; import com.splunk.rum.internal.UInt32QuadXorTraceIdRatioSampler; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + 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.AndroidInstrumentationLoader; +import io.opentelemetry.android.instrumentation.activity.ActivityLifecycleInstrumentation; +import io.opentelemetry.android.instrumentation.activity.startup.AppStartupTimer; +import io.opentelemetry.android.instrumentation.anr.AnrInstrumentation; import io.opentelemetry.android.instrumentation.anr.AnrDetectorBuilder; -import io.opentelemetry.android.instrumentation.crash.CrashReporter; +import io.opentelemetry.android.instrumentation.crash.CrashReporterInstrumentation; +import io.opentelemetry.android.instrumentation.slowrendering.SlowRenderingInstrumentation; import io.opentelemetry.android.instrumentation.crash.CrashReporterBuilder; import io.opentelemetry.android.instrumentation.lifecycle.AndroidLifecycleInstrumentation; import io.opentelemetry.android.instrumentation.network.CurrentNetworkProvider; import io.opentelemetry.android.instrumentation.slowrendering.SlowRenderingDetector; import io.opentelemetry.android.instrumentation.startup.AppStartupTimer; -import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.android.internal.services.ServiceManager; +import io.opentelemetry.android.internal.services.network.CurrentNetworkProvider; +import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService; import io.opentelemetry.exporter.logging.LoggingSpanExporter; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; -import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter; -import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.resources.ResourceBuilder; import io.opentelemetry.sdk.trace.SpanLimits; -import io.opentelemetry.sdk.trace.data.SpanData; -import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; 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; class RumInitializer { @@ -92,7 +91,6 @@ class RumInitializer { } SplunkRum initialize(Looper mainLooper) { - VisibleScreenTracker visibleScreenTracker = new VisibleScreenTracker(); initializationEvents.begin(); @@ -112,28 +110,38 @@ SplunkRum initialize(Looper mainLooper) { otelRumBuilder.mergeResource(createSplunkResource()); initializationEvents.emit("resourceInitialized"); + ServiceManager.initialize(application); + ServiceManager serviceManager = ServiceManager.get(); + CurrentNetworkProvider currentNetworkProvider = serviceManager.getCurrentNetworkProvider(); + VisibleScreenService visibleScreenService = serviceManager.getVisibleScreenService(); + // TODO: now spelled rum.sdk.init.net.provider and currently mixed up in network // attributes enabled config in upstream -// CurrentNetworkProvider currentNetworkProvider = -// CurrentNetworkProvider.createAndStart(application); +//// CurrentNetworkProvider currentNetworkProvider = +//// CurrentNetworkProvider.create(application); +// currentNetworkProvider.start(); // otelRumBuilder.setCurrentNetworkProvider(currentNetworkProvider); -// initializationEvents.emit("connectionUtilInitialized"); + initializationEvents.emit("connectionUtilInitialized"); // TODO: How truly important is the order of these span processors? The location of event // generation should probably not be altered... - // Add batch span processor - otelRumBuilder.addTracerProviderCustomizer( - (tracerProviderBuilder, app) -> { - SpanExporter zipkinExporter = - buildFilteringExporter(currentNetworkProvider, visibleScreenTracker); - initializationEvents.emit("exporterInitialized"); - - BatchSpanProcessor batchSpanProcessor = - BatchSpanProcessor.builder(zipkinExporter).build(); - initializationEvents.emit("batchSpanProcessorInitialized"); - return tracerProviderBuilder.addSpanProcessor(batchSpanProcessor); - }); + // Get exporters going... + otelRumBuilder.addSpanExporterCustomizer(this::buildSpanExporter); +// otelRumBuilder.addLogRecordExporterCustomizer(xxx todo ); + +// // Add batch span processor +// otelRumBuilder.addTracerProviderCustomizer( +// (tracerProviderBuilder, app) -> { +// SpanExporter zipkinExporter = +// buildFilteringExporter(currentNetworkProvider, visibleScreenService); +// initializationEvents.emit("exporterInitialized"); +// +// BatchSpanProcessor batchSpanProcessor = +// BatchSpanProcessor.builder(zipkinExporter).build(); +// initializationEvents.emit("batchSpanProcessorInitialized"); +// return tracerProviderBuilder.addSpanProcessor(batchSpanProcessor); +// }); // Inhibit the upstream exporter because we add our own BatchSpanProcessor otelRumBuilder.addSpanExporterCustomizer(x -> new NoOpSpanExporter()); @@ -198,23 +206,23 @@ SplunkRum initialize(Looper mainLooper) { otelRum.getOpenTelemetry().getTracerProvider())); if (builder.isAnrDetectionEnabled()) { - installAnrDetector(otelRumBuilder, mainLooper); + configureAnrInstrumentation(); } if (builder.isSlowRenderingDetectionEnabled()) { - installSlowRenderingDetector(otelRumBuilder); + configureSlowRenderingInstrumentation(otelRumBuilder); } if (builder.isCrashReportingEnabled()) { - installCrashReporter(otelRumBuilder); + configureCrashReporter(otelRumBuilder); } SettableScreenAttributesAppender screenAttributesAppender = - new SettableScreenAttributesAppender(visibleScreenTracker); + new SettableScreenAttributesAppender(visibleScreenService); otelRumBuilder.addTracerProviderCustomizer( (tracerProviderBuilder, app) -> tracerProviderBuilder.addSpanProcessor(screenAttributesAppender)); // Lifecycle events instrumentation are always installed. - installLifecycleInstrumentations(otelRumBuilder, visibleScreenTracker); + configureLifecycleInstrumentations(); OpenTelemetryRum openTelemetryRum = otelRumBuilder.build(); @@ -228,19 +236,19 @@ SplunkRum initialize(Looper mainLooper) { } @NonNull - private MemorySpanBuffer constructBacklogProvider(VisibleScreenTracker visibleScreenTracker) { + private MemorySpanBuffer constructBacklogProvider(VisibleScreenService visibleScreenService) { if (builder.isBackgroundInstrumentationDeferredUntilForeground()) { - return new StartTypeAwareMemorySpanBuffer(visibleScreenTracker); + return new StartTypeAwareMemorySpanBuffer(visibleScreenService); } else { return new DefaultMemorySpanBuffer(); } } @NonNull - private SpanStorage constructSpanFileProvider(VisibleScreenTracker visibleScreenTracker) { + private SpanStorage constructSpanFileProvider(VisibleScreenService visibleScreenService) { if (builder.isBackgroundInstrumentationDeferredUntilForeground()) { return StartTypeAwareSpanStorage.create( - visibleScreenTracker, + visibleScreenService, new FileUtils(), application.getApplicationContext().getFilesDir()); } else { @@ -249,32 +257,23 @@ private SpanStorage constructSpanFileProvider(VisibleScreenTracker visibleScreen } } - private void installLifecycleInstrumentations( - OpenTelemetryRumBuilder otelRumBuilder, VisibleScreenTracker visibleScreenTracker) { - - otelRumBuilder.addInstrumentation( - instrumentedApp -> { - Function tracerCustomizer = - tracer -> - (Tracer) - spanName -> { - String component = - spanName.equals(APP_START_SPAN_NAME) - ? COMPONENT_APPSTART - : COMPONENT_UI; - return tracer.spanBuilder(spanName) - .setAttribute(COMPONENT_KEY, component); - }; - AndroidLifecycleInstrumentation instrumentation = - AndroidLifecycleInstrumentation.builder() - .setVisibleScreenTracker(visibleScreenTracker) - .setStartupTimer(startupTimer) - .setTracerCustomizer(tracerCustomizer) - .setScreenNameExtractor(SplunkScreenNameExtractor.INSTANCE) - .build(); - instrumentation.installOn(instrumentedApp); - initializationEvents.emit("activityLifecycleCallbacksInitialized"); + private void configureLifecycleInstrumentations() { + ActivityLifecycleInstrumentation instrumentation = AndroidInstrumentationLoader.getInstrumentation(ActivityLifecycleInstrumentation.class); + if(instrumentation == null){ + Log.w(LOG_TAG, "Activity rendering instrumentation was not loaded! Skipping configuration."); + return; + } + instrumentation.setTracerCustomizer(tracer -> + spanName -> { + String component = + spanName.equals(APP_START_SPAN_NAME) + ? COMPONENT_APPSTART + : COMPONENT_UI; + return tracer.spanBuilder(spanName) + .setAttribute(COMPONENT_KEY, component); }); + instrumentation.setScreenNameExtractor(SplunkScreenNameExtractor.INSTANCE); + initializationEvents.emit("activityLifecycleCallbacksInitialized"); } /** @@ -282,7 +281,6 @@ private void installLifecycleInstrumentations( * AndroidResource. */ private Resource createSplunkResource() { - // applicationName can't be null at this stage String applicationName = requireNonNull(builder.applicationName); ResourceBuilder resourceBuilder = Resource.builder().put(APP_NAME_KEY, applicationName); @@ -292,233 +290,229 @@ private Resource createSplunkResource() { return resourceBuilder.build(); } - private void installAnrDetector(OpenTelemetryRumBuilder otelRumBuilder, Looper mainLooper) { - otelRumBuilder.addInstrumentation( - instrumentedApplication -> { - ErrorIdentifierExtractor extractor = new ErrorIdentifierExtractor(application); - ErrorIdentifierInfo errorIdentifierInfo = extractor.extractInfo(); - String applicationId = errorIdentifierInfo.getApplicationId(); - String versionCode = errorIdentifierInfo.getVersionCode(); - String uuid = errorIdentifierInfo.getCustomUUID(); - - AnrDetectorBuilder builder = AnrDetector.builder(); - builder.addAttributesExtractor(constant(COMPONENT_KEY, COMPONENT_ERROR)); - - if (applicationId != null) - builder.addAttributesExtractor(constant(APPLICATION_ID_KEY, applicationId)); - if (versionCode != null) - builder.addAttributesExtractor(constant(APP_VERSION_CODE_KEY, versionCode)); - if (uuid != null) - builder.addAttributesExtractor(constant(SPLUNK_OLLY_UUID_KEY, uuid)); - - builder.setMainLooper(mainLooper).build().installOn(instrumentedApplication); - - initializationEvents.emit("anrMonitorInitialized"); - }); + private void configureAnrInstrumentation() { + AnrInstrumentation instrumentation = AndroidInstrumentationLoader.getInstrumentation(AnrInstrumentation.class); + if(instrumentation == null){ + Log.w(LOG_TAG, "ANR instrumentation was not loaded! Skipping configuration."); + return; + } + ErrorIdentifierExtractor extractor = new ErrorIdentifierExtractor(application); + ErrorIdentifierInfo errorIdentifierInfo = extractor.extractInfo(); + String applicationId = errorIdentifierInfo.getApplicationId(); + String versionCode = errorIdentifierInfo.getVersionCode(); + String uuid = errorIdentifierInfo.getCustomUUID(); + + instrumentation.addAttributesExtractor(constant(COMPONENT_KEY, COMPONENT_ERROR)); + + if (applicationId != null){ + instrumentation.addAttributesExtractor(constant(APPLICATION_ID_KEY, applicationId)); + } + if (versionCode != null){ + instrumentation.addAttributesExtractor(constant(APP_VERSION_CODE_KEY, versionCode)); + } + if (uuid != null){ + instrumentation.addAttributesExtractor(constant(SPLUNK_OLLY_UUID_KEY, uuid)); + } + + initializationEvents.emit("anrMonitorInitialized"); } - private void installCrashReporter(OpenTelemetryRumBuilder otelRumBuilder) { - otelRumBuilder.addInstrumentation( - (app,otelRum) -> { - ErrorIdentifierExtractor extractor = new ErrorIdentifierExtractor(application); - ErrorIdentifierInfo errorIdentifierInfo = extractor.extractInfo(); - String applicationId = errorIdentifierInfo.getApplicationId(); - String versionCode = errorIdentifierInfo.getVersionCode(); - String uuid = errorIdentifierInfo.getCustomUUID(); - - CrashReporterBuilder builder = CrashReporter.builder(); - builder.addAttributesExtractor( - RuntimeDetailsExtractor.create( - app.getApplicationContext())) - .addAttributesExtractor(new CrashComponentExtractor()); - - if (applicationId != null) - builder.addAttributesExtractor(constant(APPLICATION_ID_KEY, applicationId)); - if (versionCode != null) - builder.addAttributesExtractor(constant(APP_VERSION_CODE_KEY, versionCode)); - if (uuid != null) - builder.addAttributesExtractor(constant(SPLUNK_OLLY_UUID_KEY, uuid)); - - builder.build().installOn(instrumentedApplication); - - initializationEvents.emit("crashReportingInitialized"); - }); + private void configureSlowRenderingInstrumentation(OpenTelemetryRumBuilder otelRumBuilder) { + SlowRenderingInstrumentation instrumentation = AndroidInstrumentationLoader.getInstrumentation(SlowRenderingInstrumentation.class); + if(instrumentation == null){ + Log.w(LOG_TAG, "Slow rendering instrumentation was not loaded! Skipping configuration."); + return; + } + instrumentation.setSlowRenderingDetectionPollInterval(builder.slowRenderingDetectionPollInterval); + initializationEvents.emit("slowRenderingDetectorInitialized"); } - private void installSlowRenderingDetector(OpenTelemetryRumBuilder otelRumBuilder) { - otelRumBuilder.addInstrumentation( - instrumentedApplication -> { - SlowRenderingDetector.builder() - .setSlowRenderingDetectionPollInterval( - builder.slowRenderingDetectionPollInterval) - .build() - .installOn(app); - initializationEvents.emit("slowRenderingDetectorInitialized"); - }); + private void configureCrashReporter(OpenTelemetryRumBuilder otelRumBuilder) { + CrashReporterInstrumentation instrumentation = AndroidInstrumentationLoader.getInstrumentation(CrashReporterInstrumentation.class); + if(instrumentation == null){ + Log.w(LOG_TAG, "Crash reporter instrumentation was not loaded! Skipping configuration."); + return; + } + ErrorIdentifierExtractor extractor = new ErrorIdentifierExtractor(application); + ErrorIdentifierInfo errorIdentifierInfo = extractor.extractInfo(); + String applicationId = errorIdentifierInfo.getApplicationId(); + String versionCode = errorIdentifierInfo.getVersionCode(); + String uuid = errorIdentifierInfo.getCustomUUID(); + + instrumentation.addAttributesExtractor( + RuntimeDetailsExtractor.create( + app.getApplicationContext())) + .addAttributesExtractor(new CrashComponentExtractor()); + + if (applicationId != null){ + instrumentation.addAttributesExtractor(constant(APPLICATION_ID_KEY, applicationId)); + } + if (versionCode != null){ + instrumentation.addAttributesExtractor(constant(APP_VERSION_CODE_KEY, versionCode)); + } + if (uuid != null){ + instrumentation.addAttributesExtractor(constant(SPLUNK_OLLY_UUID_KEY, uuid)); + } + + initializationEvents.emit("crashReportingInitialized"); } // visible for testing - SpanExporter buildFilteringExporter( - CurrentNetworkProvider currentNetworkProvider, - VisibleScreenTracker visibleScreenTracker) { - SpanExporter exporter = buildExporter(currentNetworkProvider, visibleScreenTracker); + @NonNull + SpanExporter buildSpanExporter(SpanExporter delegate) { + OtlpHttpSpanExporter otlp = OtlpHttpSpanExporter.builder() + .setEndpoint(builder.beaconEndpoint) + .addHeader("X-SF-Token", builder.rumAccessToken) + .build(); SpanExporter splunkTranslatedExporter = new SplunkSpanDataModifier( - exporter, + otlp, builder.isReactNativeSupportEnabled(), - builder.shouldUseOtlpExporter()); + true); SpanExporter filteredExporter = builder.decorateWithSpanFilter(splunkTranslatedExporter); - initializationEvents.emit("zipkin exporter initialized"); + initializationEvents.emit("otlp span exporter initialized"); return filteredExporter; } - private SpanExporter buildExporter( - CurrentNetworkProvider currentNetworkProvider, - VisibleScreenTracker visibleScreenTracker) { - if (builder.isDebugEnabled()) { - // tell the Zipkin exporter to shut up already. We're on mobile, network stuff happens. - // we'll do our best to hang on to the spans with the wrapping BufferingExporter. - ZipkinSpanExporter.baseLogger.setLevel(Level.SEVERE); - initializationEvents.emit("logger setup complete"); - } - - if (builder.isDiskBufferingEnabled()) { - return buildStorageBufferingExporter( - currentNetworkProvider, constructSpanFileProvider(visibleScreenTracker)); - } - - return buildMemoryBufferingThrottledExporter( - currentNetworkProvider, constructBacklogProvider(visibleScreenTracker)); - } - - //TODO: Make this use OTLP buffering via upstream - private SpanExporter buildStorageBufferingExporter( - CurrentNetworkProvider currentNetworkProvider, SpanStorage spanStorage) { - Sender sender = buildCustomizedZipkinSender(); - - BandwidthTracker bandwidthTracker = new BandwidthTracker(); - - FileSender fileSender = - FileSender.builder().sender(sender).bandwidthTracker(bandwidthTracker).build(); - DiskToZipkinExporter diskToZipkinExporter = - DiskToZipkinExporter.builder() - .connectionUtil(currentNetworkProvider) - .fileSender(fileSender) - .bandwidthTracker(bandwidthTracker) - .spanFileProvider(spanStorage) - .build(); - diskToZipkinExporter.startPolling(); - - return getToDiskExporter(spanStorage); - } - - @NonNull - private Sender buildCustomizedZipkinSender() { - OkHttpSender.Builder okBuilder = - OkHttpSender.newBuilder().endpoint(getEndpointWithAuthTokenQueryParam()); - builder.httpSenderCustomizer.customize(okBuilder); - return okBuilder.build(); - } +// +// private SpanExporter buildExporter( +// CurrentNetworkProvider currentNetworkProvider, +// VisibleScreenService visibleScreenService) { +// xxxx +// if (builder.isDebugEnabled()) { +// // tell the Zipkin exporter to shut up already. We're on mobile, network stuff happens. +// // we'll do our best to hang on to the spans with the wrapping BufferingExporter. +// ZipkinSpanExporter.baseLogger.setLevel(Level.SEVERE); +// initializationEvents.emit("logger setup complete"); +// } +// +// if (builder.isDiskBufferingEnabled()) { +// return buildStorageBufferingExporter( +// currentNetworkProvider, constructSpanFileProvider(visibleScreenService)); +// } +// +// return buildMemoryBufferingThrottledExporter( +// currentNetworkProvider, constructBacklogProvider(visibleScreenService)); +// } +// +// //TODO: Make this use OTLP buffering via upstream +// private SpanExporter buildStorageBufferingExporter( +// CurrentNetworkProvider currentNetworkProvider, SpanStorage spanStorage) { +// Sender sender = buildCustomizedZipkinSender(); +// +// BandwidthTracker bandwidthTracker = new BandwidthTracker(); +// +// FileSender fileSender = +// FileSender.builder().sender(sender).bandwidthTracker(bandwidthTracker).build(); +// DiskToZipkinExporter diskToZipkinExporter = +// DiskToZipkinExporter.builder() +// .connectionUtil(currentNetworkProvider) +// .fileSender(fileSender) +// .bandwidthTracker(bandwidthTracker) +// .spanFileProvider(spanStorage) +// .build(); +// diskToZipkinExporter.startPolling(); +// +// return getToDiskExporter(spanStorage); +// } +// +// @NonNull +// private Sender buildCustomizedZipkinSender() { +// OkHttpSender.Builder okBuilder = +// OkHttpSender.newBuilder().endpoint(getEndpointWithAuthTokenQueryParam()); +// builder.httpSenderCustomizer.customize(okBuilder); +// return okBuilder.build(); +// } @NonNull private String getEndpointWithAuthTokenQueryParam() { return builder.beaconEndpoint + "?auth=" + builder.rumAccessToken; } - private SpanExporter buildMemoryBufferingThrottledExporter( - CurrentNetworkProvider currentNetworkProvider, MemorySpanBuffer backlogProvider) { - SpanExporter zipkinSpanExporter = getCoreSpanExporter(); - MemoryBufferingExporter memoryBufferingExporter = - new MemoryBufferingExporter( - currentNetworkProvider, zipkinSpanExporter, backlogProvider); - return buildThrottlingExporter(memoryBufferingExporter); - } - - private static ThrottlingExporter buildThrottlingExporter( - MemoryBufferingExporter memoryBufferingExporter) { - return ThrottlingExporter.newBuilder(memoryBufferingExporter) - .categorizeByAttribute(COMPONENT_KEY) - .maxSpansInWindow(100) - .windowSize(Duration.ofSeconds(30)) - .build(); - } - - SpanExporter getToDiskExporter(SpanStorage spanStorage) { - return new LazyInitSpanExporter( - () -> - ZipkinWriteToDiskExporterFactory.create( - builder.maxUsageMegabytes, spanStorage)); - } - - // visible for testing - SpanExporter getCoreSpanExporter() { - Supplier exporterSupplier = supplyZipkinExporter(); - if (builder.shouldUseOtlpExporter()) { - exporterSupplier = supplyOtlpExporter(); - } - // return a lazy init exporter so the main thread doesn't block on the setup. - return new LazyInitSpanExporter(exporterSupplier); - } - - @NonNull - private Supplier supplyOtlpExporter() { - String endpoint = getEndpointWithAuthTokenQueryParam(); - return () -> - OtlpHttpSpanExporter.builder() - .setEndpoint(endpoint) - .addHeader("X-SF-Token", builder.rumAccessToken) - . - .build(); - } - - //TODO: This needs to go away as part of 2.0, OTLP only - @NonNull - private Supplier supplyZipkinExporter() { - String endpoint = getEndpointWithAuthTokenQueryParam(); - return () -> - ZipkinSpanExporter.builder() - .setEncoder(new CustomZipkinEncoder()) - .setEndpoint(endpoint) - // remove the local IP address - .setLocalIpAddressSupplier(() -> null) - .setSender(buildCustomizedZipkinSender()) - .build(); - } - - private static class LazyInitSpanExporter implements SpanExporter { - @Nullable private volatile SpanExporter delegate; - private final Supplier s; - - public LazyInitSpanExporter(Supplier s) { - this.s = s; - } - - private SpanExporter getDelegate() { - SpanExporter d = delegate; - if (d == null) { - synchronized (this) { - d = delegate; - if (d == null) { - delegate = d = s.get(); - } - } - } - return d; - } - - @Override - public CompletableResultCode export(Collection spans) { - return getDelegate().export(spans); - } - - @Override - public CompletableResultCode flush() { - return getDelegate().flush(); - } - - @Override - public CompletableResultCode shutdown() { - return getDelegate().shutdown(); - } - } +// private SpanExporter buildMemoryBufferingThrottledExporter( +// CurrentNetworkProvider currentNetworkProvider, MemorySpanBuffer backlogProvider) { +// SpanExporter zipkinSpanExporter = getCoreSpanExporter(); +// MemoryBufferingExporter memoryBufferingExporter = +// new MemoryBufferingExporter( +// currentNetworkProvider, zipkinSpanExporter, backlogProvider); +// return buildThrottlingExporter(memoryBufferingExporter); +// } + +// private static ThrottlingExporter buildThrottlingExporter( +// MemoryBufferingExporter memoryBufferingExporter) { +// return ThrottlingExporter.newBuilder(memoryBufferingExporter) +// .categorizeByAttribute(COMPONENT_KEY) +// .maxSpansInWindow(100) +// .windowSize(Duration.ofSeconds(30)) +// .build(); +// } + +// SpanExporter getToDiskExporter(SpanStorage spanStorage) { +// return new LazyInitSpanExporter( +// () -> +// ZipkinWriteToDiskExporterFactory.create( +// builder.maxUsageMegabytes, spanStorage)); +// } +// +// // visible for testing +// SpanExporter getCoreSpanExporter() { +// Supplier exporterSupplier = supplyZipkinExporter(); +// if (builder.shouldUseOtlpExporter()) { +// exporterSupplier = supplyOtlpExporter(); +// } +// // return a lazy init exporter so the main thread doesn't block on the setup. +// return new LazyInitSpanExporter(exporterSupplier); +// } + +// +// //TODO: This needs to go away as part of 2.0, OTLP only +// @NonNull +// private Supplier supplyZipkinExporter() { +// String endpoint = getEndpointWithAuthTokenQueryParam(); +// return () -> +// ZipkinSpanExporter.builder() +// .setEncoder(new CustomZipkinEncoder()) +// .setEndpoint(endpoint) +// // remove the local IP address +// .setLocalIpAddressSupplier(() -> null) +// .setSender(buildCustomizedZipkinSender()) +// .build(); +// } +// +// private static class LazyInitSpanExporter implements SpanExporter { +// @Nullable private volatile SpanExporter delegate; +// private final Supplier s; +// +// public LazyInitSpanExporter(Supplier s) { +// this.s = s; +// } +// +// private SpanExporter getDelegate() { +// SpanExporter d = delegate; +// if (d == null) { +// synchronized (this) { +// d = delegate; +// if (d == null) { +// delegate = d = s.get(); +// } +// } +// } +// return d; +// } +// +// @Override +// public CompletableResultCode export(Collection spans) { +// return getDelegate().export(spans); +// } +// +// @Override +// public CompletableResultCode flush() { +// return getDelegate().flush(); +// } +// +// @Override +// public CompletableResultCode shutdown() { +// return getDelegate().shutdown(); +// } +// } } diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/RumScreenName.java b/splunk-otel-android/src/main/java/com/splunk/rum/RumScreenName.java deleted file mode 100644 index ab28a020..00000000 --- a/splunk-otel-android/src/main/java/com/splunk/rum/RumScreenName.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - */ - -package com.splunk.rum; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * This annotation can be used to customize the {@code screen.name} attribute for an instrumented - * Fragment or Activity. @Deprecated RumScreenName moved to - * io.opentelemetry.rum.internal.instrumentation package - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface RumScreenName { - /** Return the customized screen name. */ - String value(); -} diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/ScreenAttributesAppender.java b/splunk-otel-android/src/main/java/com/splunk/rum/ScreenAttributesAppender.java deleted file mode 100644 index 2b9ec6f8..00000000 --- a/splunk-otel-android/src/main/java/com/splunk/rum/ScreenAttributesAppender.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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. - */ - -package com.splunk.rum; - -import static io.opentelemetry.android.common.RumConstants.SCREEN_NAME_KEY; - -import io.opentelemetry.android.instrumentation.activity.VisibleScreenTracker; -import io.opentelemetry.context.Context; -import io.opentelemetry.sdk.trace.ReadWriteSpan; -import io.opentelemetry.sdk.trace.ReadableSpan; -import io.opentelemetry.sdk.trace.SpanProcessor; - -class ScreenAttributesAppender implements SpanProcessor { - - private final VisibleScreenTracker visibleScreenTracker; - - ScreenAttributesAppender(VisibleScreenTracker visibleScreenTracker) { - this.visibleScreenTracker = visibleScreenTracker; - } - - @Override - public void onStart(Context parentContext, ReadWriteSpan span) { - String currentScreen = visibleScreenTracker.getCurrentlyVisibleScreen(); - span.setAttribute(SCREEN_NAME_KEY, currentScreen); - } - - @Override - public boolean isStartRequired() { - return true; - } - - @Override - public void onEnd(ReadableSpan span) {} - - @Override - public boolean isEndRequired() { - return false; - } -} 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 84eaec05..940ea65c 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 @@ -28,17 +28,21 @@ import androidx.annotation.Nullable; import com.splunk.rum.internal.GlobalAttributesSupplier; import io.opentelemetry.android.OpenTelemetryRum; -import io.opentelemetry.android.instrumentation.startup.AppStartupTimer; +import io.opentelemetry.android.instrumentation.activity.startup.AppStartupTimer; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.api.incubator.events.EventLogger; +import io.opentelemetry.api.logs.LoggerProvider; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.instrumentation.okhttp.v3_0.OkHttpTelemetry; import io.opentelemetry.sdk.OpenTelemetrySdk; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; + +import io.opentelemetry.sdk.logs.internal.SdkEventLoggerProvider; import okhttp3.Call; import okhttp3.OkHttpClient; @@ -184,7 +188,7 @@ public Call.Factory createRumOkHttpCallFactory(OkHttpClient client) { private OkHttpTelemetry createOkHttpTracing() { return OkHttpTelemetry.builder(getOpenTelemetry()) - .addAttributesExtractor( + .addAttributeExtractor( new RumResponseAttributesExtractor(new ServerTimingHeaderParser())) .build(); } @@ -207,19 +211,28 @@ public String getRumSessionId() { } /** - * Add a custom event to RUM monitoring. This can be useful to capture business events, or + * Emits a custom event to RUM monitoring. This can be useful to capture business events, or * simply add instrumentation to your application. * - *

This event will be turned into a Span and sent to the RUM ingest along with other, - * auto-generated spans. + *

This event will be sent to the RUM ingest along with other, auto-generated spans and events. * * @param name The name of the event. * @param attributes Any {@link Attributes} to associate with the event. */ - public void addRumEvent(String name, Attributes attributes) { - getTracer().spanBuilder(name).setAllAttributes(attributes).startSpan().end(); + public void emitEvent(String name, Attributes attributes) { + String instrumentationScope = "TODO: Fixme to something legit"; + emitEvent(name, instrumentationScope, attributes); } + public void emitEvent(String name, String instrumentationScope, Attributes attributes) { + LoggerProvider loggerProvider = openTelemetryRum.getOpenTelemetry().getLogsBridge(); + EventLogger eventLogger = SdkEventLoggerProvider.create(loggerProvider) + .get(instrumentationScope); + eventLogger.builder(name).setAttributes(attributes).emit(); + } + + //TODO: Allow emitEvent() with a custom Body + /** * Start a Span to time a named workflow. * diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkScreenNameExtractor.java b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkScreenNameExtractor.java index 0b5728bf..e2d5042b 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkScreenNameExtractor.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkScreenNameExtractor.java @@ -18,9 +18,11 @@ import android.app.Activity; import androidx.fragment.app.Fragment; -import io.opentelemetry.android.instrumentation.ScreenNameExtractor; import java.util.function.Function; +import io.opentelemetry.android.instrumentation.annotations.RumScreenName; +import io.opentelemetry.android.instrumentation.common.ScreenNameExtractor; + /** * Screen name extractor that supports the original Splunk annotation but falls back to * OpenTelemetry defaults when not present. diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/StartTypeAwareMemorySpanBuffer.java b/splunk-otel-android/src/main/java/com/splunk/rum/StartTypeAwareMemorySpanBuffer.java index 3bd03f15..e1af2a33 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/StartTypeAwareMemorySpanBuffer.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/StartTypeAwareMemorySpanBuffer.java @@ -16,17 +16,18 @@ package com.splunk.rum; -import io.opentelemetry.android.instrumentation.activity.VisibleScreenTracker; -import io.opentelemetry.sdk.trace.data.SpanData; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Queue; +import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService; +import io.opentelemetry.sdk.trace.data.SpanData; + public class StartTypeAwareMemorySpanBuffer implements MemorySpanBuffer { - private final VisibleScreenTracker visibleScreenTracker; + private final VisibleScreenService visibleScreenTracker; private final Queue backlog = new ArrayDeque<>(); @@ -35,7 +36,7 @@ public class StartTypeAwareMemorySpanBuffer implements MemorySpanBuffer { */ private final Queue backgroundSpanBacklog = new ArrayDeque<>(); - public StartTypeAwareMemorySpanBuffer(VisibleScreenTracker visibleScreenTracker) { + public StartTypeAwareMemorySpanBuffer(VisibleScreenService visibleScreenTracker) { this.visibleScreenTracker = visibleScreenTracker; } diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/StartTypeAwareSpanStorage.java b/splunk-otel-android/src/main/java/com/splunk/rum/StartTypeAwareSpanStorage.java index 4b3de32c..6a2fe59f 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/StartTypeAwareSpanStorage.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/StartTypeAwareSpanStorage.java @@ -19,12 +19,15 @@ import static com.splunk.rum.SplunkRum.LOG_TAG; import android.util.Log; + import androidx.annotation.VisibleForTesting; -import io.opentelemetry.android.instrumentation.activity.VisibleScreenTracker; + import java.io.File; import java.util.UUID; import java.util.stream.Stream; +import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService; + /*** * Store span files to /span/background/@uniqueId/ for spans created when the app started in the background. * If the app is brought to foreground and the same session ID still in use, the background spans are moved to /span for eventual sending. @@ -32,41 +35,41 @@ */ class StartTypeAwareSpanStorage implements SpanStorage { - private final VisibleScreenTracker visibleScreenTracker; + private final VisibleScreenService visibleScreenService; private final FileUtils fileUtils; private final String uniqueId; private final File rootDir; private final File spanDir; static StartTypeAwareSpanStorage create( - VisibleScreenTracker visibleScreenTracker, FileUtils fileUtils, File rootDir) { + VisibleScreenService visibleScreenService, FileUtils fileUtils, File rootDir) { File spansDir = fileUtils.getSpansDirectory(rootDir); String uniqueId = UUID.randomUUID().toString(); - return create(visibleScreenTracker, fileUtils, rootDir, spansDir, uniqueId); + return create(visibleScreenService, fileUtils, rootDir, spansDir, uniqueId); } @VisibleForTesting static StartTypeAwareSpanStorage create( - VisibleScreenTracker visibleScreenTracker, + VisibleScreenService visibleScreenService, FileUtils fileUtils, File rootDir, File spansDir, String uniqueId) { StartTypeAwareSpanStorage startTypeAwareSpanStorage = new StartTypeAwareSpanStorage( - visibleScreenTracker, fileUtils, rootDir, spansDir, uniqueId); + visibleScreenService, fileUtils, rootDir, spansDir, uniqueId); startTypeAwareSpanStorage.cleanupUnsentBackgroundSpans(); return startTypeAwareSpanStorage; } @VisibleForTesting StartTypeAwareSpanStorage( - VisibleScreenTracker visibleScreenTracker, + VisibleScreenService visibleScreenService, FileUtils fileUtils, File rootDir, File spansDir, String uniqueId) { - this.visibleScreenTracker = visibleScreenTracker; + this.visibleScreenService = visibleScreenService; this.fileUtils = fileUtils; this.rootDir = rootDir; this.spanDir = spansDir; @@ -92,9 +95,9 @@ public Stream getPendingFiles() { } private boolean isAppForeground() { - return (visibleScreenTracker.getCurrentlyVisibleScreen() != null - && !visibleScreenTracker.getCurrentlyVisibleScreen().equals("unknown")) - || visibleScreenTracker.getPreviouslyVisibleScreen() != null; + return (visibleScreenService.getCurrentlyVisibleScreen() != null + && !visibleScreenService.getCurrentlyVisibleScreen().equals("unknown")) + || visibleScreenService.getPreviouslyVisibleScreen() != null; } private void moveBackgroundSpanToPendingSpan() { diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/DiskToZipkinExporterTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/DiskToZipkinExporterTest.java deleted file mode 100644 index 1dda3cba..00000000 --- a/splunk-otel-android/src/test/java/com/splunk/rum/DiskToZipkinExporterTest.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * 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. - */ - -package com.splunk.rum; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import io.opentelemetry.android.instrumentation.network.CurrentNetwork; -import io.opentelemetry.android.instrumentation.network.CurrentNetworkProvider; -import java.io.File; -import java.util.stream.Stream; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -class DiskToZipkinExporterTest { - - static final int BANDWIDTH_LIMIT = 20 * 1024; - static final File spanFilesPath = new File("/path/to/thing"); - static final SpanStorage SPAN_STORAGE = mock(SpanStorage.class); - private File file1 = null; - private File file2 = null; - private File imposter = null; - - @Mock private CurrentNetworkProvider currentNetworkProvider; - @Mock private FileUtils fileUtils; - @Mock private CurrentNetwork currentNetwork; - @Mock FileSender sender; - @Mock private BandwidthTracker bandwidthTracker; - - @BeforeEach - void setup() throws Exception { - Mockito.reset(SPAN_STORAGE); - when(SPAN_STORAGE.provideSpansDirectory()).thenReturn(spanFilesPath); - file1 = new File(SPAN_STORAGE.provideSpansDirectory() + File.separator + "file1.spans"); - file2 = new File(SPAN_STORAGE.provideSpansDirectory() + File.separator + "file2.spans"); - imposter = - new File( - SPAN_STORAGE.provideSpansDirectory() - + File.separator - + "someImposterFile.dll"); - - when(currentNetworkProvider.refreshNetworkStatus()).thenReturn(currentNetwork); - when(currentNetwork.isOnline()).thenReturn(true); - Stream files = Stream.of(file1, imposter, file2); - when(SPAN_STORAGE.getPendingFiles()).thenReturn(files); - } - - @Test - void testHappyPathExport() { - when(sender.handleFileOnDisk(file1)).thenReturn(true); - when(sender.handleFileOnDisk(file2)).thenReturn(true); - - DiskToZipkinExporter exporter = buildExporter(); - - exporter.doExportCycle(); - verify(sender).handleFileOnDisk(file1); - verify(sender).handleFileOnDisk(file2); - verify(bandwidthTracker, never()).tick(anyList()); - } - - @Test - void fileFailureSkipsSubsequentFiles() { - - when(sender.handleFileOnDisk(file1)).thenReturn(false); - - DiskToZipkinExporter exporter = buildExporter(); - - exporter.doExportCycle(); - - verify(sender).handleFileOnDisk(file1); - verify(sender, never()).handleFileOnDisk(file2); - } - - @Test - void testSkipsWhenOffline() { - Mockito.reset(SPAN_STORAGE); - when(currentNetwork.isOnline()).thenReturn(false); - - DiskToZipkinExporter exporter = buildExporter(); - - exporter.doExportCycle(); - - verifyNoMoreInteractions(SPAN_STORAGE); - verifyNoMoreInteractions(sender); - } - - @Test - void testSkipsWhenOverBandwidth() { - when(bandwidthTracker.totalSustainedRate()).thenReturn(BANDWIDTH_LIMIT + 1.0); - - DiskToZipkinExporter exporter = buildExporter(); - - exporter.doExportCycle(); - - verify(sender, never()).handleFileOnDisk(any()); - } - - @Test - void testOtherExceptionsHandled() { - when(SPAN_STORAGE.getPendingFiles()).thenThrow(new RuntimeException("unexpected!")); - DiskToZipkinExporter exporter = buildExporter(); - - exporter.doExportCycle(); - verify(sender, never()).handleFileOnDisk(any()); - } - - private DiskToZipkinExporter buildExporter() { - return DiskToZipkinExporter.builder() - .fileSender(sender) - .bandwidthLimit(BANDWIDTH_LIMIT) - .bandwidthTracker(bandwidthTracker) - .spanFileProvider(SPAN_STORAGE) - .connectionUtil(currentNetworkProvider) - .build(); - } -} diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/MemoryBufferingExporterTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/MemoryBufferingExporterTest.java deleted file mode 100644 index 82071bcd..00000000 --- a/splunk-otel-android/src/test/java/com/splunk/rum/MemoryBufferingExporterTest.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * 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. - */ - -package com.splunk.rum; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.opentelemetry.android.instrumentation.network.CurrentNetwork; -import io.opentelemetry.android.instrumentation.network.CurrentNetworkProvider; -import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.trace.data.SpanData; -import io.opentelemetry.sdk.trace.export.SpanExporter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; - -class MemoryBufferingExporterTest { - private final CurrentNetworkProvider currentNetworkProvider = - mock(CurrentNetworkProvider.class); - private final CurrentNetwork currentNetwork = mock(CurrentNetwork.class); - - private final MemorySpanBuffer backlogProvider = mock(MemorySpanBuffer.class); - - @BeforeEach - void setUp() { - when(currentNetworkProvider.refreshNetworkStatus()).thenReturn(currentNetwork); - } - - @Test - void happyPath() { - List spans = Arrays.asList(mock(SpanData.class), mock(SpanData.class)); - when(currentNetwork.isOnline()).thenReturn(true); - when(backlogProvider.drain()).thenReturn(spans); - - SpanExporter delegate = mock(SpanExporter.class); - MemoryBufferingExporter bufferingExporter = - new MemoryBufferingExporter(currentNetworkProvider, delegate, backlogProvider); - - when(delegate.export(spans)).thenReturn(CompletableResultCode.ofSuccess()); - - CompletableResultCode result = bufferingExporter.export(spans); - assertTrue(result.isSuccess()); - } - - @Test - void offlinePath() { - when(currentNetwork.isOnline()).thenReturn(false, true); - List spans = Arrays.asList(mock(SpanData.class), mock(SpanData.class)); - List secondBatch = new ArrayList<>(spans); - SpanData anotherSpan = mock(SpanData.class); - secondBatch.add(anotherSpan); - when(backlogProvider.drain()).thenReturn(secondBatch); - - SpanExporter delegate = mock(SpanExporter.class); - MemoryBufferingExporter bufferingExporter = - new MemoryBufferingExporter(currentNetworkProvider, delegate, backlogProvider); - - CompletableResultCode result = bufferingExporter.export(spans); - assertTrue(result.isSuccess()); - verify(delegate, never()).export(any()); - - when(delegate.export(secondBatch)).thenReturn(CompletableResultCode.ofSuccess()); - - // send another span now that we're back online. - result = bufferingExporter.export(secondBatch); - - assertTrue(result.isSuccess()); - verify(delegate).export(secondBatch); - } - - @Test - void retryPath() { - SpanData one = mock(SpanData.class); - SpanData two = mock(SpanData.class); - SpanData three = mock(SpanData.class); - List spans = Arrays.asList(one, two); - List secondSpans = Arrays.asList(one, two, three); - when(backlogProvider.drain()).thenReturn(spans, secondSpans); - when(currentNetwork.isOnline()).thenReturn(true); - - SpanExporter delegate = mock(SpanExporter.class); - MemoryBufferingExporter bufferingExporter = - new MemoryBufferingExporter(currentNetworkProvider, delegate, backlogProvider); - - when(delegate.export(spans)).thenReturn(CompletableResultCode.ofFailure()); - when(delegate.export(secondSpans)).thenReturn(CompletableResultCode.ofSuccess()); - - CompletableResultCode firstResult = bufferingExporter.export(spans); - assertFalse(firstResult.isSuccess()); - - CompletableResultCode secondResult = - bufferingExporter.export(Collections.singletonList(three)); - assertTrue(secondResult.isSuccess()); - } - - @Test - void flush_withBacklog() { - SpanData one = mock(SpanData.class); - SpanData two = mock(SpanData.class); - List spans = Arrays.asList(one, two); - when(backlogProvider.drain()).thenReturn(spans); - when(currentNetwork.isOnline()).thenReturn(true); - - SpanExporter delegate = mock(SpanExporter.class); - MemoryBufferingExporter bufferingExporter = - new MemoryBufferingExporter(currentNetworkProvider, delegate, backlogProvider); - - when(delegate.export(spans)) - .thenReturn(CompletableResultCode.ofFailure()) - .thenReturn(CompletableResultCode.ofSuccess()); - - CompletableResultCode firstResult = bufferingExporter.export(spans); - assertFalse(firstResult.isSuccess()); - - CompletableResultCode secondResult = bufferingExporter.flush(); - assertTrue(secondResult.isSuccess()); - // 2 times...once from the failure, and once from the flush with success - verify(delegate, times(2)).export(spans); - } - - @Test - void flush() { - when(backlogProvider.isEmpty()).thenReturn(true); - when(currentNetwork.isOnline()).thenReturn(true); - - SpanExporter delegate = mock(SpanExporter.class); - MemoryBufferingExporter bufferingExporter = - new MemoryBufferingExporter(currentNetworkProvider, delegate, backlogProvider); - when(delegate.flush()).thenReturn(CompletableResultCode.ofSuccess()); - - CompletableResultCode secondResult = bufferingExporter.flush(); - assertTrue(secondResult.isSuccess()); - verify(delegate).flush(); - } - - @SuppressWarnings("unchecked") - @Test - void maxBacklog() { - List firstSet = new ArrayList<>(); - for (int i = 0; i < 110; i++) { - firstSet.add(mock(SpanData.class)); - } - List secondSet = new ArrayList<>(); - for (int i = 0; i < 20; i++) { - secondSet.add(mock(SpanData.class)); - } - - when(currentNetwork.isOnline()).thenReturn(true); - when(backlogProvider.drain()).thenReturn(firstSet, secondSet); - - SpanExporter delegate = mock(SpanExporter.class); - MemoryBufferingExporter bufferingExporter = - new MemoryBufferingExporter( - currentNetworkProvider, delegate, new DefaultMemorySpanBuffer()); - - when(delegate.export(firstSet)).thenReturn(CompletableResultCode.ofFailure()); - - CompletableResultCode firstResult = bufferingExporter.export(firstSet); - assertFalse(firstResult.isSuccess()); - - ArgumentCaptor> argumentCaptor = ArgumentCaptor.forClass(List.class); - when(delegate.export(argumentCaptor.capture())) - .thenReturn(CompletableResultCode.ofSuccess()); - - CompletableResultCode secondResult = bufferingExporter.export(secondSet); - assertTrue(secondResult.isSuccess()); - - List value = argumentCaptor.getValue(); - // we keep only 100 of the first 110 that failed. - assertEquals(120, value.size()); - } - - @Test - void shutdown() { - SpanExporter delegate = mock(SpanExporter.class); - MemoryBufferingExporter bufferingExporter = - new MemoryBufferingExporter(currentNetworkProvider, delegate, backlogProvider); - - bufferingExporter.shutdown(); - verify(delegate).shutdown(); - } -} diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/NoOpSplunkRumTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/NoOpSplunkRumTest.java index bcb2b779..a4fd550e 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/NoOpSplunkRumTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/NoOpSplunkRumTest.java @@ -32,7 +32,7 @@ class NoOpSplunkRumTest { @Test void doesNotThrow() { NoOpSplunkRum instance = NoOpSplunkRum.INSTANCE; - instance.addRumEvent("foo", Attributes.empty()); + instance.emitEvent("foo", Attributes.empty()); instance.addRumException(new RuntimeException(), Attributes.empty()); assertNotNull(instance.getOpenTelemetry()); diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/RumInitializerTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/RumInitializerTest.java index 7387620e..bff277e6 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/RumInitializerTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/RumInitializerTest.java @@ -36,10 +36,10 @@ import android.content.pm.ApplicationInfo; import android.os.Looper; import com.splunk.rum.incubating.HttpSenderCustomizer; -import io.opentelemetry.android.instrumentation.activity.VisibleScreenTracker; -import io.opentelemetry.android.instrumentation.network.CurrentNetwork; -import io.opentelemetry.android.instrumentation.network.CurrentNetworkProvider; -import io.opentelemetry.android.instrumentation.startup.AppStartupTimer; + +import io.opentelemetry.android.instrumentation.activity.startup.AppStartupTimer; +import io.opentelemetry.android.internal.services.network.CurrentNetworkProvider; +import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.SpanKind; @@ -88,15 +88,16 @@ void initializationSpan() { InMemorySpanExporter testExporter = InMemorySpanExporter.create(); AppStartupTimer startupTimer = new AppStartupTimer(); - RumInitializer testInitializer = - new RumInitializer(splunkRumBuilder, application, startupTimer) { - @Override - SpanExporter buildFilteringExporter( - CurrentNetworkProvider connectionUtil, - VisibleScreenTracker visibleScreenTracker) { - return testExporter; - } - }; + RumInitializer testInitializer = new RumInitializer(splunkRumBuilder, application, startupTimer); + //TODO: This is probably broken +// { +// @Override +// SpanExporter buildFilteringExporter( +// CurrentNetworkProvider connectionUtil, +// VisibleScreenService visibleScreenService) { +// return testExporter; +// } +// }; SplunkRum splunkRum = testInitializer.initialize(mainLooper); startupTimer.runCompletionCallback(); splunkRum.flushSpans(); @@ -148,21 +149,24 @@ void spanLimitsAreConfigured() { InMemorySpanExporter testExporter = InMemorySpanExporter.create(); AppStartupTimer startupTimer = new AppStartupTimer(); RumInitializer testInitializer = - new RumInitializer(splunkRumBuilder, application, startupTimer) { - @Override - SpanExporter buildFilteringExporter( - CurrentNetworkProvider connectionUtil, - VisibleScreenTracker visibleScreenTracker) { - return testExporter; - } - }; + new RumInitializer(splunkRumBuilder, application, startupTimer); + //TODO: This is probably broken + +// { +// @Override +// SpanExporter buildFilteringExporter( +// CurrentNetworkProvider connectionUtil, +// VisibleScreenTracker visibleScreenTracker) { +// return testExporter; +// } +// }; SplunkRum splunkRum = testInitializer.initialize(mainLooper); splunkRum.flushSpans(); testExporter.reset(); AttributeKey longAttributeKey = stringKey("longAttribute"); - splunkRum.addRumEvent( + splunkRum.emitEvent( "testEvent", Attributes.of( longAttributeKey, @@ -178,52 +182,55 @@ SpanExporter buildFilteringExporter( assertEquals(makeString('a', RumInitializer.MAX_ATTRIBUTE_LENGTH), truncatedValue); } + //TODO: Delete or rebuild this /** Verify that we have buffering in place in our exporter implementation. */ - @Test - void verifyExporterBuffering() { - SplunkRumBuilder splunkRumBuilder = - new SplunkRumBuilder() - .setRealm("dev") - .setApplicationName("testApp") - .setRumAccessToken("accessToken"); - AppStartupTimer startupTimer = new AppStartupTimer(); - InMemorySpanExporter testExporter = InMemorySpanExporter.create(); - - RumInitializer testInitializer = - new RumInitializer(splunkRumBuilder, application, startupTimer) { - @Override - SpanExporter getCoreSpanExporter() { - return testExporter; - } - }; - - CurrentNetworkProvider currentNetworkProvider = mock(CurrentNetworkProvider.class); - CurrentNetwork currentNetwork = mock(CurrentNetwork.class); - - when(currentNetworkProvider.refreshNetworkStatus()).thenReturn(currentNetwork); - when(currentNetwork.isOnline()).thenReturn(false, true); - - long currentTimeNanos = MILLISECONDS.toNanos(System.currentTimeMillis()); - - SpanExporter spanExporter = - testInitializer.buildFilteringExporter( - currentNetworkProvider, new VisibleScreenTracker()); - List batch1 = new ArrayList<>(); - for (int i = 0; i < 99; i++) { - batch1.add(createTestSpan(currentTimeNanos - MINUTES.toNanos(1))); - } - // space out the two batches, so they are well under the rate limit - List batch2 = new ArrayList<>(); - for (int i = 0; i < 99; i++) { - batch2.add(createTestSpan(currentTimeNanos)); - } - spanExporter.export(batch1); - spanExporter.export(batch2); - - // we want to verify that everything got exported, including everything buffered while - // offline. - assertEquals(198, testExporter.getFinishedSpanItems().size()); - } +// @Test +// void verifyExporterBuffering() { +// SplunkRumBuilder splunkRumBuilder = +// new SplunkRumBuilder() +// .setRealm("dev") +// .setApplicationName("testApp") +// .setRumAccessToken("accessToken"); +// AppStartupTimer startupTimer = new AppStartupTimer(); +// InMemorySpanExporter testExporter = InMemorySpanExporter.create(); +// +// RumInitializer testInitializer = +// new RumInitializer(splunkRumBuilder, application, startupTimer); +// //TODO: This is probably broken +//// { +//// @Override +//// SpanExporter getCoreSpanExporter() { +//// return testExporter; +//// } +//// }; +// +// CurrentNetworkProvider currentNetworkProvider = mock(CurrentNetworkProvider.class); +// CurrentNetwork currentNetwork = mock(CurrentNetwork.class); +// +// when(currentNetworkProvider.refreshNetworkStatus()).thenReturn(currentNetwork); +// when(currentNetwork.isOnline()).thenReturn(false, true); +// +// long currentTimeNanos = MILLISECONDS.toNanos(System.currentTimeMillis()); +// +// SpanExporter spanExporter = +// testInitializer.buildFilteringExporter( +// currentNetworkProvider, new VisibleScreenTracker()); +// List batch1 = new ArrayList<>(); +// for (int i = 0; i < 99; i++) { +// batch1.add(createTestSpan(currentTimeNanos - MINUTES.toNanos(1))); +// } +// // space out the two batches, so they are well under the rate limit +// List batch2 = new ArrayList<>(); +// for (int i = 0; i < 99; i++) { +// batch2.add(createTestSpan(currentTimeNanos)); +// } +// spanExporter.export(batch1); +// spanExporter.export(batch2); +// +// // we want to verify that everything got exported, including everything buffered while +// // offline. +// assertEquals(198, testExporter.getFinishedSpanItems().size()); +// } private TestSpanData createTestSpan(long startTimeNanos) { return TestSpanData.builder() @@ -254,7 +261,7 @@ void canCustomizeHttpSender() { RumInitializer testInitializer = new RumInitializer(splunkRumBuilder, application, new AppStartupTimer()); SplunkRum rum = testInitializer.initialize(mainLooper); - rum.addRumEvent("foo", Attributes.empty()); // need to trigger export + rum.emitEvent("foo", Attributes.empty()); // need to trigger export rum.flushSpans(); assertNotNull(rum); @@ -276,12 +283,14 @@ void shouldTranslateExceptionEventsToSpanAttributes() { AppStartupTimer appStartupTimer = new AppStartupTimer(); RumInitializer initializer = - new RumInitializer(splunkRumBuilder, application, appStartupTimer) { - @Override - SpanExporter getCoreSpanExporter() { - return spanExporter; - } - }; + new RumInitializer(splunkRumBuilder, application, appStartupTimer); + //TODO: Fix this is probably broken +// { +// @Override +// SpanExporter getCoreSpanExporter() { +// return spanExporter; +// } +// }; SplunkRum splunkRum = initializer.initialize(mainLooper); appStartupTimer.runCompletionCallback(); @@ -342,13 +351,15 @@ void canSetScreenName() { when(application.getApplicationContext()).thenReturn(context); when(application.getMainLooper()).thenReturn(mainLooper); + //TODO: Fix this is probably broken RumInitializer testInitializer = - new RumInitializer(splunkRumBuilder, application, new AppStartupTimer()) { - @Override - SpanExporter getCoreSpanExporter() { - return testExporter; - } - }; + new RumInitializer(splunkRumBuilder, application, new AppStartupTimer()); +// { +// @Override +// SpanExporter getCoreSpanExporter() { +// return testExporter; +// } +// }; SplunkRum splunkRum = testInitializer.initialize(mainLooper); splunkRum.experimentalSetScreenName("screen-1"); diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/ScreenAttributesAppenderTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/ScreenAttributesAppenderTest.java deleted file mode 100644 index ccd67ff5..00000000 --- a/splunk-otel-android/src/test/java/com/splunk/rum/ScreenAttributesAppenderTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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. - */ - -package com.splunk.rum; - -import static io.opentelemetry.android.common.RumConstants.LAST_SCREEN_NAME_KEY; -import static io.opentelemetry.android.common.RumConstants.SCREEN_NAME_KEY; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.opentelemetry.android.instrumentation.activity.VisibleScreenTracker; -import io.opentelemetry.context.Context; -import io.opentelemetry.sdk.trace.ReadWriteSpan; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -class ScreenAttributesAppenderTest { - - private VisibleScreenTracker visibleScreenTracker; - - @BeforeEach - void setUp() { - visibleScreenTracker = mock(VisibleScreenTracker.class); - } - - @Test - void interfaceMethods() { - ScreenAttributesAppender screenAttributesAppender = - new ScreenAttributesAppender(visibleScreenTracker); - - assertTrue(screenAttributesAppender.isStartRequired()); - assertFalse(screenAttributesAppender.isEndRequired()); - } - - @Test - void appendAttributesOnStart() { - when(visibleScreenTracker.getCurrentlyVisibleScreen()).thenReturn("ScreenOne"); - - ReadWriteSpan span = mock(ReadWriteSpan.class); - - ScreenAttributesAppender screenAttributesAppender = - new ScreenAttributesAppender(visibleScreenTracker); - - screenAttributesAppender.onStart(Context.current(), span); - verify(span).setAttribute(SCREEN_NAME_KEY, "ScreenOne"); - } - - @Test - void appendAttributes_noCurrentScreens() { - when(visibleScreenTracker.getCurrentlyVisibleScreen()).thenReturn("unknown"); - - ReadWriteSpan span = mock(ReadWriteSpan.class); - - ScreenAttributesAppender screenAttributesAppender = - new ScreenAttributesAppender(visibleScreenTracker); - - screenAttributesAppender.onStart(Context.current(), span); - verify(span).setAttribute(SCREEN_NAME_KEY, "unknown"); - verify(span, never()).setAttribute(eq(LAST_SCREEN_NAME_KEY), any()); - } -} 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 ae73578a..65b23997 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 @@ -38,7 +38,7 @@ import android.webkit.WebView; import com.splunk.rum.internal.GlobalAttributesSupplier; import io.opentelemetry.android.OpenTelemetryRum; -import io.opentelemetry.android.instrumentation.activity.VisibleScreenTracker; +import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.api.trace.Span; @@ -62,20 +62,22 @@ import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) -public class SplunkRumTest { +class SplunkRumTest { @RegisterExtension final OpenTelemetryExtension otelTesting = OpenTelemetryExtension.create(); - private Tracer tracer; + Tracer tracer; - @Mock private OpenTelemetryRum openTelemetryRum; - @Mock private GlobalAttributesSupplier globalAttributes; + @Mock OpenTelemetryRum openTelemetryRum; + @Mock GlobalAttributesSupplier globalAttributes; - private SettableScreenAttributesAppender screenNameAppender; + SettableScreenAttributesAppender screenNameAppender; + Application application; @BeforeEach - public void setup() { - screenNameAppender = new SettableScreenAttributesAppender(new VisibleScreenTracker()); + void setup() { + application = mock(Application.class, RETURNS_DEEP_STUBS); + screenNameAppender = new SettableScreenAttributesAppender(new VisibleScreenService(application)); tracer = otelTesting.getOpenTelemetry().getTracer("testTracer"); SplunkRum.resetSingletonForTest(); @@ -83,7 +85,6 @@ public void setup() { @Test void initialization_onlyOnce() { - Application application = mock(Application.class, RETURNS_DEEP_STUBS); Context context = mock(Context.class); SplunkRumBuilder splunkRumBuilder = @@ -156,7 +157,7 @@ void addEvent() { SplunkRum splunkRum = new SplunkRum(openTelemetryRum, globalAttributes, screenNameAppender); Attributes attributes = Attributes.of(stringKey("one"), "1", longKey("two"), 2L); - splunkRum.addRumEvent("foo", attributes); + splunkRum.emitEvent("foo", attributes); List spans = otelTesting.getSpans(); assertEquals(1, spans.size()); diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/SplunkSpanDataModifierTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/SplunkSpanDataModifierTest.java index 97fd90bf..22d39490 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/SplunkSpanDataModifierTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/SplunkSpanDataModifierTest.java @@ -26,7 +26,7 @@ import static java.util.Collections.singletonList; import static org.mockito.Mockito.when; -import io.opentelemetry.android.RumConstants; +import io.opentelemetry.android.common.RumConstants; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.SpanKind; diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/StartTypeAwareMemorySpanBufferTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/StartTypeAwareMemorySpanBufferTest.java index d83bc269..8c6d603b 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/StartTypeAwareMemorySpanBufferTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/StartTypeAwareMemorySpanBufferTest.java @@ -20,7 +20,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import io.opentelemetry.android.instrumentation.activity.VisibleScreenTracker; +import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService; import io.opentelemetry.sdk.trace.data.SpanData; import java.util.ArrayList; import java.util.List; @@ -28,7 +28,7 @@ public class StartTypeAwareMemorySpanBufferTest { - private final VisibleScreenTracker visibleScreenTracker = mock(VisibleScreenTracker.class); + private final VisibleScreenService visibleScreenTracker = mock(VisibleScreenService.class); private final StartTypeAwareMemorySpanBuffer memorySpanBuffer = new StartTypeAwareMemorySpanBuffer(visibleScreenTracker); diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/StartTypeAwareSpanStorageTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/StartTypeAwareSpanStorageTest.java index aa2b195d..f820d548 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/StartTypeAwareSpanStorageTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/StartTypeAwareSpanStorageTest.java @@ -26,7 +26,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import io.opentelemetry.android.instrumentation.activity.VisibleScreenTracker; import java.io.File; import java.util.ArrayList; import java.util.List; @@ -37,20 +36,22 @@ import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; +import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService; + class StartTypeAwareSpanStorageTest { final File rootDir = new File("files/"); - VisibleScreenTracker visibleScreenTracker; + VisibleScreenService visibleScreenService; FileUtils fileUtils; private StartTypeAwareSpanStorage fileProvider; @BeforeEach void setup() { - visibleScreenTracker = mock(); + visibleScreenService = mock(); fileUtils = mock(); when(fileUtils.getSpansDirectory(rootDir)).thenReturn(new File(rootDir, "spans")); - fileProvider = StartTypeAwareSpanStorage.create(visibleScreenTracker, fileUtils, rootDir); + fileProvider = StartTypeAwareSpanStorage.create(visibleScreenService, fileUtils, rootDir); } @Test @@ -59,13 +60,13 @@ void create_onNewId_shouldCleanOldBackgroundFiles() { ArgumentCaptor fileArgumentCaptor = ArgumentCaptor.forClass(File.class); when(file.getPath()).thenReturn("files/spans/background/123"); - fileProvider = StartTypeAwareSpanStorage.create(visibleScreenTracker, fileUtils, rootDir); + fileProvider = StartTypeAwareSpanStorage.create(visibleScreenService, fileUtils, rootDir); fileUtils = mock(FileUtils.class); when(fileUtils.listDirectories(any())).thenReturn(Stream.of(file)); when(fileUtils.listFiles(file)).thenReturn(Stream.of(file)); when(fileUtils.exists(any())).thenReturn(true); - fileProvider = StartTypeAwareSpanStorage.create(visibleScreenTracker, fileUtils, rootDir); + fileProvider = StartTypeAwareSpanStorage.create(visibleScreenService, fileUtils, rootDir); verify(fileUtils, times(2)).safeDelete(fileArgumentCaptor.capture()); assertEquals(file, fileArgumentCaptor.getAllValues().get(0)); @@ -75,12 +76,12 @@ void create_onNewId_shouldCleanOldBackgroundFiles() { @Test void doesNotAttemptIfBackgroundDirNotExist() { - fileProvider = StartTypeAwareSpanStorage.create(visibleScreenTracker, fileUtils, rootDir); + fileProvider = StartTypeAwareSpanStorage.create(visibleScreenService, fileUtils, rootDir); fileUtils = mock(FileUtils.class); when(fileUtils.exists(any())).thenReturn(false); when(fileUtils.listDirectories(any())).thenReturn(Stream.empty()); - fileProvider = StartTypeAwareSpanStorage.create(visibleScreenTracker, fileUtils, rootDir); + fileProvider = StartTypeAwareSpanStorage.create(visibleScreenService, fileUtils, rootDir); verify(fileUtils, never()).listFiles(any()); verify(fileUtils, never()).safeDelete(any()); @@ -104,7 +105,7 @@ void create_cleanDoesntRemoveDirIfNotEmpty() { fileProvider = StartTypeAwareSpanStorage.create( - visibleScreenTracker, fileUtils, rootDir, spansDir, uniqueId); + visibleScreenService, fileUtils, rootDir, spansDir, uniqueId); verify(fileUtils).safeDelete(fileArgumentCaptor.capture()); assertEquals(file, fileArgumentCaptor.getAllValues().get(0)); @@ -112,8 +113,8 @@ void create_cleanDoesntRemoveDirIfNotEmpty() { @Test void getPendingFiles_givenInBackground_shouldReturnForegroundOnlySpan() { - when(visibleScreenTracker.getPreviouslyVisibleScreen()).thenReturn(null); - when(visibleScreenTracker.getCurrentlyVisibleScreen()).thenReturn("unknown"); + when(visibleScreenService.getPreviouslyVisibleScreen()).thenReturn(null); + when(visibleScreenService.getCurrentlyVisibleScreen()).thenReturn("unknown"); List spans = fileProvider.getPendingFiles().collect(Collectors.toList()); assertEquals(0, spans.size()); } @@ -121,8 +122,8 @@ void getPendingFiles_givenInBackground_shouldReturnForegroundOnlySpan() { @Test void getPendingFiles_givenPreviouslyInBackground_shouldMoveBackgroundSpanToForegroundSpanForSending() { - when(visibleScreenTracker.getPreviouslyVisibleScreen()).thenReturn("LauncherActivity"); - when(visibleScreenTracker.getCurrentlyVisibleScreen()).thenReturn("MainActivity"); + when(visibleScreenService.getPreviouslyVisibleScreen()).thenReturn("LauncherActivity"); + when(visibleScreenService.getCurrentlyVisibleScreen()).thenReturn("MainActivity"); List backgroundFiles = new ArrayList<>(); File fileToMove = mock(); @@ -149,8 +150,8 @@ void getPendingFiles_givenInBackground_shouldReturnForegroundOnlySpan() { @Test void getSpanPath_givenInBackground_shouldReturnBackgroundSpanPath() { - when(visibleScreenTracker.getPreviouslyVisibleScreen()).thenReturn(null); - when(visibleScreenTracker.getCurrentlyVisibleScreen()).thenReturn("unknown"); + when(visibleScreenService.getPreviouslyVisibleScreen()).thenReturn(null); + when(visibleScreenService.getCurrentlyVisibleScreen()).thenReturn("unknown"); File path = fileProvider.provideSpansDirectory(); @@ -159,8 +160,8 @@ void getSpanPath_givenInBackground_shouldReturnBackgroundSpanPath() { @Test void getSpanPath_givenInForeground_shouldReturnForegroundSpanPath() { - when(visibleScreenTracker.getPreviouslyVisibleScreen()).thenReturn("LauncherActivity"); - when(visibleScreenTracker.getCurrentlyVisibleScreen()).thenReturn("MainActivity"); + when(visibleScreenService.getPreviouslyVisibleScreen()).thenReturn("LauncherActivity"); + when(visibleScreenService.getCurrentlyVisibleScreen()).thenReturn("MainActivity"); File path = fileProvider.provideSpansDirectory(); From 527cb8359f6b6ea799260c002589c3258faa801b Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 4 Sep 2024 13:22:43 -0700 Subject: [PATCH 14/29] fix debug span logging --- .../java/com/splunk/rum/RumInitializer.java | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 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 1b7e4d99..b372bd21 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 @@ -173,19 +173,6 @@ SplunkRum initialize(Looper mainLooper) { }); } - // Wire up the logging exporter, if enabled. - if (builder.isDebugEnabled()) { - otelRumBuilder.addTracerProviderCustomizer( - (tracerProviderBuilder, app) -> { - tracerProviderBuilder.addSpanProcessor( - SimpleSpanProcessor.create( - builder.decorateWithSpanFilter( - LoggingSpanExporter.create()))); - initializationEvents.emit("debugSpanExporterInitialized"); - return tracerProviderBuilder; - }); - } - // Add final event showing tracer provider init finished otelRumBuilder.addTracerProviderCustomizer( (tracerProviderBuilder, app) -> { @@ -371,6 +358,12 @@ SpanExporter buildSpanExporter(SpanExporter delegate) { true); SpanExporter filteredExporter = builder.decorateWithSpanFilter(splunkTranslatedExporter); initializationEvents.emit("otlp span exporter initialized"); + + // Wire up the logging exporter, if enabled. + if (builder.isDebugEnabled()) { + initializationEvents.emit("debugSpanExporterInitialized"); + return SpanExporter.composite(LoggingSpanExporter.create(), filteredExporter); + } return filteredExporter; } From dd44f66b3ed2bdc57167a7872fd3233a72f44686 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Mon, 9 Sep 2024 15:04:33 -0700 Subject: [PATCH 15/29] work in progress -- enable disk buffering --- gradle/libs.versions.toml | 1 + sample-app/build.gradle.kts | 4 -- splunk-otel-android/build.gradle.kts | 1 + .../main/java/com/splunk/rum/ConfigFlags.java | 12 ----- .../java/com/splunk/rum/RumInitializer.java | 9 +++- .../java/com/splunk/rum/SplunkRumBuilder.java | 48 ++++++------------- .../com/splunk/rum/SplunkRumBuilderTest.java | 33 ------------- 7 files changed, 25 insertions(+), 83 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9344c434..46c90e8b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -22,6 +22,7 @@ opentelemetry-api = { module = "io.opentelemetry:opentelemetry-api", version.ref opentelemetry-api-incubator = { module = "io.opentelemetry:opentelemetry-api-incubator" } opentelemetry-api-events = { module = "io.opentelemetry:opentelemetry-api-events", version.ref = "opentelemetry-core-alpha" } opentelemetry-android-agent = { module = "io.opentelemetry.android:android-agent", version.ref = "opentelemetry-android" } +opentelemetry-android-instrumentation-commonapi = { module = "io.opentelemetry.android:instrumentation-common-api", version.ref = "opentelemetry-android" } opentelemetry-instrumenter-api = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api", version.ref = "opentelemetry-inst" } opentelemetry-instrumenter-api-incubator = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-incubator", version.ref = "opentelemetry-inst-alpha" } opentelemetry-instrumentation-okhttp = { module = "io.opentelemetry.instrumentation:opentelemetry-okhttp-3.0", version.ref = "opentelemetry-inst-alpha" } diff --git a/sample-app/build.gradle.kts b/sample-app/build.gradle.kts index 138fa348..c0de5cea 100644 --- a/sample-app/build.gradle.kts +++ b/sample-app/build.gradle.kts @@ -72,11 +72,7 @@ composeCompiler { } repositories { - // TODO: Remove after android-agent 0.7.0-alpha is released maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") } -// mavenCentral() -// google() -// gradlePluginPortal() } dependencies { diff --git a/splunk-otel-android/build.gradle.kts b/splunk-otel-android/build.gradle.kts index ba3ce209..749bdf7b 100644 --- a/splunk-otel-android/build.gradle.kts +++ b/splunk-otel-android/build.gradle.kts @@ -43,6 +43,7 @@ dependencies { api(platform(libs.opentelemetry.instrumentation.bom)) api(platform(libs.opentelemetry.bom)) api(libs.opentelemetry.android.agent) + api(libs.opentelemetry.android.instrumentation.commonapi) // not included in agent implementation(libs.opentelemetry.sdk) implementation(libs.opentelemetry.api.incubator) diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/ConfigFlags.java b/splunk-otel-android/src/main/java/com/splunk/rum/ConfigFlags.java index d290a9aa..2b1d8790 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/ConfigFlags.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/ConfigFlags.java @@ -102,18 +102,6 @@ boolean isReactNativeSupportEnabled() { return reactNativeSupportEnabled; } - void enableOtlpExporter() { - exportUsingOtlp = true; - } - - void disableOtlpExporter() { - exportUsingOtlp = false; - } - - boolean shouldUseOtlpExporter() { - return exportUsingOtlp; - } - @NonNull @Override public String toString() { 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 b372bd21..0ad4134a 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 @@ -47,6 +47,7 @@ import io.opentelemetry.android.OpenTelemetryRum; import io.opentelemetry.android.OpenTelemetryRumBuilder; import io.opentelemetry.android.config.OtelRumConfig; +import io.opentelemetry.android.features.diskbuffering.DiskBufferingConfiguration; import io.opentelemetry.android.instrumentation.AndroidInstrumentationLoader; import io.opentelemetry.android.instrumentation.activity.ActivityLifecycleInstrumentation; import io.opentelemetry.android.instrumentation.activity.startup.AppStartupTimer; @@ -99,6 +100,11 @@ SplunkRum initialize(Looper mainLooper) { new GlobalAttributesSupplier(builder.globalAttributes); config.setGlobalAttributes(globalAttributeSupplier); + config.setDiskBufferingConfiguration(DiskBufferingConfiguration.builder() + .setEnabled(true) + .setMaxCacheSize(100_000_000) + .build()); + // TODO: Note/document this instrumentation is now opt-in via application classpath via build settings // if (!builder.isNetworkMonitorEnabled()) { // config.disableNetworkChangeMonitoring(); @@ -362,7 +368,8 @@ SpanExporter buildSpanExporter(SpanExporter delegate) { // Wire up the logging exporter, if enabled. if (builder.isDebugEnabled()) { initializationEvents.emit("debugSpanExporterInitialized"); - return SpanExporter.composite(LoggingSpanExporter.create(), filteredExporter); + SpanExporter result = SpanExporter.composite(LoggingSpanExporter.create(), filteredExporter); + return result; } return filteredExporter; } diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkRumBuilder.java b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkRumBuilder.java index ead999bb..69d6c838 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkRumBuilder.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkRumBuilder.java @@ -111,18 +111,11 @@ public SplunkRumBuilder setRealm(String realm) { "beaconEndpoint has already been set. Realm configuration will be ignored."); return this; } - this.beaconEndpoint = "https://rum-ingest." + realm + ".signalfx.com/v1/rum"; this.realm = realm; - if (shouldUseOtlpExporter()) { - configureBeaconForOtlp(); - } + this.beaconEndpoint = "https://rum-ingest." + this.realm + ".signalfx.com/v1/rumotlp"; return this; } - private void configureBeaconForOtlp() { - this.beaconEndpoint = "https://rum-ingest." + realm + ".signalfx.com/v1/rumotlp"; - } - /** * Sets the RUM auth token to be used by the RUM library. * @@ -155,14 +148,7 @@ public SplunkRumBuilder enableDebug() { * @return {@code this} */ public SplunkRumBuilder enableDiskBuffering() { - if (shouldUseOtlpExporter()) { - Log.w(SplunkRum.LOG_TAG, "OTLP export is not yet compatible with disk buffering!"); - Log.w( - SplunkRum.LOG_TAG, - "Because disk buffering is enabled, OTLP export is now disabled!"); - configFlags.disableOtlpExporter(); - } - + // TODO: Default to enabled, switch this perhaps to allow disabling configFlags.enableDiskBuffering(); return this; } @@ -380,19 +366,19 @@ public SplunkRumBuilder enableBackgroundInstrumentationDeferredUntilForeground() * * @return {@code this} */ - public SplunkRumBuilder enableExperimentalOtlpExporter() { - if (isDiskBufferingEnabled()) { - Log.w(SplunkRum.LOG_TAG, "OTLP export is not yet compatible with disk buffering!"); - Log.w(SplunkRum.LOG_TAG, "Please disable disk buffering in order to use OTLP export."); - Log.w(SplunkRum.LOG_TAG, "OTLP is not enabled."); - return this; - } - configFlags.enableOtlpExporter(); - if (this.realm != null) { - configureBeaconForOtlp(); - } - return this; - } +// public SplunkRumBuilder enableExperimentalOtlpExporter() { +// if (isDiskBufferingEnabled()) { +// Log.w(SplunkRum.LOG_TAG, "OTLP export is not yet compatible with disk buffering!"); +// Log.w(SplunkRum.LOG_TAG, "Please disable disk buffering in order to use OTLP export."); +// Log.w(SplunkRum.LOG_TAG, "OTLP is not enabled."); +// return this; +// } +// configFlags.enableOtlpExporter(); +// if (this.realm != null) { +// configureBeaconForOtlp(); +// } +// return this; +// } // one day maybe these can use kotlin delegation ConfigFlags getConfigFlags() { @@ -429,10 +415,6 @@ boolean isDiskBufferingEnabled() { return configFlags.isDiskBufferingEnabled(); } - boolean shouldUseOtlpExporter() { - return configFlags.shouldUseOtlpExporter(); - } - boolean isReactNativeSupportEnabled() { return configFlags.isReactNativeSupportEnabled(); } diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/SplunkRumBuilderTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/SplunkRumBuilderTest.java index 92491614..162ea93c 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/SplunkRumBuilderTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/SplunkRumBuilderTest.java @@ -91,37 +91,4 @@ void beaconOverridesRealm() { SplunkRum.builder().setRealm("us0").setBeaconEndpoint("http://beacon"); assertEquals("http://beacon", builder.beaconEndpoint); } - - @Test - void otlpNotEnabledByDefault() { - SplunkRumBuilder builder = SplunkRum.builder().setRealm("jp0"); - assertThat(builder.getConfigFlags().shouldUseOtlpExporter()).isFalse(); - } - - @Test - void enableOtlp() { - SplunkRumBuilder builder = - SplunkRum.builder().setRealm("jp0").enableExperimentalOtlpExporter(); - assertThat(builder.getConfigFlags().shouldUseOtlpExporter()).isTrue(); - } - - @Test - void otlpFailsWhenDiskBufferingEnabled() { - SplunkRumBuilder builder = - SplunkRum.builder() - .setRealm("us0") - .enableDiskBuffering() - .enableExperimentalOtlpExporter(); - assertThat(builder.getConfigFlags().shouldUseOtlpExporter()).isFalse(); - } - - @Test - void enableDiskBufferAfterOtlp() { - SplunkRumBuilder builder = - SplunkRum.builder() - .setRealm("us0") - .enableExperimentalOtlpExporter() - .enableDiskBuffering(); - assertThat(builder.getConfigFlags().shouldUseOtlpExporter()).isFalse(); - } } From 68493057ecb5afefcad8365f1ef56ed3cb171e0e Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Sep 2024 13:24:03 -0700 Subject: [PATCH 16/29] remove unnecessary customizer --- .../src/main/java/com/splunk/rum/RumInitializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 0ad4134a..7905a71b 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 @@ -150,7 +150,7 @@ SplunkRum initialize(Looper mainLooper) { // }); // Inhibit the upstream exporter because we add our own BatchSpanProcessor - otelRumBuilder.addSpanExporterCustomizer(x -> new NoOpSpanExporter()); +// otelRumBuilder.addSpanExporterCustomizer(x -> new NoOpSpanExporter()); // Set span limits otelRumBuilder.addTracerProviderCustomizer( From f5a362e8f7b7efd137448e2be61e87f6701b3442 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Fri, 13 Sep 2024 15:54:22 -0700 Subject: [PATCH 17/29] cleanup --- .../java/com/splunk/rum/RumInitializer.java | 22 ------------------- 1 file changed, 22 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 7905a71b..f92e791a 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 @@ -38,7 +38,6 @@ import androidx.annotation.NonNull; import com.splunk.rum.internal.GlobalAttributesSupplier; -import com.splunk.rum.internal.NoOpSpanExporter; import com.splunk.rum.internal.UInt32QuadXorTraceIdRatioSampler; import java.util.concurrent.atomic.AtomicReference; @@ -68,7 +67,6 @@ import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.resources.ResourceBuilder; import io.opentelemetry.sdk.trace.SpanLimits; -import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; import io.opentelemetry.sdk.trace.export.SpanExporter; import io.opentelemetry.sdk.trace.samplers.Sampler; @@ -129,28 +127,8 @@ SplunkRum initialize(Looper mainLooper) { // otelRumBuilder.setCurrentNetworkProvider(currentNetworkProvider); initializationEvents.emit("connectionUtilInitialized"); - // TODO: How truly important is the order of these span processors? The location of event - // generation should probably not be altered... - // Get exporters going... otelRumBuilder.addSpanExporterCustomizer(this::buildSpanExporter); -// otelRumBuilder.addLogRecordExporterCustomizer(xxx todo ); - -// // Add batch span processor -// otelRumBuilder.addTracerProviderCustomizer( -// (tracerProviderBuilder, app) -> { -// SpanExporter zipkinExporter = -// buildFilteringExporter(currentNetworkProvider, visibleScreenService); -// initializationEvents.emit("exporterInitialized"); -// -// BatchSpanProcessor batchSpanProcessor = -// BatchSpanProcessor.builder(zipkinExporter).build(); -// initializationEvents.emit("batchSpanProcessorInitialized"); -// return tracerProviderBuilder.addSpanProcessor(batchSpanProcessor); -// }); - - // Inhibit the upstream exporter because we add our own BatchSpanProcessor -// otelRumBuilder.addSpanExporterCustomizer(x -> new NoOpSpanExporter()); // Set span limits otelRumBuilder.addTracerProviderCustomizer( From 81667b6496d1d88bf47cdb42d8cf4e45e7703ae0 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 18 Sep 2024 14:43:14 -0700 Subject: [PATCH 18/29] add todo --- .../src/main/java/com/splunk/rum/RumInitializer.java | 1 + 1 file changed, 1 insertion(+) 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 f92e791a..1e174476 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 @@ -206,6 +206,7 @@ SplunkRum initialize(Looper mainLooper) { return new SplunkRum(openTelemetryRum, globalAttributeSupplier, screenAttributesAppender); } + // TODO: Wire this stuff back up so that we can defer background spans again?.... @NonNull private MemorySpanBuffer constructBacklogProvider(VisibleScreenService visibleScreenService) { if (builder.isBackgroundInstrumentationDeferredUntilForeground()) { From 9c1d7a1bae1751fb91c68e8afb6f121133904f9c Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 17 Oct 2024 13:41:15 -0700 Subject: [PATCH 19/29] format and fix after rebase --- sample-app/build.gradle.kts | 1 - .../splunk/android/sample/MainActivity.java | 1 - .../splunk/android/sample/SecondFragment.java | 3 - .../java/com/splunk/rum/RumInitializer.java | 442 +++++++++--------- .../main/java/com/splunk/rum/SplunkRum.java | 12 +- .../java/com/splunk/rum/SplunkRumBuilder.java | 28 +- .../splunk/rum/SplunkScreenNameExtractor.java | 3 +- .../rum/StartTypeAwareMemorySpanBuffer.java | 5 +- .../splunk/rum/StartTypeAwareSpanStorage.java | 5 +- .../com/splunk/rum/RumInitializerTest.java | 173 ++++--- .../com/splunk/rum/SplunkRumBuilderTest.java | 1 - .../java/com/splunk/rum/SplunkRumTest.java | 3 +- .../rum/StartTypeAwareSpanStorageTest.java | 3 +- 13 files changed, 345 insertions(+), 335 deletions(-) diff --git a/sample-app/build.gradle.kts b/sample-app/build.gradle.kts index c0de5cea..1db75a02 100644 --- a/sample-app/build.gradle.kts +++ b/sample-app/build.gradle.kts @@ -7,7 +7,6 @@ plugins { alias(libs.plugins.compose) } - val localProperties = Properties() localProperties.load(FileInputStream(rootProject.file("local.properties"))) diff --git a/sample-app/src/main/java/com/splunk/android/sample/MainActivity.java b/sample-app/src/main/java/com/splunk/android/sample/MainActivity.java index 6196484f..b7881aa0 100644 --- a/sample-app/src/main/java/com/splunk/android/sample/MainActivity.java +++ b/sample-app/src/main/java/com/splunk/android/sample/MainActivity.java @@ -43,7 +43,6 @@ import androidx.work.WorkManager; import com.splunk.android.sample.databinding.ActivityMainBinding; import com.splunk.rum.SplunkRum; - import io.opentelemetry.android.instrumentation.annotations.RumScreenName; import io.opentelemetry.api.common.Attributes; import java.util.Arrays; diff --git a/sample-app/src/main/java/com/splunk/android/sample/SecondFragment.java b/sample-app/src/main/java/com/splunk/android/sample/SecondFragment.java index a03f2be1..b3057ea2 100644 --- a/sample-app/src/main/java/com/splunk/android/sample/SecondFragment.java +++ b/sample-app/src/main/java/com/splunk/android/sample/SecondFragment.java @@ -29,14 +29,11 @@ import androidx.navigation.fragment.NavHostFragment; import com.splunk.android.sample.databinding.FragmentSecondBinding; import com.splunk.rum.SplunkRum; - import io.opentelemetry.android.instrumentation.annotations.RumScreenName; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Scope; -import io.opentelemetry.sdk.OpenTelemetrySdk; -import io.opentelemetry.sdk.logs.internal.SdkEventLoggerProvider; import java.util.Random; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; 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 1e174476..7f165bed 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 @@ -26,39 +26,28 @@ import static com.splunk.rum.SplunkRum.LOG_TAG; import static com.splunk.rum.SplunkRum.RUM_TRACER_NAME; import static com.splunk.rum.SplunkRum.SPLUNK_OLLY_UUID_KEY; -import static java.util.Objects.requireNonNull; import static io.opentelemetry.android.common.RumConstants.APP_START_SPAN_NAME; import static io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor.constant; import static io.opentelemetry.semconv.incubating.DeploymentIncubatingAttributes.DEPLOYMENT_ENVIRONMENT; +import static java.util.Objects.requireNonNull; import android.app.Application; import android.os.Looper; import android.util.Log; - import androidx.annotation.NonNull; - import com.splunk.rum.internal.GlobalAttributesSupplier; +import com.splunk.rum.internal.NoOpSpanExporter; import com.splunk.rum.internal.UInt32QuadXorTraceIdRatioSampler; - -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Supplier; - 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.features.diskbuffering.DiskBufferingConfiguration; import io.opentelemetry.android.instrumentation.AndroidInstrumentationLoader; import io.opentelemetry.android.instrumentation.activity.ActivityLifecycleInstrumentation; import io.opentelemetry.android.instrumentation.activity.startup.AppStartupTimer; import io.opentelemetry.android.instrumentation.anr.AnrInstrumentation; -import io.opentelemetry.android.instrumentation.anr.AnrDetectorBuilder; import io.opentelemetry.android.instrumentation.crash.CrashReporterInstrumentation; import io.opentelemetry.android.instrumentation.slowrendering.SlowRenderingInstrumentation; -import io.opentelemetry.android.instrumentation.crash.CrashReporterBuilder; -import io.opentelemetry.android.instrumentation.lifecycle.AndroidLifecycleInstrumentation; -import io.opentelemetry.android.instrumentation.network.CurrentNetworkProvider; -import io.opentelemetry.android.instrumentation.slowrendering.SlowRenderingDetector; -import io.opentelemetry.android.instrumentation.startup.AppStartupTimer; import io.opentelemetry.android.internal.services.ServiceManager; import io.opentelemetry.android.internal.services.network.CurrentNetworkProvider; import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService; @@ -67,8 +56,11 @@ import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.resources.ResourceBuilder; import io.opentelemetry.sdk.trace.SpanLimits; +import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; import io.opentelemetry.sdk.trace.export.SpanExporter; import io.opentelemetry.sdk.trace.samplers.Sampler; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; class RumInitializer { @@ -98,15 +90,11 @@ SplunkRum initialize(Looper mainLooper) { new GlobalAttributesSupplier(builder.globalAttributes); config.setGlobalAttributes(globalAttributeSupplier); - config.setDiskBufferingConfiguration(DiskBufferingConfiguration.builder() - .setEnabled(true) - .setMaxCacheSize(100_000_000) - .build()); - - // TODO: Note/document this instrumentation is now opt-in via application classpath via build settings -// if (!builder.isNetworkMonitorEnabled()) { -// config.disableNetworkChangeMonitoring(); -// } + // TODO: Note/document this instrumentation is now opt-in via application classpath via + // build settings + // if (!builder.isNetworkMonitorEnabled()) { + // config.disableNetworkChangeMonitoring(); + // } config.disableScreenAttributes(); OpenTelemetryRumBuilder otelRumBuilder = OpenTelemetryRum.builder(application, config); @@ -121,14 +109,35 @@ SplunkRum initialize(Looper mainLooper) { // TODO: now spelled rum.sdk.init.net.provider and currently mixed up in network // attributes enabled config in upstream -//// CurrentNetworkProvider currentNetworkProvider = -//// CurrentNetworkProvider.create(application); -// currentNetworkProvider.start(); -// otelRumBuilder.setCurrentNetworkProvider(currentNetworkProvider); + //// CurrentNetworkProvider currentNetworkProvider = + //// CurrentNetworkProvider.create(application); + // currentNetworkProvider.start(); + // otelRumBuilder.setCurrentNetworkProvider(currentNetworkProvider); initializationEvents.emit("connectionUtilInitialized"); + // TODO: How truly important is the order of these span processors? The location of event + // generation should probably not be altered... + // Get exporters going... otelRumBuilder.addSpanExporterCustomizer(this::buildSpanExporter); + // otelRumBuilder.addLogRecordExporterCustomizer(xxx todo ); + + // // Add batch span processor + // otelRumBuilder.addTracerProviderCustomizer( + // (tracerProviderBuilder, app) -> { + // SpanExporter zipkinExporter = + // buildFilteringExporter(currentNetworkProvider, + // visibleScreenService); + // initializationEvents.emit("exporterInitialized"); + // + // BatchSpanProcessor batchSpanProcessor = + // BatchSpanProcessor.builder(zipkinExporter).build(); + // initializationEvents.emit("batchSpanProcessorInitialized"); + // return tracerProviderBuilder.addSpanProcessor(batchSpanProcessor); + // }); + + // Inhibit the upstream exporter because we add our own BatchSpanProcessor + otelRumBuilder.addSpanExporterCustomizer(x -> new NoOpSpanExporter()); // Set span limits otelRumBuilder.addTracerProviderCustomizer( @@ -157,6 +166,19 @@ SplunkRum initialize(Looper mainLooper) { }); } + // Wire up the logging exporter, if enabled. + if (builder.isDebugEnabled()) { + otelRumBuilder.addTracerProviderCustomizer( + (tracerProviderBuilder, app) -> { + tracerProviderBuilder.addSpanProcessor( + SimpleSpanProcessor.create( + builder.decorateWithSpanFilter( + LoggingSpanExporter.create()))); + initializationEvents.emit("debugSpanExporterInitialized"); + return tracerProviderBuilder; + }); + } + // Add final event showing tracer provider init finished otelRumBuilder.addTracerProviderCustomizer( (tracerProviderBuilder, app) -> { @@ -206,7 +228,6 @@ SplunkRum initialize(Looper mainLooper) { return new SplunkRum(openTelemetryRum, globalAttributeSupplier, screenAttributesAppender); } - // TODO: Wire this stuff back up so that we can defer background spans again?.... @NonNull private MemorySpanBuffer constructBacklogProvider(VisibleScreenService visibleScreenService) { if (builder.isBackgroundInstrumentationDeferredUntilForeground()) { @@ -230,20 +251,25 @@ private SpanStorage constructSpanFileProvider(VisibleScreenService visibleScreen } private void configureLifecycleInstrumentations() { - ActivityLifecycleInstrumentation instrumentation = AndroidInstrumentationLoader.getInstrumentation(ActivityLifecycleInstrumentation.class); - if(instrumentation == null){ - Log.w(LOG_TAG, "Activity rendering instrumentation was not loaded! Skipping configuration."); + ActivityLifecycleInstrumentation instrumentation = + AndroidInstrumentationLoader.getInstrumentation( + ActivityLifecycleInstrumentation.class); + if (instrumentation == null) { + Log.w( + LOG_TAG, + "Activity rendering instrumentation was not loaded! Skipping configuration."); return; } - instrumentation.setTracerCustomizer(tracer -> - spanName -> { - String component = - spanName.equals(APP_START_SPAN_NAME) - ? COMPONENT_APPSTART - : COMPONENT_UI; - return tracer.spanBuilder(spanName) - .setAttribute(COMPONENT_KEY, component); - }); + instrumentation.setTracerCustomizer( + tracer -> + spanName -> { + String component = + spanName.equals(APP_START_SPAN_NAME) + ? COMPONENT_APPSTART + : COMPONENT_UI; + return tracer.spanBuilder(spanName) + .setAttribute(COMPONENT_KEY, component); + }); instrumentation.setScreenNameExtractor(SplunkScreenNameExtractor.INSTANCE); initializationEvents.emit("activityLifecycleCallbacksInitialized"); } @@ -263,8 +289,9 @@ private Resource createSplunkResource() { } private void configureAnrInstrumentation() { - AnrInstrumentation instrumentation = AndroidInstrumentationLoader.getInstrumentation(AnrInstrumentation.class); - if(instrumentation == null){ + AnrInstrumentation instrumentation = + AndroidInstrumentationLoader.getInstrumentation(AnrInstrumentation.class); + if (instrumentation == null) { Log.w(LOG_TAG, "ANR instrumentation was not loaded! Skipping configuration."); return; } @@ -276,13 +303,13 @@ private void configureAnrInstrumentation() { instrumentation.addAttributesExtractor(constant(COMPONENT_KEY, COMPONENT_ERROR)); - if (applicationId != null){ + if (applicationId != null) { instrumentation.addAttributesExtractor(constant(APPLICATION_ID_KEY, applicationId)); } - if (versionCode != null){ + if (versionCode != null) { instrumentation.addAttributesExtractor(constant(APP_VERSION_CODE_KEY, versionCode)); } - if (uuid != null){ + if (uuid != null) { instrumentation.addAttributesExtractor(constant(SPLUNK_OLLY_UUID_KEY, uuid)); } @@ -290,19 +317,26 @@ private void configureAnrInstrumentation() { } private void configureSlowRenderingInstrumentation(OpenTelemetryRumBuilder otelRumBuilder) { - SlowRenderingInstrumentation instrumentation = AndroidInstrumentationLoader.getInstrumentation(SlowRenderingInstrumentation.class); - if(instrumentation == null){ - Log.w(LOG_TAG, "Slow rendering instrumentation was not loaded! Skipping configuration."); + SlowRenderingInstrumentation instrumentation = + AndroidInstrumentationLoader.getInstrumentation(SlowRenderingInstrumentation.class); + if (instrumentation == null) { + Log.w( + LOG_TAG, + "Slow rendering instrumentation was not loaded! Skipping configuration."); return; } - instrumentation.setSlowRenderingDetectionPollInterval(builder.slowRenderingDetectionPollInterval); + instrumentation.setSlowRenderingDetectionPollInterval( + builder.slowRenderingDetectionPollInterval); initializationEvents.emit("slowRenderingDetectorInitialized"); } private void configureCrashReporter(OpenTelemetryRumBuilder otelRumBuilder) { - CrashReporterInstrumentation instrumentation = AndroidInstrumentationLoader.getInstrumentation(CrashReporterInstrumentation.class); - if(instrumentation == null){ - Log.w(LOG_TAG, "Crash reporter instrumentation was not loaded! Skipping configuration."); + CrashReporterInstrumentation instrumentation = + AndroidInstrumentationLoader.getInstrumentation(CrashReporterInstrumentation.class); + if (instrumentation == null) { + Log.w( + LOG_TAG, + "Crash reporter instrumentation was not loaded! Skipping configuration."); return; } ErrorIdentifierExtractor extractor = new ErrorIdentifierExtractor(application); @@ -312,17 +346,16 @@ private void configureCrashReporter(OpenTelemetryRumBuilder otelRumBuilder) { String uuid = errorIdentifierInfo.getCustomUUID(); instrumentation.addAttributesExtractor( - RuntimeDetailsExtractor.create( - app.getApplicationContext())) - .addAttributesExtractor(new CrashComponentExtractor()); + RuntimeDetailsExtractor.create(application.getApplicationContext())); + instrumentation.addAttributesExtractor(new CrashComponentExtractor()); - if (applicationId != null){ + if (applicationId != null) { instrumentation.addAttributesExtractor(constant(APPLICATION_ID_KEY, applicationId)); } - if (versionCode != null){ + if (versionCode != null) { instrumentation.addAttributesExtractor(constant(APP_VERSION_CODE_KEY, versionCode)); } - if (uuid != null){ + if (uuid != null) { instrumentation.addAttributesExtractor(constant(SPLUNK_OLLY_UUID_KEY, uuid)); } @@ -332,166 +365,159 @@ private void configureCrashReporter(OpenTelemetryRumBuilder otelRumBuilder) { // visible for testing @NonNull SpanExporter buildSpanExporter(SpanExporter delegate) { - OtlpHttpSpanExporter otlp = OtlpHttpSpanExporter.builder() - .setEndpoint(builder.beaconEndpoint) - .addHeader("X-SF-Token", builder.rumAccessToken) - .build(); + OtlpHttpSpanExporter otlp = + OtlpHttpSpanExporter.builder() + .setEndpoint(builder.beaconEndpoint) + .addHeader("X-SF-Token", builder.rumAccessToken) + .build(); SpanExporter splunkTranslatedExporter = - new SplunkSpanDataModifier( - otlp, - builder.isReactNativeSupportEnabled(), - true); + new SplunkSpanDataModifier(otlp, builder.isReactNativeSupportEnabled(), true); SpanExporter filteredExporter = builder.decorateWithSpanFilter(splunkTranslatedExporter); initializationEvents.emit("otlp span exporter initialized"); - - // Wire up the logging exporter, if enabled. - if (builder.isDebugEnabled()) { - initializationEvents.emit("debugSpanExporterInitialized"); - SpanExporter result = SpanExporter.composite(LoggingSpanExporter.create(), filteredExporter); - return result; - } return filteredExporter; } -// -// private SpanExporter buildExporter( -// CurrentNetworkProvider currentNetworkProvider, -// VisibleScreenService visibleScreenService) { -// xxxx -// if (builder.isDebugEnabled()) { -// // tell the Zipkin exporter to shut up already. We're on mobile, network stuff happens. -// // we'll do our best to hang on to the spans with the wrapping BufferingExporter. -// ZipkinSpanExporter.baseLogger.setLevel(Level.SEVERE); -// initializationEvents.emit("logger setup complete"); -// } -// -// if (builder.isDiskBufferingEnabled()) { -// return buildStorageBufferingExporter( -// currentNetworkProvider, constructSpanFileProvider(visibleScreenService)); -// } -// -// return buildMemoryBufferingThrottledExporter( -// currentNetworkProvider, constructBacklogProvider(visibleScreenService)); -// } -// -// //TODO: Make this use OTLP buffering via upstream -// private SpanExporter buildStorageBufferingExporter( -// CurrentNetworkProvider currentNetworkProvider, SpanStorage spanStorage) { -// Sender sender = buildCustomizedZipkinSender(); -// -// BandwidthTracker bandwidthTracker = new BandwidthTracker(); -// -// FileSender fileSender = -// FileSender.builder().sender(sender).bandwidthTracker(bandwidthTracker).build(); -// DiskToZipkinExporter diskToZipkinExporter = -// DiskToZipkinExporter.builder() -// .connectionUtil(currentNetworkProvider) -// .fileSender(fileSender) -// .bandwidthTracker(bandwidthTracker) -// .spanFileProvider(spanStorage) -// .build(); -// diskToZipkinExporter.startPolling(); -// -// return getToDiskExporter(spanStorage); -// } -// -// @NonNull -// private Sender buildCustomizedZipkinSender() { -// OkHttpSender.Builder okBuilder = -// OkHttpSender.newBuilder().endpoint(getEndpointWithAuthTokenQueryParam()); -// builder.httpSenderCustomizer.customize(okBuilder); -// return okBuilder.build(); -// } + // + // private SpanExporter buildExporter( + // CurrentNetworkProvider currentNetworkProvider, + // VisibleScreenService visibleScreenService) { + // xxxx + // if (builder.isDebugEnabled()) { + // // tell the Zipkin exporter to shut up already. We're on mobile, network stuff + // happens. + // // we'll do our best to hang on to the spans with the wrapping BufferingExporter. + // ZipkinSpanExporter.baseLogger.setLevel(Level.SEVERE); + // initializationEvents.emit("logger setup complete"); + // } + // + // if (builder.isDiskBufferingEnabled()) { + // return buildStorageBufferingExporter( + // currentNetworkProvider, constructSpanFileProvider(visibleScreenService)); + // } + // + // return buildMemoryBufferingThrottledExporter( + // currentNetworkProvider, constructBacklogProvider(visibleScreenService)); + // } + // + // //TODO: Make this use OTLP buffering via upstream + // private SpanExporter buildStorageBufferingExporter( + // CurrentNetworkProvider currentNetworkProvider, SpanStorage spanStorage) { + // Sender sender = buildCustomizedZipkinSender(); + // + // BandwidthTracker bandwidthTracker = new BandwidthTracker(); + // + // FileSender fileSender = + // + // FileSender.builder().sender(sender).bandwidthTracker(bandwidthTracker).build(); + // DiskToZipkinExporter diskToZipkinExporter = + // DiskToZipkinExporter.builder() + // .connectionUtil(currentNetworkProvider) + // .fileSender(fileSender) + // .bandwidthTracker(bandwidthTracker) + // .spanFileProvider(spanStorage) + // .build(); + // diskToZipkinExporter.startPolling(); + // + // return getToDiskExporter(spanStorage); + // } + // + // @NonNull + // private Sender buildCustomizedZipkinSender() { + // OkHttpSender.Builder okBuilder = + // OkHttpSender.newBuilder().endpoint(getEndpointWithAuthTokenQueryParam()); + // builder.httpSenderCustomizer.customize(okBuilder); + // return okBuilder.build(); + // } @NonNull private String getEndpointWithAuthTokenQueryParam() { return builder.beaconEndpoint + "?auth=" + builder.rumAccessToken; } -// private SpanExporter buildMemoryBufferingThrottledExporter( -// CurrentNetworkProvider currentNetworkProvider, MemorySpanBuffer backlogProvider) { -// SpanExporter zipkinSpanExporter = getCoreSpanExporter(); -// MemoryBufferingExporter memoryBufferingExporter = -// new MemoryBufferingExporter( -// currentNetworkProvider, zipkinSpanExporter, backlogProvider); -// return buildThrottlingExporter(memoryBufferingExporter); -// } - -// private static ThrottlingExporter buildThrottlingExporter( -// MemoryBufferingExporter memoryBufferingExporter) { -// return ThrottlingExporter.newBuilder(memoryBufferingExporter) -// .categorizeByAttribute(COMPONENT_KEY) -// .maxSpansInWindow(100) -// .windowSize(Duration.ofSeconds(30)) -// .build(); -// } - -// SpanExporter getToDiskExporter(SpanStorage spanStorage) { -// return new LazyInitSpanExporter( -// () -> -// ZipkinWriteToDiskExporterFactory.create( -// builder.maxUsageMegabytes, spanStorage)); -// } -// -// // visible for testing -// SpanExporter getCoreSpanExporter() { -// Supplier exporterSupplier = supplyZipkinExporter(); -// if (builder.shouldUseOtlpExporter()) { -// exporterSupplier = supplyOtlpExporter(); -// } -// // return a lazy init exporter so the main thread doesn't block on the setup. -// return new LazyInitSpanExporter(exporterSupplier); -// } - -// -// //TODO: This needs to go away as part of 2.0, OTLP only -// @NonNull -// private Supplier supplyZipkinExporter() { -// String endpoint = getEndpointWithAuthTokenQueryParam(); -// return () -> -// ZipkinSpanExporter.builder() -// .setEncoder(new CustomZipkinEncoder()) -// .setEndpoint(endpoint) -// // remove the local IP address -// .setLocalIpAddressSupplier(() -> null) -// .setSender(buildCustomizedZipkinSender()) -// .build(); -// } -// -// private static class LazyInitSpanExporter implements SpanExporter { -// @Nullable private volatile SpanExporter delegate; -// private final Supplier s; -// -// public LazyInitSpanExporter(Supplier s) { -// this.s = s; -// } -// -// private SpanExporter getDelegate() { -// SpanExporter d = delegate; -// if (d == null) { -// synchronized (this) { -// d = delegate; -// if (d == null) { -// delegate = d = s.get(); -// } -// } -// } -// return d; -// } -// -// @Override -// public CompletableResultCode export(Collection spans) { -// return getDelegate().export(spans); -// } -// -// @Override -// public CompletableResultCode flush() { -// return getDelegate().flush(); -// } -// -// @Override -// public CompletableResultCode shutdown() { -// return getDelegate().shutdown(); -// } -// } + // private SpanExporter buildMemoryBufferingThrottledExporter( + // CurrentNetworkProvider currentNetworkProvider, MemorySpanBuffer backlogProvider) { + // SpanExporter zipkinSpanExporter = getCoreSpanExporter(); + // MemoryBufferingExporter memoryBufferingExporter = + // new MemoryBufferingExporter( + // currentNetworkProvider, zipkinSpanExporter, backlogProvider); + // return buildThrottlingExporter(memoryBufferingExporter); + // } + + // private static ThrottlingExporter buildThrottlingExporter( + // MemoryBufferingExporter memoryBufferingExporter) { + // return ThrottlingExporter.newBuilder(memoryBufferingExporter) + // .categorizeByAttribute(COMPONENT_KEY) + // .maxSpansInWindow(100) + // .windowSize(Duration.ofSeconds(30)) + // .build(); + // } + + // SpanExporter getToDiskExporter(SpanStorage spanStorage) { + // return new LazyInitSpanExporter( + // () -> + // ZipkinWriteToDiskExporterFactory.create( + // builder.maxUsageMegabytes, spanStorage)); + // } + // + // // visible for testing + // SpanExporter getCoreSpanExporter() { + // Supplier exporterSupplier = supplyZipkinExporter(); + // if (builder.shouldUseOtlpExporter()) { + // exporterSupplier = supplyOtlpExporter(); + // } + // // return a lazy init exporter so the main thread doesn't block on the setup. + // return new LazyInitSpanExporter(exporterSupplier); + // } + + // + // //TODO: This needs to go away as part of 2.0, OTLP only + // @NonNull + // private Supplier supplyZipkinExporter() { + // String endpoint = getEndpointWithAuthTokenQueryParam(); + // return () -> + // ZipkinSpanExporter.builder() + // .setEncoder(new CustomZipkinEncoder()) + // .setEndpoint(endpoint) + // // remove the local IP address + // .setLocalIpAddressSupplier(() -> null) + // .setSender(buildCustomizedZipkinSender()) + // .build(); + // } + // + // private static class LazyInitSpanExporter implements SpanExporter { + // @Nullable private volatile SpanExporter delegate; + // private final Supplier s; + // + // public LazyInitSpanExporter(Supplier s) { + // this.s = s; + // } + // + // private SpanExporter getDelegate() { + // SpanExporter d = delegate; + // if (d == null) { + // synchronized (this) { + // d = delegate; + // if (d == null) { + // delegate = d = s.get(); + // } + // } + // } + // return d; + // } + // + // @Override + // public CompletableResultCode export(Collection spans) { + // return getDelegate().export(spans); + // } + // + // @Override + // public CompletableResultCode flush() { + // return getDelegate().flush(); + // } + // + // @Override + // public CompletableResultCode shutdown() { + // return getDelegate().shutdown(); + // } + // } } 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 940ea65c..b6abd505 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 @@ -39,10 +39,9 @@ import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.instrumentation.okhttp.v3_0.OkHttpTelemetry; import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.logs.internal.SdkEventLoggerProvider; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; - -import io.opentelemetry.sdk.logs.internal.SdkEventLoggerProvider; import okhttp3.Call; import okhttp3.OkHttpClient; @@ -214,7 +213,8 @@ public String getRumSessionId() { * Emits a custom event to RUM monitoring. This can be useful to capture business events, or * simply add instrumentation to your application. * - *

This event will be sent to the RUM ingest along with other, auto-generated spans and events. + *

This event will be sent to the RUM ingest along with other, auto-generated spans and + * events. * * @param name The name of the event. * @param attributes Any {@link Attributes} to associate with the event. @@ -226,12 +226,12 @@ public void emitEvent(String name, Attributes attributes) { public void emitEvent(String name, String instrumentationScope, Attributes attributes) { LoggerProvider loggerProvider = openTelemetryRum.getOpenTelemetry().getLogsBridge(); - EventLogger eventLogger = SdkEventLoggerProvider.create(loggerProvider) - .get(instrumentationScope); + EventLogger eventLogger = + SdkEventLoggerProvider.create(loggerProvider).get(instrumentationScope); eventLogger.builder(name).setAttributes(attributes).emit(); } - //TODO: Allow emitEvent() with a custom Body + // TODO: Allow emitEvent() with a custom Body /** * Start a Span to time a named workflow. diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkRumBuilder.java b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkRumBuilder.java index 69d6c838..4d524518 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkRumBuilder.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkRumBuilder.java @@ -366,19 +366,21 @@ public SplunkRumBuilder enableBackgroundInstrumentationDeferredUntilForeground() * * @return {@code this} */ -// public SplunkRumBuilder enableExperimentalOtlpExporter() { -// if (isDiskBufferingEnabled()) { -// Log.w(SplunkRum.LOG_TAG, "OTLP export is not yet compatible with disk buffering!"); -// Log.w(SplunkRum.LOG_TAG, "Please disable disk buffering in order to use OTLP export."); -// Log.w(SplunkRum.LOG_TAG, "OTLP is not enabled."); -// return this; -// } -// configFlags.enableOtlpExporter(); -// if (this.realm != null) { -// configureBeaconForOtlp(); -// } -// return this; -// } + // public SplunkRumBuilder enableExperimentalOtlpExporter() { + // if (isDiskBufferingEnabled()) { + // Log.w(SplunkRum.LOG_TAG, "OTLP export is not yet compatible with disk + // buffering!"); + // Log.w(SplunkRum.LOG_TAG, "Please disable disk buffering in order to use OTLP + // export."); + // Log.w(SplunkRum.LOG_TAG, "OTLP is not enabled."); + // return this; + // } + // configFlags.enableOtlpExporter(); + // if (this.realm != null) { + // configureBeaconForOtlp(); + // } + // return this; + // } // one day maybe these can use kotlin delegation ConfigFlags getConfigFlags() { diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkScreenNameExtractor.java b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkScreenNameExtractor.java index e2d5042b..4d33ce6e 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkScreenNameExtractor.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkScreenNameExtractor.java @@ -18,10 +18,9 @@ import android.app.Activity; import androidx.fragment.app.Fragment; -import java.util.function.Function; - import io.opentelemetry.android.instrumentation.annotations.RumScreenName; import io.opentelemetry.android.instrumentation.common.ScreenNameExtractor; +import java.util.function.Function; /** * Screen name extractor that supports the original Splunk annotation but falls back to diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/StartTypeAwareMemorySpanBuffer.java b/splunk-otel-android/src/main/java/com/splunk/rum/StartTypeAwareMemorySpanBuffer.java index e1af2a33..a2f8075a 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/StartTypeAwareMemorySpanBuffer.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/StartTypeAwareMemorySpanBuffer.java @@ -16,15 +16,14 @@ package com.splunk.rum; +import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService; +import io.opentelemetry.sdk.trace.data.SpanData; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Queue; -import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService; -import io.opentelemetry.sdk.trace.data.SpanData; - public class StartTypeAwareMemorySpanBuffer implements MemorySpanBuffer { private final VisibleScreenService visibleScreenTracker; diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/StartTypeAwareSpanStorage.java b/splunk-otel-android/src/main/java/com/splunk/rum/StartTypeAwareSpanStorage.java index 6a2fe59f..5354a5b3 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/StartTypeAwareSpanStorage.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/StartTypeAwareSpanStorage.java @@ -19,15 +19,12 @@ import static com.splunk.rum.SplunkRum.LOG_TAG; import android.util.Log; - import androidx.annotation.VisibleForTesting; - +import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService; import java.io.File; import java.util.UUID; import java.util.stream.Stream; -import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService; - /*** * Store span files to /span/background/@uniqueId/ for spans created when the app started in the background. * If the app is brought to foreground and the same session ID still in use, the background spans are moved to /span for eventual sending. diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/RumInitializerTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/RumInitializerTest.java index bff277e6..9622c0f5 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/RumInitializerTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/RumInitializerTest.java @@ -21,14 +21,11 @@ import static io.opentelemetry.android.common.RumConstants.SCREEN_NAME_KEY; import static io.opentelemetry.api.common.AttributeKey.stringKey; import static java.util.Collections.emptyList; -import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static java.util.concurrent.TimeUnit.MINUTES; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.app.Application; @@ -36,10 +33,7 @@ import android.content.pm.ApplicationInfo; import android.os.Looper; import com.splunk.rum.incubating.HttpSenderCustomizer; - import io.opentelemetry.android.instrumentation.activity.startup.AppStartupTimer; -import io.opentelemetry.android.internal.services.network.CurrentNetworkProvider; -import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.SpanKind; @@ -49,9 +43,7 @@ import io.opentelemetry.sdk.trace.data.EventData; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.data.StatusData; -import io.opentelemetry.sdk.trace.export.SpanExporter; import io.opentelemetry.semconv.ExceptionAttributes; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.atomic.AtomicReference; @@ -88,16 +80,17 @@ void initializationSpan() { InMemorySpanExporter testExporter = InMemorySpanExporter.create(); AppStartupTimer startupTimer = new AppStartupTimer(); - RumInitializer testInitializer = new RumInitializer(splunkRumBuilder, application, startupTimer); - //TODO: This is probably broken -// { -// @Override -// SpanExporter buildFilteringExporter( -// CurrentNetworkProvider connectionUtil, -// VisibleScreenService visibleScreenService) { -// return testExporter; -// } -// }; + RumInitializer testInitializer = + new RumInitializer(splunkRumBuilder, application, startupTimer); + // TODO: This is probably broken + // { + // @Override + // SpanExporter buildFilteringExporter( + // CurrentNetworkProvider connectionUtil, + // VisibleScreenService visibleScreenService) { + // return testExporter; + // } + // }; SplunkRum splunkRum = testInitializer.initialize(mainLooper); startupTimer.runCompletionCallback(); splunkRum.flushSpans(); @@ -150,16 +143,16 @@ void spanLimitsAreConfigured() { AppStartupTimer startupTimer = new AppStartupTimer(); RumInitializer testInitializer = new RumInitializer(splunkRumBuilder, application, startupTimer); - //TODO: This is probably broken - -// { -// @Override -// SpanExporter buildFilteringExporter( -// CurrentNetworkProvider connectionUtil, -// VisibleScreenTracker visibleScreenTracker) { -// return testExporter; -// } -// }; + // TODO: This is probably broken + + // { + // @Override + // SpanExporter buildFilteringExporter( + // CurrentNetworkProvider connectionUtil, + // VisibleScreenTracker visibleScreenTracker) { + // return testExporter; + // } + // }; SplunkRum splunkRum = testInitializer.initialize(mainLooper); splunkRum.flushSpans(); @@ -182,55 +175,55 @@ void spanLimitsAreConfigured() { assertEquals(makeString('a', RumInitializer.MAX_ATTRIBUTE_LENGTH), truncatedValue); } - //TODO: Delete or rebuild this + // TODO: Delete or rebuild this /** Verify that we have buffering in place in our exporter implementation. */ -// @Test -// void verifyExporterBuffering() { -// SplunkRumBuilder splunkRumBuilder = -// new SplunkRumBuilder() -// .setRealm("dev") -// .setApplicationName("testApp") -// .setRumAccessToken("accessToken"); -// AppStartupTimer startupTimer = new AppStartupTimer(); -// InMemorySpanExporter testExporter = InMemorySpanExporter.create(); -// -// RumInitializer testInitializer = -// new RumInitializer(splunkRumBuilder, application, startupTimer); -// //TODO: This is probably broken -//// { -//// @Override -//// SpanExporter getCoreSpanExporter() { -//// return testExporter; -//// } -//// }; -// -// CurrentNetworkProvider currentNetworkProvider = mock(CurrentNetworkProvider.class); -// CurrentNetwork currentNetwork = mock(CurrentNetwork.class); -// -// when(currentNetworkProvider.refreshNetworkStatus()).thenReturn(currentNetwork); -// when(currentNetwork.isOnline()).thenReturn(false, true); -// -// long currentTimeNanos = MILLISECONDS.toNanos(System.currentTimeMillis()); -// -// SpanExporter spanExporter = -// testInitializer.buildFilteringExporter( -// currentNetworkProvider, new VisibleScreenTracker()); -// List batch1 = new ArrayList<>(); -// for (int i = 0; i < 99; i++) { -// batch1.add(createTestSpan(currentTimeNanos - MINUTES.toNanos(1))); -// } -// // space out the two batches, so they are well under the rate limit -// List batch2 = new ArrayList<>(); -// for (int i = 0; i < 99; i++) { -// batch2.add(createTestSpan(currentTimeNanos)); -// } -// spanExporter.export(batch1); -// spanExporter.export(batch2); -// -// // we want to verify that everything got exported, including everything buffered while -// // offline. -// assertEquals(198, testExporter.getFinishedSpanItems().size()); -// } + // @Test + // void verifyExporterBuffering() { + // SplunkRumBuilder splunkRumBuilder = + // new SplunkRumBuilder() + // .setRealm("dev") + // .setApplicationName("testApp") + // .setRumAccessToken("accessToken"); + // AppStartupTimer startupTimer = new AppStartupTimer(); + // InMemorySpanExporter testExporter = InMemorySpanExporter.create(); + // + // RumInitializer testInitializer = + // new RumInitializer(splunkRumBuilder, application, startupTimer); + // //TODO: This is probably broken + //// { + //// @Override + //// SpanExporter getCoreSpanExporter() { + //// return testExporter; + //// } + //// }; + // + // CurrentNetworkProvider currentNetworkProvider = mock(CurrentNetworkProvider.class); + // CurrentNetwork currentNetwork = mock(CurrentNetwork.class); + // + // when(currentNetworkProvider.refreshNetworkStatus()).thenReturn(currentNetwork); + // when(currentNetwork.isOnline()).thenReturn(false, true); + // + // long currentTimeNanos = MILLISECONDS.toNanos(System.currentTimeMillis()); + // + // SpanExporter spanExporter = + // testInitializer.buildFilteringExporter( + // currentNetworkProvider, new VisibleScreenTracker()); + // List batch1 = new ArrayList<>(); + // for (int i = 0; i < 99; i++) { + // batch1.add(createTestSpan(currentTimeNanos - MINUTES.toNanos(1))); + // } + // // space out the two batches, so they are well under the rate limit + // List batch2 = new ArrayList<>(); + // for (int i = 0; i < 99; i++) { + // batch2.add(createTestSpan(currentTimeNanos)); + // } + // spanExporter.export(batch1); + // spanExporter.export(batch2); + // + // // we want to verify that everything got exported, including everything buffered while + // // offline. + // assertEquals(198, testExporter.getFinishedSpanItems().size()); + // } private TestSpanData createTestSpan(long startTimeNanos) { return TestSpanData.builder() @@ -284,13 +277,13 @@ void shouldTranslateExceptionEventsToSpanAttributes() { AppStartupTimer appStartupTimer = new AppStartupTimer(); RumInitializer initializer = new RumInitializer(splunkRumBuilder, application, appStartupTimer); - //TODO: Fix this is probably broken -// { -// @Override -// SpanExporter getCoreSpanExporter() { -// return spanExporter; -// } -// }; + // TODO: Fix this is probably broken + // { + // @Override + // SpanExporter getCoreSpanExporter() { + // return spanExporter; + // } + // }; SplunkRum splunkRum = initializer.initialize(mainLooper); appStartupTimer.runCompletionCallback(); @@ -351,15 +344,15 @@ void canSetScreenName() { when(application.getApplicationContext()).thenReturn(context); when(application.getMainLooper()).thenReturn(mainLooper); - //TODO: Fix this is probably broken + // TODO: Fix this is probably broken RumInitializer testInitializer = new RumInitializer(splunkRumBuilder, application, new AppStartupTimer()); -// { -// @Override -// SpanExporter getCoreSpanExporter() { -// return testExporter; -// } -// }; + // { + // @Override + // SpanExporter getCoreSpanExporter() { + // return testExporter; + // } + // }; SplunkRum splunkRum = testInitializer.initialize(mainLooper); splunkRum.experimentalSetScreenName("screen-1"); diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/SplunkRumBuilderTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/SplunkRumBuilderTest.java index 162ea93c..4a50abaf 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/SplunkRumBuilderTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/SplunkRumBuilderTest.java @@ -16,7 +16,6 @@ package com.splunk.rum; -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; 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 65b23997..1b518bdf 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 @@ -77,7 +77,8 @@ class SplunkRumTest { @BeforeEach void setup() { application = mock(Application.class, RETURNS_DEEP_STUBS); - screenNameAppender = new SettableScreenAttributesAppender(new VisibleScreenService(application)); + screenNameAppender = + new SettableScreenAttributesAppender(new VisibleScreenService(application)); tracer = otelTesting.getOpenTelemetry().getTracer("testTracer"); SplunkRum.resetSingletonForTest(); diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/StartTypeAwareSpanStorageTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/StartTypeAwareSpanStorageTest.java index f820d548..fb3505c5 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/StartTypeAwareSpanStorageTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/StartTypeAwareSpanStorageTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService; import java.io.File; import java.util.ArrayList; import java.util.List; @@ -36,8 +37,6 @@ import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; -import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService; - class StartTypeAwareSpanStorageTest { final File rootDir = new File("files/"); From 64e5824a697e12259f9d6ceef21e5fabe686a6a2 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 17 Oct 2024 14:33:23 -0700 Subject: [PATCH 20/29] remove duplication --- .../java/com/splunk/rum/RumInitializer.java | 53 ++++++++----------- 1 file changed, 21 insertions(+), 32 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 7f165bed..d7f80571 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 @@ -53,6 +53,7 @@ import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService; import io.opentelemetry.exporter.logging.LoggingSpanExporter; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.resources.ResourceBuilder; import io.opentelemetry.sdk.trace.SpanLimits; @@ -60,6 +61,7 @@ import io.opentelemetry.sdk.trace.export.SpanExporter; import io.opentelemetry.sdk.trace.samplers.Sampler; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; import java.util.function.Supplier; class RumInitializer { @@ -202,10 +204,10 @@ SplunkRum initialize(Looper mainLooper) { configureAnrInstrumentation(); } if (builder.isSlowRenderingDetectionEnabled()) { - configureSlowRenderingInstrumentation(otelRumBuilder); + configureSlowRenderingInstrumentation(); } if (builder.isCrashReportingEnabled()) { - configureCrashReporter(otelRumBuilder); + configureCrashReporter(); } SettableScreenAttributesAppender screenAttributesAppender = @@ -295,28 +297,13 @@ private void configureAnrInstrumentation() { Log.w(LOG_TAG, "ANR instrumentation was not loaded! Skipping configuration."); return; } - ErrorIdentifierExtractor extractor = new ErrorIdentifierExtractor(application); - ErrorIdentifierInfo errorIdentifierInfo = extractor.extractInfo(); - String applicationId = errorIdentifierInfo.getApplicationId(); - String versionCode = errorIdentifierInfo.getVersionCode(); - String uuid = errorIdentifierInfo.getCustomUUID(); - instrumentation.addAttributesExtractor(constant(COMPONENT_KEY, COMPONENT_ERROR)); - - if (applicationId != null) { - instrumentation.addAttributesExtractor(constant(APPLICATION_ID_KEY, applicationId)); - } - if (versionCode != null) { - instrumentation.addAttributesExtractor(constant(APP_VERSION_CODE_KEY, versionCode)); - } - if (uuid != null) { - instrumentation.addAttributesExtractor(constant(SPLUNK_OLLY_UUID_KEY, uuid)); - } + addErrorIdentifyingAttributes(instrumentation::addAttributesExtractor); initializationEvents.emit("anrMonitorInitialized"); } - private void configureSlowRenderingInstrumentation(OpenTelemetryRumBuilder otelRumBuilder) { + private void configureSlowRenderingInstrumentation() { SlowRenderingInstrumentation instrumentation = AndroidInstrumentationLoader.getInstrumentation(SlowRenderingInstrumentation.class); if (instrumentation == null) { @@ -330,7 +317,7 @@ private void configureSlowRenderingInstrumentation(OpenTelemetryRumBuilder otelR initializationEvents.emit("slowRenderingDetectorInitialized"); } - private void configureCrashReporter(OpenTelemetryRumBuilder otelRumBuilder) { + private void configureCrashReporter() { CrashReporterInstrumentation instrumentation = AndroidInstrumentationLoader.getInstrumentation(CrashReporterInstrumentation.class); if (instrumentation == null) { @@ -339,27 +326,29 @@ private void configureCrashReporter(OpenTelemetryRumBuilder otelRumBuilder) { "Crash reporter instrumentation was not loaded! Skipping configuration."); return; } - ErrorIdentifierExtractor extractor = new ErrorIdentifierExtractor(application); - ErrorIdentifierInfo errorIdentifierInfo = extractor.extractInfo(); - String applicationId = errorIdentifierInfo.getApplicationId(); - String versionCode = errorIdentifierInfo.getVersionCode(); - String uuid = errorIdentifierInfo.getCustomUUID(); - instrumentation.addAttributesExtractor( RuntimeDetailsExtractor.create(application.getApplicationContext())); instrumentation.addAttributesExtractor(new CrashComponentExtractor()); + addErrorIdentifyingAttributes(instrumentation::addAttributesExtractor); + + initializationEvents.emit("crashReportingInitialized"); + } + private void addErrorIdentifyingAttributes( + Consumer> consumer) { + ErrorIdentifierExtractor extractor = new ErrorIdentifierExtractor(application); + ErrorIdentifierInfo errorIdentifierInfo = extractor.extractInfo(); + String applicationId = errorIdentifierInfo.getApplicationId(); + String versionCode = errorIdentifierInfo.getVersionCode(); if (applicationId != null) { - instrumentation.addAttributesExtractor(constant(APPLICATION_ID_KEY, applicationId)); + consumer.accept(constant(APPLICATION_ID_KEY, applicationId)); } if (versionCode != null) { - instrumentation.addAttributesExtractor(constant(APP_VERSION_CODE_KEY, versionCode)); + consumer.accept(constant(APP_VERSION_CODE_KEY, versionCode)); } - if (uuid != null) { - instrumentation.addAttributesExtractor(constant(SPLUNK_OLLY_UUID_KEY, uuid)); + if (errorIdentifierInfo.getCustomUUID() != null) { + consumer.accept(constant(SPLUNK_OLLY_UUID_KEY, errorIdentifierInfo.getCustomUUID())); } - - initializationEvents.emit("crashReportingInitialized"); } // visible for testing From 12410e77f3f71157a2b736226956126be36e66b6 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 17 Oct 2024 15:23:18 -0700 Subject: [PATCH 21/29] set up disk buffering --- .../java/com/splunk/rum/RumInitializer.java | 80 +++---------------- .../com/splunk/rum/ThrottlingExporter.java | 1 + 2 files changed, 12 insertions(+), 69 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 d7f80571..224e1eab 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 @@ -42,6 +42,7 @@ import io.opentelemetry.android.OpenTelemetryRumBuilder; import io.opentelemetry.android.RuntimeDetailsExtractor; import io.opentelemetry.android.config.OtelRumConfig; +import io.opentelemetry.android.features.diskbuffering.DiskBufferingConfiguration; import io.opentelemetry.android.instrumentation.AndroidInstrumentationLoader; import io.opentelemetry.android.instrumentation.activity.ActivityLifecycleInstrumentation; import io.opentelemetry.android.instrumentation.activity.startup.AppStartupTimer; @@ -51,6 +52,7 @@ import io.opentelemetry.android.internal.services.ServiceManager; import io.opentelemetry.android.internal.services.network.CurrentNetworkProvider; import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService; +import io.opentelemetry.api.common.Attributes; import io.opentelemetry.exporter.logging.LoggingSpanExporter; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; @@ -92,6 +94,8 @@ SplunkRum initialize(Looper mainLooper) { new GlobalAttributesSupplier(builder.globalAttributes); config.setGlobalAttributes(globalAttributeSupplier); + + // TODO: Note/document this instrumentation is now opt-in via application classpath via // build settings // if (!builder.isNetworkMonitorEnabled()) { @@ -99,6 +103,12 @@ SplunkRum initialize(Looper mainLooper) { // } config.disableScreenAttributes(); + DiskBufferingConfiguration diskBufferingConfig = DiskBufferingConfiguration.builder() + .setEnabled(builder.isDiskBufferingEnabled()) + .setMaxCacheSize(100_000_000) + .build(); + config.setDiskBufferingConfiguration(diskBufferingConfig); + OpenTelemetryRumBuilder otelRumBuilder = OpenTelemetryRum.builder(application, config); otelRumBuilder.mergeResource(createSplunkResource()); @@ -139,7 +149,7 @@ SplunkRum initialize(Looper mainLooper) { // }); // Inhibit the upstream exporter because we add our own BatchSpanProcessor - otelRumBuilder.addSpanExporterCustomizer(x -> new NoOpSpanExporter()); +// otelRumBuilder.addSpanExporterCustomizer(x -> new NoOpSpanExporter()); // Set span limits otelRumBuilder.addTracerProviderCustomizer( @@ -366,72 +376,11 @@ SpanExporter buildSpanExporter(SpanExporter delegate) { return filteredExporter; } - // - // private SpanExporter buildExporter( - // CurrentNetworkProvider currentNetworkProvider, - // VisibleScreenService visibleScreenService) { - // xxxx - // if (builder.isDebugEnabled()) { - // // tell the Zipkin exporter to shut up already. We're on mobile, network stuff - // happens. - // // we'll do our best to hang on to the spans with the wrapping BufferingExporter. - // ZipkinSpanExporter.baseLogger.setLevel(Level.SEVERE); - // initializationEvents.emit("logger setup complete"); - // } - // - // if (builder.isDiskBufferingEnabled()) { - // return buildStorageBufferingExporter( - // currentNetworkProvider, constructSpanFileProvider(visibleScreenService)); - // } - // - // return buildMemoryBufferingThrottledExporter( - // currentNetworkProvider, constructBacklogProvider(visibleScreenService)); - // } - // - // //TODO: Make this use OTLP buffering via upstream - // private SpanExporter buildStorageBufferingExporter( - // CurrentNetworkProvider currentNetworkProvider, SpanStorage spanStorage) { - // Sender sender = buildCustomizedZipkinSender(); - // - // BandwidthTracker bandwidthTracker = new BandwidthTracker(); - // - // FileSender fileSender = - // - // FileSender.builder().sender(sender).bandwidthTracker(bandwidthTracker).build(); - // DiskToZipkinExporter diskToZipkinExporter = - // DiskToZipkinExporter.builder() - // .connectionUtil(currentNetworkProvider) - // .fileSender(fileSender) - // .bandwidthTracker(bandwidthTracker) - // .spanFileProvider(spanStorage) - // .build(); - // diskToZipkinExporter.startPolling(); - // - // return getToDiskExporter(spanStorage); - // } - // - // @NonNull - // private Sender buildCustomizedZipkinSender() { - // OkHttpSender.Builder okBuilder = - // OkHttpSender.newBuilder().endpoint(getEndpointWithAuthTokenQueryParam()); - // builder.httpSenderCustomizer.customize(okBuilder); - // return okBuilder.build(); - // } - @NonNull private String getEndpointWithAuthTokenQueryParam() { return builder.beaconEndpoint + "?auth=" + builder.rumAccessToken; } - // private SpanExporter buildMemoryBufferingThrottledExporter( - // CurrentNetworkProvider currentNetworkProvider, MemorySpanBuffer backlogProvider) { - // SpanExporter zipkinSpanExporter = getCoreSpanExporter(); - // MemoryBufferingExporter memoryBufferingExporter = - // new MemoryBufferingExporter( - // currentNetworkProvider, zipkinSpanExporter, backlogProvider); - // return buildThrottlingExporter(memoryBufferingExporter); - // } - // private static ThrottlingExporter buildThrottlingExporter( // MemoryBufferingExporter memoryBufferingExporter) { // return ThrottlingExporter.newBuilder(memoryBufferingExporter) @@ -440,13 +389,6 @@ private String getEndpointWithAuthTokenQueryParam() { // .windowSize(Duration.ofSeconds(30)) // .build(); // } - - // SpanExporter getToDiskExporter(SpanStorage spanStorage) { - // return new LazyInitSpanExporter( - // () -> - // ZipkinWriteToDiskExporterFactory.create( - // builder.maxUsageMegabytes, spanStorage)); - // } // // // visible for testing // SpanExporter getCoreSpanExporter() { diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/ThrottlingExporter.java b/splunk-otel-android/src/main/java/com/splunk/rum/ThrottlingExporter.java index 3dfe836c..08c655b0 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/ThrottlingExporter.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/ThrottlingExporter.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.function.Function; +//TODO: jjp - This class is no longer wired up and could be removed class ThrottlingExporter implements SpanExporter { private final SpanExporter delegate; private final Function categoryFunction; From d08085d51aeb1c8fb027f82f2784d817ff19a5be Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 17 Oct 2024 15:28:04 -0700 Subject: [PATCH 22/29] spotless --- .../main/java/com/splunk/rum/RumInitializer.java | 15 ++++++--------- .../java/com/splunk/rum/ThrottlingExporter.java | 2 +- 2 files changed, 7 insertions(+), 10 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 224e1eab..14ac81b4 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 @@ -36,7 +36,6 @@ import android.util.Log; import androidx.annotation.NonNull; import com.splunk.rum.internal.GlobalAttributesSupplier; -import com.splunk.rum.internal.NoOpSpanExporter; import com.splunk.rum.internal.UInt32QuadXorTraceIdRatioSampler; import io.opentelemetry.android.OpenTelemetryRum; import io.opentelemetry.android.OpenTelemetryRumBuilder; @@ -52,7 +51,6 @@ import io.opentelemetry.android.internal.services.ServiceManager; import io.opentelemetry.android.internal.services.network.CurrentNetworkProvider; import io.opentelemetry.android.internal.services.visiblescreen.VisibleScreenService; -import io.opentelemetry.api.common.Attributes; import io.opentelemetry.exporter.logging.LoggingSpanExporter; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; @@ -94,8 +92,6 @@ SplunkRum initialize(Looper mainLooper) { new GlobalAttributesSupplier(builder.globalAttributes); config.setGlobalAttributes(globalAttributeSupplier); - - // TODO: Note/document this instrumentation is now opt-in via application classpath via // build settings // if (!builder.isNetworkMonitorEnabled()) { @@ -103,10 +99,11 @@ SplunkRum initialize(Looper mainLooper) { // } config.disableScreenAttributes(); - DiskBufferingConfiguration diskBufferingConfig = DiskBufferingConfiguration.builder() - .setEnabled(builder.isDiskBufferingEnabled()) - .setMaxCacheSize(100_000_000) - .build(); + DiskBufferingConfiguration diskBufferingConfig = + DiskBufferingConfiguration.builder() + .setEnabled(builder.isDiskBufferingEnabled()) + .setMaxCacheSize(100_000_000) + .build(); config.setDiskBufferingConfiguration(diskBufferingConfig); OpenTelemetryRumBuilder otelRumBuilder = OpenTelemetryRum.builder(application, config); @@ -149,7 +146,7 @@ SplunkRum initialize(Looper mainLooper) { // }); // Inhibit the upstream exporter because we add our own BatchSpanProcessor -// otelRumBuilder.addSpanExporterCustomizer(x -> new NoOpSpanExporter()); + // otelRumBuilder.addSpanExporterCustomizer(x -> new NoOpSpanExporter()); // Set span limits otelRumBuilder.addTracerProviderCustomizer( diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/ThrottlingExporter.java b/splunk-otel-android/src/main/java/com/splunk/rum/ThrottlingExporter.java index 08c655b0..7594e361 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/ThrottlingExporter.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/ThrottlingExporter.java @@ -31,7 +31,7 @@ import java.util.Map; import java.util.function.Function; -//TODO: jjp - This class is no longer wired up and could be removed +// TODO: jjp - This class is no longer wired up and could be removed class ThrottlingExporter implements SpanExporter { private final SpanExporter delegate; private final Function categoryFunction; From 6195d047997c5c958ff6fe353e199c4728eb1824 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 17 Oct 2024 15:29:07 -0700 Subject: [PATCH 23/29] remove dead zipkin classes --- .../com/splunk/rum/CustomZipkinEncoder.java | 62 --------- .../com/splunk/rum/ZipkinToDiskSender.java | 127 ------------------ .../rum/ZipkinWriteToDiskExporterFactory.java | 51 ------- .../splunk/rum/CustomZipkinEncoderTest.java | 45 ------- .../splunk/rum/ZipkinToDiskSenderTest.java | 127 ------------------ 5 files changed, 412 deletions(-) delete mode 100644 splunk-otel-android/src/main/java/com/splunk/rum/CustomZipkinEncoder.java delete mode 100644 splunk-otel-android/src/main/java/com/splunk/rum/ZipkinToDiskSender.java delete mode 100644 splunk-otel-android/src/main/java/com/splunk/rum/ZipkinWriteToDiskExporterFactory.java delete mode 100644 splunk-otel-android/src/test/java/com/splunk/rum/CustomZipkinEncoderTest.java delete mode 100644 splunk-otel-android/src/test/java/com/splunk/rum/ZipkinToDiskSenderTest.java diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/CustomZipkinEncoder.java b/splunk-otel-android/src/main/java/com/splunk/rum/CustomZipkinEncoder.java deleted file mode 100644 index 7bd1d0da..00000000 --- a/splunk-otel-android/src/main/java/com/splunk/rum/CustomZipkinEncoder.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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. - */ - -package com.splunk.rum; - -import java.nio.charset.StandardCharsets; -import zipkin2.Span; -import zipkin2.internal.JsonCodec; -import zipkin2.internal.V2SpanWriter; -import zipkin2.internal.WriteBuffer; -import zipkin2.reporter.BytesEncoder; -import zipkin2.reporter.Encoding; - -/** - * We need a custom encoder to correct for the fact that the zipkin Span.Builder lowercases all Span - * names. - * - *

SplunkSpanDataModifier#SPLUNK_OPERATION_KEY}) with the span name properly cased, then - * correcting the span name here at encoding time. - */ -class CustomZipkinEncoder implements BytesEncoder { - - private final WriteBuffer.Writer writer = new V2SpanWriter(); - - @Override - public Encoding encoding() { - return Encoding.JSON; - } - - @Override - public int sizeInBytes(Span span) { - return this.writer.sizeInBytes(span); - } - - @Override - public byte[] encode(Span span) { - String properSpanName = - span.tags().get(SplunkSpanDataModifier.SPLUNK_OPERATION_KEY.getKey()); - - // note: this can be optimized, if necessary. Let's keep it simple for now. - byte[] rawBytes = JsonCodec.write(this.writer, span); - String renamedResult = - new String(rawBytes, StandardCharsets.UTF_8) - .replace( - "\"name\":\"" + span.name() + "\"", - "\"name\":\"" + properSpanName + "\""); - return renamedResult.getBytes(StandardCharsets.UTF_8); - } -} diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/ZipkinToDiskSender.java b/splunk-otel-android/src/main/java/com/splunk/rum/ZipkinToDiskSender.java deleted file mode 100644 index e33f0f38..00000000 --- a/splunk-otel-android/src/main/java/com/splunk/rum/ZipkinToDiskSender.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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. - */ - -package com.splunk.rum; - -import static java.util.Objects.requireNonNull; - -import android.util.Log; -import androidx.annotation.Nullable; -import io.opentelemetry.sdk.common.Clock; -import java.io.File; -import java.io.IOException; -import java.util.List; -import zipkin2.reporter.BytesMessageSender; -import zipkin2.reporter.Encoding; - -class ZipkinToDiskSender implements BytesMessageSender { - - private final SpanStorage spanStorage; - private final FileUtils fileUtils; - private final Clock clock; - private final DeviceSpanStorageLimiter storageLimiter; - - private ZipkinToDiskSender(Builder builder) { - this.spanStorage = requireNonNull(builder.fileProvider); - this.fileUtils = builder.fileUtils; - this.clock = builder.clock; - this.storageLimiter = requireNonNull(builder.storageLimiter); - } - - @Override - public Encoding encoding() { - return Encoding.JSON; - } - - @Override - public int messageMaxBytes() { - return 1024 * 1024; - } - - @Override - public int messageSizeInBytes(List encodedSpans) { - return encodedSpans.stream().reduce(0, (acc, cur) -> acc + cur.length + 1, Integer::sum); - } - - @Override - public void send(List encodedSpans) throws IOException { - if (encodedSpans.isEmpty()) { - return; - } - if (!storageLimiter.ensureFreeSpace()) { - Log.e( - SplunkRum.LOG_TAG, - "Dropping " - + encodedSpans.size() - + " spans: Too much telemetry has been buffered or not enough space on device."); - return; - } - long now = clock.now(); - File filename = createFilename(now); - try { - fileUtils.writeAsLines(filename, encodedSpans); - } catch (IOException e) { - Log.e(SplunkRum.LOG_TAG, "Error writing spans to storage", e); - } - } - - @Override - public int messageSizeInBytes(int encodedSizeInBytes) { - return encoding().listSizeInBytes(encodedSizeInBytes); - } - - private File createFilename(long now) { - return new File(spanStorage.provideSpansDirectory(), now + ".spans"); - } - - static Builder builder() { - return new Builder(); - } - - @Override - public void close() throws IOException {} - - static class Builder { - @Nullable private SpanStorage fileProvider; - private FileUtils fileUtils = new FileUtils(); - private Clock clock = Clock.getDefault(); - @Nullable private DeviceSpanStorageLimiter storageLimiter; - - Builder spanFileProvider(SpanStorage spanStorage) { - this.fileProvider = spanStorage; - return this; - } - - Builder fileUtils(FileUtils fileUtils) { - this.fileUtils = fileUtils; - return this; - } - - Builder clock(Clock clock) { - this.clock = clock; - return this; - } - - Builder storageLimiter(DeviceSpanStorageLimiter limiter) { - this.storageLimiter = limiter; - return this; - } - - ZipkinToDiskSender build() { - return new ZipkinToDiskSender(this); - } - } -} diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/ZipkinWriteToDiskExporterFactory.java b/splunk-otel-android/src/main/java/com/splunk/rum/ZipkinWriteToDiskExporterFactory.java deleted file mode 100644 index 8994c0d1..00000000 --- a/splunk-otel-android/src/main/java/com/splunk/rum/ZipkinWriteToDiskExporterFactory.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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. - */ - -package com.splunk.rum; - -import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter; -import zipkin2.reporter.BytesMessageSender; - -/** - * Creates a ZipkinSpanExporter that is configured with an instance of a ZipkinToDiskSender that - * writes telemetry to disk. - */ -class ZipkinWriteToDiskExporterFactory { - - private ZipkinWriteToDiskExporterFactory() {} - - static ZipkinSpanExporter create(int maxUsageMegabytes, SpanStorage spanStorage) { - FileUtils fileUtils = new FileUtils(); - DeviceSpanStorageLimiter limiter = - DeviceSpanStorageLimiter.builder() - .fileUtils(fileUtils) - .fileProvider(spanStorage) - .maxStorageUseMb(maxUsageMegabytes) - .build(); - BytesMessageSender sender = - ZipkinToDiskSender.builder() - .spanFileProvider(spanStorage) - .fileUtils(fileUtils) - .storageLimiter(limiter) - .build(); - return ZipkinSpanExporter.builder() - .setEncoder(new CustomZipkinEncoder()) - .setSender(sender) - // remove the local IP address - .setLocalIpAddressSupplier(() -> null) - .build(); - } -} diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/CustomZipkinEncoderTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/CustomZipkinEncoderTest.java deleted file mode 100644 index ffafa099..00000000 --- a/splunk-otel-android/src/test/java/com/splunk/rum/CustomZipkinEncoderTest.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - */ - -package com.splunk.rum; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import io.opentelemetry.api.trace.SpanId; -import io.opentelemetry.api.trace.TraceId; -import org.junit.jupiter.api.Test; -import zipkin2.Span; - -class CustomZipkinEncoderTest { - - @Test - void nameReplacement() { - CustomZipkinEncoder encoder = new CustomZipkinEncoder(); - Span span = - Span.newBuilder() - .name("lowercase") - .traceId(TraceId.fromLongs(1, 2)) - .id(SpanId.fromLong(1)) - .putTag(SplunkSpanDataModifier.SPLUNK_OPERATION_KEY.getKey(), "UpperCase") - .build(); - byte[] bytes = encoder.encode(span); - // this assertion verifies that we changed the name - assertEquals( - "{\"traceId\":\"00000000000000010000000000000002\",\"id\":\"0000000000000001\",\"name\":\"UpperCase\",\"tags\":{\"_splunk_operation\":\"UpperCase\"}}", - new String(bytes)); - assertEquals(bytes.length, encoder.sizeInBytes(span)); - } -} diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/ZipkinToDiskSenderTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/ZipkinToDiskSenderTest.java deleted file mode 100644 index e2bca924..00000000 --- a/splunk-otel-android/src/test/java/com/splunk/rum/ZipkinToDiskSenderTest.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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. - */ - -package com.splunk.rum; - -import static java.util.Collections.emptyList; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoInteractions; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import io.opentelemetry.sdk.common.Clock; -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.List; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -class ZipkinToDiskSenderTest { - - private final long now = System.currentTimeMillis(); - private final File path = new File("/my/great/storage/location"); - private final SpanStorage spanStorage = mock(SpanStorage.class); - - private final String finalFile = "/my/great/storage/location/" + now + ".spans"; - private final File finalPath = new File(finalFile); - private final byte[] span1 = "span one".getBytes(StandardCharsets.UTF_8); - private final byte[] span2 = "span one".getBytes(StandardCharsets.UTF_8); - private final List spans = Arrays.asList(span1, span2); - - @Mock private FileUtils fileUtils; - @Mock private Clock clock; - @Mock private DeviceSpanStorageLimiter limiter; - - @BeforeEach - void setup() { - lenient().when(clock.now()).thenReturn(now); - lenient().when(limiter.ensureFreeSpace()).thenReturn(true); - } - - @Test - void testHappyPath() throws Exception { - when(spanStorage.provideSpansDirectory()).thenReturn(path); - - ZipkinToDiskSender sender = - ZipkinToDiskSender.builder() - .spanFileProvider(spanStorage) - .fileUtils(fileUtils) - .clock(clock) - .storageLimiter(limiter) - .build(); - sender.send(spans); - - verify(fileUtils).writeAsLines(finalPath, spans); - } - - @Test - void testEmptyListDoesNotWriteFile() throws Exception { - ZipkinToDiskSender sender = - ZipkinToDiskSender.builder() - .spanFileProvider(spanStorage) - .fileUtils(fileUtils) - .storageLimiter(limiter) - .build(); - sender.send(emptyList()); - verifyNoInteractions(fileUtils); - } - - @Test - void testWriteFails() throws Exception { - when(spanStorage.provideSpansDirectory()).thenReturn(path); - doThrow(new IOException("boom")).when(fileUtils).writeAsLines(finalPath, spans); - - ZipkinToDiskSender sender = - ZipkinToDiskSender.builder() - .spanFileProvider(spanStorage) - .fileUtils(fileUtils) - .clock(clock) - .storageLimiter(limiter) - .build(); - - sender.send(spans); - // Exception not thrown - } - - @Test - void testLimitExceeded() throws Exception { - Mockito.reset(clock); - when(limiter.ensureFreeSpace()).thenReturn(false); - - ZipkinToDiskSender sender = - ZipkinToDiskSender.builder() - .spanFileProvider(spanStorage) - .fileUtils(fileUtils) - .clock(clock) - .storageLimiter(limiter) - .build(); - - sender.send(spans); - - verifyNoMoreInteractions(clock); - verifyNoMoreInteractions(fileUtils); - } -} From 786144bc95c042a70171ec171a2d6662e715644c Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 23 Oct 2024 14:26:36 -0700 Subject: [PATCH 24/29] remove unused --- .../src/main/java/com/splunk/rum/ConfigFlags.java | 1 - 1 file changed, 1 deletion(-) diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/ConfigFlags.java b/splunk-otel-android/src/main/java/com/splunk/rum/ConfigFlags.java index 2b1d8790..b79b488d 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/ConfigFlags.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/ConfigFlags.java @@ -28,7 +28,6 @@ class ConfigFlags { private boolean slowRenderingDetectionEnabled = true; private boolean subprocessInstrumentationEnabled = true; private boolean backgroundInstrumentationDeferredUntilForeground = false; - private boolean exportUsingOtlp = false; void enableDebug() { debugEnabled = true; From cacee237d89a74b4e45b57fb0dfb0301f5da8864 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 23 Oct 2024 14:30:14 -0700 Subject: [PATCH 25/29] remove unused --- .../src/main/java/com/splunk/rum/RumInitializer.java | 5 ----- 1 file changed, 5 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 14ac81b4..9a266e47 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 @@ -373,11 +373,6 @@ SpanExporter buildSpanExporter(SpanExporter delegate) { return filteredExporter; } - @NonNull - private String getEndpointWithAuthTokenQueryParam() { - return builder.beaconEndpoint + "?auth=" + builder.rumAccessToken; - } - // private static ThrottlingExporter buildThrottlingExporter( // MemoryBufferingExporter memoryBufferingExporter) { // return ThrottlingExporter.newBuilder(memoryBufferingExporter) From 0a6721846a96f7c5826e222a4de7ee937619e61e Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 23 Oct 2024 15:08:41 -0700 Subject: [PATCH 26/29] update dependency versions, remove zipkin dep, fix extractor --- gradle/libs.versions.toml | 23 ++++++++----------- splunk-otel-android/build.gradle.kts | 1 - .../java/com/splunk/rum/RumInitializer.java | 22 ++++-------------- .../rum/RumResponseAttributesExtractor.java | 9 ++++---- 4 files changed, 20 insertions(+), 35 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 46c90e8b..a6bc6089 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,9 +1,7 @@ [versions] -opentelemetry-core = "1.42.1" -opentelemetry-core-alpha = "1.42.1-alpha" -opentelemetry-inst = "2.6.0" -opentelemetry-inst-alpha = "2.6.0-alpha" -opentelemetry-android = "0.7.0-alpha" +opentelemetry-inst = "2.9.0" +opentelemetry-inst-alpha = "2.9.0-alpha" +opentelemetry-android = "0.8.0-alpha" opentelemetry-semconv = "1.26.0-alpha" mockito = "5.14.2" junit = "5.11.3" @@ -16,22 +14,21 @@ navigationCompose = "2.7.7" [libraries] opentelemetry-instrumentation-bom = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom", version.ref = "opentelemetry-inst" } -opentelemetry-bom = { module = "io.opentelemetry:opentelemetry-bom", version.ref = "opentelemetry-core" } -opentelemetry-sdk = { module = "io.opentelemetry:opentelemetry-sdk", version.ref = "opentelemetry-core" } -opentelemetry-api = { module = "io.opentelemetry:opentelemetry-api", version.ref = "opentelemetry-core" } +opentelemetry-bom = { module = "io.opentelemetry:opentelemetry-bom" } +opentelemetry-sdk = { module = "io.opentelemetry:opentelemetry-sdk" } +opentelemetry-api = { module = "io.opentelemetry:opentelemetry-api" } opentelemetry-api-incubator = { module = "io.opentelemetry:opentelemetry-api-incubator" } -opentelemetry-api-events = { module = "io.opentelemetry:opentelemetry-api-events", version.ref = "opentelemetry-core-alpha" } +opentelemetry-api-events = { module = "io.opentelemetry:opentelemetry-api-events" } opentelemetry-android-agent = { module = "io.opentelemetry.android:android-agent", version.ref = "opentelemetry-android" } opentelemetry-android-instrumentation-commonapi = { module = "io.opentelemetry.android:instrumentation-common-api", version.ref = "opentelemetry-android" } opentelemetry-instrumenter-api = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api", version.ref = "opentelemetry-inst" } opentelemetry-instrumenter-api-incubator = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-incubator", version.ref = "opentelemetry-inst-alpha" } opentelemetry-instrumentation-okhttp = { module = "io.opentelemetry.instrumentation:opentelemetry-okhttp-3.0", version.ref = "opentelemetry-inst-alpha" } -opentelemetry-exporter-zipkin = { module = "io.opentelemetry:opentelemetry-exporter-zipkin", version.ref = "opentelemetry-core" } -opentelemetry-exporter-otlp = { module = "io.opentelemetry:opentelemetry-exporter-otlp", version.ref = "opentelemetry-core" } -opentelemetry-exporter-logging = { module = "io.opentelemetry:opentelemetry-exporter-logging", version.ref = "opentelemetry-core" } +opentelemetry-exporter-otlp = { module = "io.opentelemetry:opentelemetry-exporter-otlp" } +opentelemetry-exporter-logging = { module = "io.opentelemetry:opentelemetry-exporter-logging" } opentelemetry-semconv = { module = "io.opentelemetry.semconv:opentelemetry-semconv", version.ref = "opentelemetry-semconv" } opentelemetry-semconv-incubating = { module = "io.opentelemetry.semconv:opentelemetry-semconv-incubating", version.ref = "opentelemetry-semconv" } -opentelemetry-sdk-testing = { module = "io.opentelemetry:opentelemetry-sdk-testing", version.ref = "opentelemetry-core" } +opentelemetry-sdk-testing = { module = "io.opentelemetry:opentelemetry-sdk-testing" } zipkin-sender-okhttp = "io.zipkin.reporter2:zipkin-sender-okhttp3:3.4.2" diff --git a/splunk-otel-android/build.gradle.kts b/splunk-otel-android/build.gradle.kts index 749bdf7b..470c3362 100644 --- a/splunk-otel-android/build.gradle.kts +++ b/splunk-otel-android/build.gradle.kts @@ -48,7 +48,6 @@ dependencies { implementation(libs.opentelemetry.sdk) implementation(libs.opentelemetry.api.incubator) implementation(libs.opentelemetry.instrumentation.okhttp) - implementation(libs.opentelemetry.exporter.zipkin) implementation(libs.opentelemetry.exporter.otlp) implementation(libs.opentelemetry.exporter.logging) implementation(libs.opentelemetry.semconv) 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 9a266e47..1203bc73 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 @@ -94,9 +94,11 @@ SplunkRum initialize(Looper mainLooper) { // TODO: Note/document this instrumentation is now opt-in via application classpath via // build settings - // if (!builder.isNetworkMonitorEnabled()) { - // config.disableNetworkChangeMonitoring(); - // } + if (!builder.isNetworkMonitorEnabled()) { + // Can we simply suppress the spans? Is there more to it? + // config.fil + // config.disableNetworkChangeMonitoring(); + } config.disableScreenAttributes(); DiskBufferingConfiguration diskBufferingConfig = @@ -392,20 +394,6 @@ SpanExporter buildSpanExporter(SpanExporter delegate) { // return new LazyInitSpanExporter(exporterSupplier); // } - // - // //TODO: This needs to go away as part of 2.0, OTLP only - // @NonNull - // private Supplier supplyZipkinExporter() { - // String endpoint = getEndpointWithAuthTokenQueryParam(); - // return () -> - // ZipkinSpanExporter.builder() - // .setEncoder(new CustomZipkinEncoder()) - // .setEndpoint(endpoint) - // // remove the local IP address - // .setLocalIpAddressSupplier(() -> null) - // .setSender(buildCustomizedZipkinSender()) - // .build(); - // } // // private static class LazyInitSpanExporter implements SpanExporter { // @Nullable private volatile SpanExporter delegate; diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/RumResponseAttributesExtractor.java b/splunk-otel-android/src/main/java/com/splunk/rum/RumResponseAttributesExtractor.java index 7f8cdef4..135ce242 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/RumResponseAttributesExtractor.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/RumResponseAttributesExtractor.java @@ -23,10 +23,10 @@ import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.context.Context; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; -import okhttp3.Request; +import okhttp3.Interceptor; import okhttp3.Response; -class RumResponseAttributesExtractor implements AttributesExtractor { +class RumResponseAttributesExtractor implements AttributesExtractor { private final ServerTimingHeaderParser serverTimingHeaderParser; @@ -35,7 +35,8 @@ public RumResponseAttributesExtractor(ServerTimingHeaderParser serverTimingHeade } @Override - public void onStart(AttributesBuilder attributes, Context parentContext, Request request) { + public void onStart( + AttributesBuilder attributes, Context parentContext, Interceptor.Chain chain) { attributes.put(COMPONENT_KEY, "http"); } @@ -43,7 +44,7 @@ public void onStart(AttributesBuilder attributes, Context parentContext, Request public void onEnd( AttributesBuilder attributes, Context context, - Request request, + Interceptor.Chain chain, Response response, Throwable error) { if (response != null) { From 1c7073f1961931f03d12650ce1f893365fa1a407 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 23 Oct 2024 15:13:04 -0700 Subject: [PATCH 27/29] use semconv for old session ids --- .../main/java/com/splunk/rum/SplunkSpanDataModifier.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java index f4f37f74..cf71ede2 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java @@ -51,6 +51,8 @@ import io.opentelemetry.semconv.incubating.DeploymentIncubatingAttributes; import io.opentelemetry.semconv.incubating.DeviceIncubatingAttributes; import io.opentelemetry.semconv.incubating.OsIncubatingAttributes; +import io.opentelemetry.semconv.incubating.SessionIncubatingAttributes; + import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -104,12 +106,12 @@ private SpanData modify(SpanData original) { AttributesBuilder modifiedAttributes = original.getAttributes().toBuilder(); // Copy the native session id name into the splunk name - String sessionId = original.getAttributes().get(RumConstants.SESSION_ID_KEY); + String sessionId = original.getAttributes().get(SessionIncubatingAttributes.SESSION_ID); modifiedAttributes.put(StandardAttributes.SESSION_ID_KEY, sessionId); // Copy previous session id to splunk name, if applicable. String previousSessionId = - original.getAttributes().get(RumConstants.PREVIOUS_SESSION_ID_KEY); + original.getAttributes().get(SessionIncubatingAttributes.SESSION_PREVIOUS_ID); if (previousSessionId != null) { modifiedAttributes.put(StandardAttributes.PREVIOUS_SESSION_ID_KEY, previousSessionId); } From 8e2d295cb3afb3ade8ec90ed4660182ad4a856b6 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 23 Oct 2024 15:20:29 -0700 Subject: [PATCH 28/29] fix tests --- .../rum/RumResponseAttributesExtractorTest.java | 17 +++++++++-------- .../splunk/rum/SplunkSpanDataModifierTest.java | 6 ++++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/RumResponseAttributesExtractorTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/RumResponseAttributesExtractorTest.java index 1ca693b2..f605b750 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/RumResponseAttributesExtractorTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/RumResponseAttributesExtractorTest.java @@ -27,6 +27,7 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.context.Context; +import okhttp3.Interceptor; import okhttp3.Protocol; import okhttp3.Request; import okhttp3.Response; @@ -40,10 +41,10 @@ void spanDecoration() { when(headerParser.parse("headerValue")) .thenReturn(new String[] {"9499195c502eb217c448a68bfe0f967c", "fe16eca542cd5d86"}); - Request fakeRequest = mock(Request.class); + Interceptor.Chain fakeChain = mock(Interceptor.Chain.class); Response response = new Response.Builder() - .request(fakeRequest) + .request(mock(Request.class)) .protocol(Protocol.HTTP_1_1) .message("hello") .code(200) @@ -53,8 +54,8 @@ void spanDecoration() { RumResponseAttributesExtractor attributesExtractor = new RumResponseAttributesExtractor(headerParser); AttributesBuilder attributesBuilder = Attributes.builder(); - attributesExtractor.onStart(attributesBuilder, Context.root(), fakeRequest); - attributesExtractor.onEnd(attributesBuilder, Context.root(), fakeRequest, response, null); + attributesExtractor.onStart(attributesBuilder, Context.root(), fakeChain); + attributesExtractor.onEnd(attributesBuilder, Context.root(), fakeChain, response, null); Attributes attributes = attributesBuilder.build(); assertThat(attributes) @@ -69,10 +70,10 @@ void spanDecoration_noLinkingHeader() { ServerTimingHeaderParser headerParser = mock(ServerTimingHeaderParser.class); when(headerParser.parse(null)).thenReturn(new String[0]); - Request fakeRequest = mock(Request.class); + Interceptor.Chain fakeChain = mock(Interceptor.Chain.class); Response response = new Response.Builder() - .request(fakeRequest) + .request(mock(Request.class)) .protocol(Protocol.HTTP_1_1) .message("hello") .code(200) @@ -81,8 +82,8 @@ void spanDecoration_noLinkingHeader() { RumResponseAttributesExtractor attributesExtractor = new RumResponseAttributesExtractor(headerParser); AttributesBuilder attributesBuilder = Attributes.builder(); - attributesExtractor.onEnd(attributesBuilder, Context.root(), fakeRequest, response, null); - attributesExtractor.onStart(attributesBuilder, Context.root(), fakeRequest); + attributesExtractor.onEnd(attributesBuilder, Context.root(), fakeChain, response, null); + attributesExtractor.onStart(attributesBuilder, Context.root(), fakeChain); Attributes attributes = attributesBuilder.build(); assertThat(attributes).containsOnly(entry(COMPONENT_KEY, "http")); diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/SplunkSpanDataModifierTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/SplunkSpanDataModifierTest.java index 22d39490..02d4b057 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/SplunkSpanDataModifierTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/SplunkSpanDataModifierTest.java @@ -41,6 +41,8 @@ import io.opentelemetry.sdk.trace.export.SpanExporter; import io.opentelemetry.semconv.ResourceAttributes; import io.opentelemetry.semconv.SemanticAttributes; +import io.opentelemetry.semconv.incubating.SessionIncubatingAttributes; + import java.util.Arrays; import java.util.Collection; import org.junit.jupiter.api.Test; @@ -84,7 +86,7 @@ class SplunkSpanDataModifierTest { @Test void changesSpanIdAttrName() { String sessionId = "abc123fonzie"; - Attributes attrs = Attributes.of(RumConstants.SESSION_ID_KEY, sessionId); + Attributes attrs = Attributes.of(SessionIncubatingAttributes.SESSION_ID, sessionId); SpanData original = startBuilder().setAttributes(attrs).build(); CompletableResultCode exportResult = CompletableResultCode.ofSuccess(); @@ -98,7 +100,7 @@ void changesSpanIdAttrName() { SpanData first = exported.iterator().next(); assertThat(first.getAttributes().get(StandardAttributes.SESSION_ID_KEY)) .isEqualTo(sessionId); - assertThat(first.getAttributes().get(RumConstants.SESSION_ID_KEY)).isEqualTo(sessionId); + assertThat(first.getAttributes().get(SessionIncubatingAttributes.SESSION_ID)).isEqualTo(sessionId); } @Test From 3bd1cf82063aa65874a262cfe198daac1c656dd9 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 23 Oct 2024 15:28:30 -0700 Subject: [PATCH 29/29] spotless --- .../src/main/java/com/splunk/rum/SplunkSpanDataModifier.java | 1 - .../test/java/com/splunk/rum/SplunkSpanDataModifierTest.java | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java index cf71ede2..fdfaa90f 100644 --- a/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java +++ b/splunk-otel-android/src/main/java/com/splunk/rum/SplunkSpanDataModifier.java @@ -52,7 +52,6 @@ import io.opentelemetry.semconv.incubating.DeviceIncubatingAttributes; import io.opentelemetry.semconv.incubating.OsIncubatingAttributes; import io.opentelemetry.semconv.incubating.SessionIncubatingAttributes; - import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; diff --git a/splunk-otel-android/src/test/java/com/splunk/rum/SplunkSpanDataModifierTest.java b/splunk-otel-android/src/test/java/com/splunk/rum/SplunkSpanDataModifierTest.java index 02d4b057..b1b3137c 100644 --- a/splunk-otel-android/src/test/java/com/splunk/rum/SplunkSpanDataModifierTest.java +++ b/splunk-otel-android/src/test/java/com/splunk/rum/SplunkSpanDataModifierTest.java @@ -42,7 +42,6 @@ import io.opentelemetry.semconv.ResourceAttributes; import io.opentelemetry.semconv.SemanticAttributes; import io.opentelemetry.semconv.incubating.SessionIncubatingAttributes; - import java.util.Arrays; import java.util.Collection; import org.junit.jupiter.api.Test; @@ -100,7 +99,8 @@ void changesSpanIdAttrName() { SpanData first = exported.iterator().next(); assertThat(first.getAttributes().get(StandardAttributes.SESSION_ID_KEY)) .isEqualTo(sessionId); - assertThat(first.getAttributes().get(SessionIncubatingAttributes.SESSION_ID)).isEqualTo(sessionId); + assertThat(first.getAttributes().get(SessionIncubatingAttributes.SESSION_ID)) + .isEqualTo(sessionId); } @Test