Skip to content

Commit

Permalink
Feature/background aware span export (#648)
Browse files Browse the repository at this point in the history
* add SpanFileProvider

Signed-off-by: reza stallone <[email protected]>

* add StartTypeAwareSpanFileProvider

Signed-off-by: reza stallone <[email protected]>

* add function to calculate dir size from /span & /span/background recursively

Signed-off-by: reza stallone <[email protected]>

* change session id to UUID to loose coupling from otel session id

Signed-off-by: reza stallone <[email protected]>

* provide file path for span using SpanFileProvider

Signed-off-by: reza stallone <[email protected]>

* abstract backlog for MemoryBufferingExporter

Signed-off-by: reza stallone <[email protected]>

* implement start type aware BacklogProvider

Signed-off-by: reza stallone <[email protected]>

* implement default SpanFileProvider

Signed-off-by: reza stallone <[email protected]>

* return start type aware BacklogProvider & SpanFileProvider based on isBackgroundTaskReportingDisabled config

Signed-off-by: reza stallone <[email protected]>

* add unit test for StartTypeAwareSpanFileProvider

Signed-off-by: reza stallone <[email protected]>

* add background worker for testing

Signed-off-by: reza stallone <[email protected]>

* move constructor below fields

Signed-off-by: reza stallone <[email protected]>

* move static constant above fields

Signed-off-by: reza stallone <[email protected]>

* rename fillFromBacklog to drain

Signed-off-by: reza stallone <[email protected]>

* reduce SpanFileProvider access level to package level

Signed-off-by: reza stallone <[email protected]>

* rename SpanFileProvider to SpanStorage

Signed-off-by: reza stallone <[email protected]>

* invert if in provideSpanFile

Signed-off-by: reza stallone <[email protected]>

* pass root directory to SpanStorage constructor instead of Application

Signed-off-by: reza stallone <[email protected]>

* remove Application dependency from StartTypeAwareSpanStorageTest.java

Signed-off-by: reza stallone <[email protected]>

* reduce access level BacklogProvider to package level

Signed-off-by: reza stallone <[email protected]>

* move max span in backlog checking back to MemoryBufferingExporter

Signed-off-by: reza stallone <[email protected]>

* rename StartTypeAwareBacklogProvider to StartTypeAwareMemorySpanBuffer

Signed-off-by: reza stallone <[email protected]>

* use Stream to list file recursively

Signed-off-by: reza stallone <[email protected]>

* reword description for StartTypeAwareSpanStorage

Signed-off-by: reza stallone <[email protected]>

* remove unused semicolon

Signed-off-by: reza stallone <[email protected]>

* call forEach directly instead of collect since it's also terminal operator

Signed-off-by: reza stallone <[email protected]>

* remove unused import

Signed-off-by: reza stallone <[email protected]>

* use debug log level instead of information

Signed-off-by: reza stallone <[email protected]>

* move methods close to immediate caller for readability

Signed-off-by: reza stallone <[email protected]>

* remove DemoWorker from manifest declaration

Signed-off-by: reza stallone <[email protected]>

* add javadoc for SpanStorage

Signed-off-by: reza stallone <[email protected]>

* rename backgroundTaskInstrumentationEnabled

Signed-off-by: reza stallone <[email protected]>

* add deffer background instrumentation until foreground Rum builder parameter

Signed-off-by: reza stallone <[email protected]>

* remove max size backlog test since the logic has been moved out of this class

Signed-off-by: reza stallone <[email protected]>

* update unit test StartTypeAwareMemorySpanBufferTest

Signed-off-by: reza stallone <[email protected]>

* remove max size exceed test from DefaultMemorySpanBufferTest

Since the logic has been moved back to MemoryBufferingExporter

Signed-off-by: reza stallone <[email protected]>

* apply spotless

Signed-off-by: reza stallone <[email protected]>

* apply spotless to splunk-otel-android project

Signed-off-by: reza stallone <[email protected]>

* downgrade io.opentelemetry.android:instrumentation to 0.1.0-alpha-SNAPSHOTS

cannot parse pom 0.2.0-alpha-SNAPSHOTS

Signed-off-by: reza stallone <[email protected]>

* Revert "downgrade io.opentelemetry.android:instrumentation to 0.1.0-alpha-SNAPSHOTS"

This reverts commit 1a0a1db.

Signed-off-by: reza stallone <[email protected]>

* fix background span not sent because not checking visibility tracker current screen

Signed-off-by: reza stallone <[email protected]>

* clean up old background directories on new uniqueId created

Signed-off-by: reza stallone <[email protected]>

* apply spotless

Signed-off-by: reza stallone <[email protected]>

* differentiate screen name between previous visible screen & current visible screen

Signed-off-by: reza stallone <[email protected]>

* reword cleanupUnsentBackgroundSpans

Signed-off-by: reza stallone <[email protected]>

* clean background span directories after moving its spans to foreground

Signed-off-by: reza stallone <[email protected]>

* apply javabean convention for variable name in ConfigFlags.java

Signed-off-by: reza stallone <[email protected]>

* rename isSubprocessInstrumentationDisabled to isSubprocessInstrumentationEnabled

Signed-off-by: reza stallone <[email protected]>

* create factory method for StartTypeAwareSpanStorage

Signed-off-by: reza stallone <[email protected]>

* reword file to dir

Co-authored-by: jason plumb <[email protected]>
Signed-off-by: reza stallone <[email protected]>

* reword file to dir

Co-authored-by: jason plumb <[email protected]>
Signed-off-by: reza stallone <[email protected]>

* apply spotless

Signed-off-by: reza stallone <[email protected]>

* fix visibility checking bug in StartTypeAwareMemorySpanBuffer

Signed-off-by: reza stallone <[email protected]>

* reword disableBackgroundTaskReporting to disableSubprocessInstrumentation

Signed-off-by: reza stallone <[email protected]>

* disableSubprocessInstrumentation in sample app

Signed-off-by: reza stallone <[email protected]>

* apply spotless

Signed-off-by: reza stallone <[email protected]>

* reword reword term backgroundTaskReporting to subprocessInstrumentation

Signed-off-by: reza stallone <[email protected]>

---------

Signed-off-by: reza stallone <[email protected]>
Co-authored-by: jason plumb <[email protected]>
  • Loading branch information
rezastallone and breedx-splk authored Oct 17, 2023
1 parent af4372a commit 41d5b50
Show file tree
Hide file tree
Showing 36 changed files with 1,123 additions and 159 deletions.
1 change: 1 addition & 0 deletions sample-app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ dependencies {
implementation(project(":splunk-otel-android"))
implementation(project(":splunk-otel-android-volley"))
implementation("com.android.volley:volley:1.2.1")
implementation("androidx.work:work-runtime:2.8.1")
implementation("io.opentelemetry.instrumentation:opentelemetry-instrumentation-api")
implementation("io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-semconv")

Expand Down
4 changes: 4 additions & 0 deletions sample-app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".SplunkBackgroundService"
android:exported="false"
android:process=":my_service_process"/>
</application>

</manifest>
56 changes: 56 additions & 0 deletions sample-app/src/main/java/com/splunk/android/sample/DemoWorker.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* 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.android.sample;

import android.content.Context;
import android.content.Intent;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
import com.splunk.rum.SplunkRum;
import io.opentelemetry.api.common.Attributes;

public class DemoWorker extends Worker {

private Context context;
public static final String TAG = "SplunkRum";

public DemoWorker(@NonNull Context context, @NonNull WorkerParameters params) {
super(context, params);
this.context = context;
}

@NonNull
@Override
public Result doWork() {
try {
SplunkRum.getInstance().addRumEvent("DemoWorker is doing work", Attributes.empty());
Log.d(TAG, "DemoWorker Starting background Service");
startBackgroundService();
return Result.success();
} catch (Exception e) {
return Result.failure();
}
}

private void startBackgroundService() {
Intent serviceIntent = new Intent(context, SplunkBackgroundService.class);
Log.d(TAG, "Starting background Service");
context.startService(serviceIntent);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
});

sessionId.postValue(splunkRum.getRumSessionId());

binding.workManager.setOnClickListener(
v -> {
WorkManagerHelper.startWorkManager(this.getContext());
});
}

private void multiThreadCrashing() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import androidx.work.ExistingPeriodicWorkPolicy;
import androidx.work.PeriodicWorkRequest;
import androidx.work.WorkManager;
import com.splunk.android.sample.databinding.ActivityMainBinding;
import com.splunk.rum.SplunkRum;
import io.opentelemetry.android.instrumentation.RumScreenName;
Expand Down Expand Up @@ -74,6 +77,18 @@ protected void onCreate(Bundle savedInstanceState) {
view -> {
new MailDialogFragment(this).show(getSupportFragmentManager(), "Mail");
});
setUpPeriodicWorker();
}

private void setUpPeriodicWorker() {
PeriodicWorkRequest workRequest =
new PeriodicWorkRequest.Builder(DemoWorker.class, 15, TimeUnit.MINUTES).build();

WorkManager.getInstance(this)
.enqueueUniquePeriodicWork(
"backgroundsplunk",
ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
workRequest);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ public void onCreate() {
.setRumAccessToken(getResources().getString(R.string.rum_access_token))
.enableDebug()
.enableDiskBuffering()
.disableBackgroundTaskReporting(BuildConfig.APPLICATION_ID)
.disableSubprocessInstrumentation(BuildConfig.APPLICATION_ID)
.enableBackgroundInstrumentationDeferredUntilForeground()
.setSlowRenderingDetectionPollInterval(Duration.ofMillis(1000))
.setDeploymentEnvironment("demo")
.limitDiskUsageMegabytes(1)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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.android.sample;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class SplunkBackgroundService extends Service {
public static final String TAG = "SplunkRum";

@Override
public IBinder onBind(Intent intent) {
return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
Log.d(TAG, "Service started on different thread");
}
stopSelf();
return START_STICKY;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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.android.sample;

import android.content.Context;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
import androidx.work.WorkRequest;

public class WorkManagerHelper {

public static void startWorkManager(Context context) {
WorkRequest demoWorkRequest = new OneTimeWorkRequest.Builder(DemoWorker.class).build();
WorkManager.getInstance(context).enqueue(demoWorkRequest);
}
}
7 changes: 7 additions & 0 deletions sample-app/src/main/res/layout/fragment_first.xml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@
android:layout_marginTop="8dp"
android:text="@string/volley_client" />

<Button
android:id="@+id/work_manager"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/worker" />

<TextView
android:id="@+id/session_id"
android:layout_width="wrap_content"
Expand Down
1 change: 1 addition & 0 deletions sample-app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<string name="http_me_up">HTTP me up!</string>
<string name="http_me_bad">Http Error</string>
<string name="volley_client">Volley HTTP</string>
<string name="worker">Worker</string>
<string name="http_not_found">HTTP Not Found</string>

<string name="local_web_view">Local WebView</string>
Expand Down
19 changes: 14 additions & 5 deletions splunk-otel-android/src/main/java/com/splunk/rum/ConfigFlags.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ class ConfigFlags {
private boolean networkMonitorEnabled = true;
private boolean anrDetectionEnabled = true;
private boolean slowRenderingDetectionEnabled = true;
private boolean backgroundTaskInstrumentationEnabled = true;
private boolean subprocessInstrumentationEnabled = true;
private boolean backgroundInstrumentationDeferredUntilForeground = false;

void enableDebug() {
debugEnabled = true;
Expand Down Expand Up @@ -56,16 +57,24 @@ void disableSlowRenderingDetection() {
slowRenderingDetectionEnabled = false;
}

public void disableBackgroundTaskDetection() {
backgroundTaskInstrumentationEnabled = false;
public void disableSubprocessInstrumentation() {
subprocessInstrumentationEnabled = false;
}

public void enableBackgroundInstrumentationDeferredUntilForeground() {
backgroundInstrumentationDeferredUntilForeground = true;
}

boolean isDebugEnabled() {
return debugEnabled;
}

boolean isBackgroundTaskInstrumentationEnabled() {
return backgroundTaskInstrumentationEnabled;
boolean isSubprocessInstrumentationEnabled() {
return subprocessInstrumentationEnabled;
}

boolean isBackgroundInstrumentationDeferredUntilForeground() {
return backgroundInstrumentationDeferredUntilForeground;
}

boolean isAnrDetectionEnabled() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* 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.sdk.trace.data.SpanData;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Queue;

public class DefaultMemorySpanBuffer implements MemorySpanBuffer {

// note: no need to make this queue thread-safe since it will only ever be called from the
// BatchSpanProcessor worker thread.
private final Queue<SpanData> backlog = new ArrayDeque<>();

@Override
public void addAll(Collection<SpanData> spans) {
backlog.addAll(spans);
}

@Override
public void addFailedSpansToBacklog(SpanData spanData) {
backlog.add(spanData);
}

@Override
public List<SpanData> drain() {
List<SpanData> retries = new ArrayList<>(backlog);
backlog.clear();
return retries;
}

@Override
public boolean isEmpty() {
return backlog.isEmpty();
}

@Override
public void clear() {
backlog.clear();
}

@Override
public int size() {
return backlog.size();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* 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 java.io.File;
import java.util.stream.Stream;

public class DefaultSpanStorage implements SpanStorage {

private final FileUtils fileUtils;
private final File rootDir;

public DefaultSpanStorage(FileUtils fileUtils, File rootDir) {
this.fileUtils = fileUtils;
this.rootDir = rootDir;
}

@Override
public File provideSpanFile() {
File spansPath = fileUtils.getSpansDirectory(rootDir);
if (spansPath.exists() || spansPath.mkdirs()) {
return spansPath;
}

Log.e(
SplunkRum.LOG_TAG,
"Error creating path " + spansPath + " for span buffer, defaulting to parent");
return rootDir;
}

@Override
public Stream<File> getAllSpanFiles() {
return fileUtils.listSpanFiles(provideSpanFile());
}

@Override
public long getTotalFileSizeInBytes() {
return fileUtils.getTotalFileSizeInBytes(provideSpanFile());
}

@Override
public Stream<File> getPendingFiles() {
return fileUtils.listSpanFiles(provideSpanFile());
}
}
Loading

0 comments on commit 41d5b50

Please sign in to comment.