Skip to content

Commit

Permalink
Allow building RUM with preconfigured SDK. (#587)
Browse files Browse the repository at this point in the history
* allow building RUM with preconfigured SDK.

* Update opentelemetry-android-instrumentation/src/main/java/io/opentelemetry/rum/internal/OpenTelemetryRum.java

Co-authored-by: Mateusz Rzeszutek <[email protected]>

* code review comments

* add imports

---------

Co-authored-by: Mateusz Rzeszutek <[email protected]>
  • Loading branch information
breedx-splk and Mateusz Rzeszutek authored Jul 6, 2023
1 parent 5aa3bea commit a220491
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@

import android.app.Application;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.trace.SdkTracerProvider;

/**
* Entrypoint for the OpenTelemetry Real User Monitoring library for Android.
Expand All @@ -28,14 +32,35 @@
public interface OpenTelemetryRum {

/**
* Returns a new {@link OpenTelemetryRumBuilder} for {@link OpenTelemetryRum}.
* Returns a new {@link OpenTelemetryRumBuilder} for {@link OpenTelemetryRum}. Use this version
* if you would like to configure individual aspects of the OpenTelemetry SDK but would still
* prefer to allow OpenTelemetry RUM to create the SDK for you. If you would like to "bring your
* own" SDK, call the two-argument version.
*
* @param application The {@link Application} that is being instrumented.
*/
static OpenTelemetryRumBuilder builder(Application application) {
return new OpenTelemetryRumBuilder(application);
}

/**
* Returns a new {@link SdkPreconfiguredRumBuilder} for {@link OpenTelemetryRum}. This version
* requires the user to preconfigure and create their own OpenTelemetrySdk instance. If you
* prefer to use the builder to configure individual aspects of the OpenTelemetry SDK and to
* create and manage it for you, call the one-argument version.
*
* <p>Specific consideration should be given to the creation of your provided SDK to ensure that
* the {@link SdkTracerProvider}, {@link SdkMeterProvider}, and {@link SdkLoggerProvider} are
* configured correctly for your target RUM provider.
*
* @param application The {@link Application} that is being instrumented.
* @param openTelemetrySdk The {@link OpenTelemetrySdk} that the user has already created.
*/
static SdkPreconfiguredRumBuilder builder(
Application application, OpenTelemetrySdk openTelemetrySdk) {
return new SdkPreconfiguredRumBuilder(application, openTelemetrySdk);
}

/** Returns a no-op implementation of {@link OpenTelemetryRum}. */
static OpenTelemetryRum noop() {
return NoopOpenTelemetryRum.INSTANCE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package io.opentelemetry.rum.internal;

import android.app.Application;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.rum.internal.instrumentation.InstrumentedApplication;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
Expand Down Expand Up @@ -54,8 +53,8 @@ public final class OpenTelemetryRumBuilder {
private Resource resource;

OpenTelemetryRumBuilder(Application application) {
SessionIdTimeoutHandler timeoutHandler = new SessionIdTimeoutHandler();
this.application = application;
SessionIdTimeoutHandler timeoutHandler = new SessionIdTimeoutHandler();
this.sessionId = new SessionId(timeoutHandler);
this.resource = AndroidResource.createDefault(application);
}
Expand Down Expand Up @@ -168,31 +167,17 @@ public SessionId getSessionId() {
* @return A new {@link OpenTelemetryRum} instance.
*/
public OpenTelemetryRum build() {
// the app state listeners need to be run in the first ActivityLifecycleCallbacks since they
// might turn off/on additional telemetry depending on whether the app is active or not
ApplicationStateWatcher applicationStateWatcher = new ApplicationStateWatcher();
application.registerActivityLifecycleCallbacks(applicationStateWatcher);

applicationStateWatcher.registerListener(sessionId.getTimeoutHandler());

OpenTelemetrySdk openTelemetrySdk =
OpenTelemetrySdk sdk =
OpenTelemetrySdk.builder()
.setTracerProvider(buildTracerProvider(sessionId, application))
.setMeterProvider(buildMeterProvider(application))
.setLoggerProvider(buildLoggerProvider(application))
.build();

Tracer tracer = openTelemetrySdk.getTracer(OpenTelemetryRum.class.getSimpleName());
sessionId.setSessionIdChangeListener(new SessionIdChangeTracer(tracer));

InstrumentedApplication instrumentedApplication =
new InstrumentedApplicationImpl(
application, openTelemetrySdk, applicationStateWatcher);
for (Consumer<InstrumentedApplication> installer : instrumentationInstallers) {
installer.accept(instrumentedApplication);
}

return new OpenTelemetryRumImpl(openTelemetrySdk, sessionId);
SdkPreconfiguredRumBuilder delegate =
new SdkPreconfiguredRumBuilder(application, sdk, sessionId);
instrumentationInstallers.forEach(delegate::addInstrumentation);
return delegate.build();
}

private SdkTracerProvider buildTracerProvider(SessionId sessionId, Application application) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* 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 io.opentelemetry.rum.internal;

import android.app.Application;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.rum.internal.instrumentation.InstrumentedApplication;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public final class SdkPreconfiguredRumBuilder {
private final Application application;
private final OpenTelemetrySdk sdk;
private final SessionId sessionId;

private final List<Consumer<InstrumentedApplication>> instrumentationInstallers =
new ArrayList<>();

SdkPreconfiguredRumBuilder(Application application, OpenTelemetrySdk openTelemetrySdk) {
this(application, openTelemetrySdk, new SessionId(new SessionIdTimeoutHandler()));
}

SdkPreconfiguredRumBuilder(
Application application, OpenTelemetrySdk openTelemetrySdk, SessionId sessionId) {
this.application = application;
this.sdk = openTelemetrySdk;
this.sessionId = sessionId;
}

/**
* Adds an instrumentation installer function that will be run on an {@link
* InstrumentedApplication} instance as a part of the {@link #build()} method call.
*
* @return {@code this}
*/
public SdkPreconfiguredRumBuilder addInstrumentation(
Consumer<InstrumentedApplication> instrumentationInstaller) {
instrumentationInstallers.add(instrumentationInstaller);
return this;
}

/**
* Creates a new instance of {@link OpenTelemetryRum} with the settings of this {@link
* OpenTelemetryRumBuilder}.
*
* <p>This method uses a preconfigured OpenTelemetry SDK and install built-in system
* instrumentations in the passed Android {@link Application}.
*
* @return A new {@link OpenTelemetryRum} instance.
*/
public OpenTelemetryRum build() {
// the app state listeners need to be run in the first ActivityLifecycleCallbacks since they
// might turn off/on additional telemetry depending on whether the app is active or not
ApplicationStateWatcher applicationStateWatcher = new ApplicationStateWatcher();
application.registerActivityLifecycleCallbacks(applicationStateWatcher);
applicationStateWatcher.registerListener(sessionId.getTimeoutHandler());

Tracer tracer = sdk.getTracer(OpenTelemetryRum.class.getSimpleName());
sessionId.setSessionIdChangeListener(new SessionIdChangeTracer(tracer));

InstrumentedApplication instrumentedApplication =
new InstrumentedApplicationImpl(application, sdk, applicationStateWatcher);
for (Consumer<InstrumentedApplication> installer : instrumentationInstallers) {
installer.accept(instrumentedApplication);
}

return new OpenTelemetryRumImpl(sdk, sessionId);
}
}

0 comments on commit a220491

Please sign in to comment.