Skip to content

Commit e34c467

Browse files
romtsngetsentry-botmarkushigetsentry-botkrystofwoldrich
authored
[SR] Session Replay (#3339)
* Add new sentry-android-replay module * Add screenshot recorder * Add sentry replay envelope and event * Add TODOs and license headers * Api dump * Formatting * Lint * Format code * More comments * Disable detekt plugin for now * WIP * Add replay envelopes * Remove jsonValue * Remove * Fix json * Finalize replay envelopes * Introduce MapObjectReader * Add missing test * Add test for MapObjectReader * Add MapObjectWriter change * Add finals * Fix test * Fix test * Address review * Add finals and annotations * Specify SHA for license headers * Address review from Dhiogo * Address review from Markus * Remove public captureReplay method * Fix test * api dump * api dump * Address review from Markus * Api dump * Add replay integration * Uncomment redacting * Update proguard rules * Add missing rule for AndroidTest * Add ReplayCache tests * Add tests * Add SessionReplayOptions * Call listeners when installing RootViewsSpy * Call listeners when installing RootViewsSpy * SessionReplayOptions -> SentryReplayOptions * Fix test * Add AndroidManifest options for replays * Add buffer mode and link replays with events/transactions * Pass hint to captureReplay * Better error handling * recycler lastScreenshot before re-assigning * Expose ReplayCache as public api * Fix redacting out of sync * _experimental -> experimental * Merge conflicts * Fix tests * Add more tests * Improve ReplayCache logic * frameUsec -> frameDurationUsec * bottom/right -> height/width * add todos * duration -> durationMs * replaId non-nullable * More conflicts * More conflicts * Fix tests * Address PR review * Add kdoc * Add kdoc * Fix tests * Add comment for experimental options * Do not run recorder if full session was not sampled * Add more tests * Add session deadline of 1h * Clean up older replays when starting a new one * Remove unnecessary extension fun * Safe executors * Fix crashing MediaCodec and use density to determine recording resolution * Add redact options and align naming * Fix tests * Fix tests * WIP * Try-catch release of encoder * Support orientation change for session mode * WIP * Spotless * TODO * Update sentry/src/main/java/io/sentry/SentryReplayOptions.java Co-authored-by: Markus Hintersteiner <[email protected]> * More gates * Revert addAll * Fix conflicts * fix test * release: 7.8.0-alpha.0 * Introduce CaptureStrategy for buffer and session modes * Formatting * WIP * Expose public API for flutter * Spotless * Spotless * Remove breadcrumb import * Send temporary breadcrumbs and add test * Formatting * Sort rrweb events * Formatting * Expose replayCacheDir * Capture network requests * Change op name to resource.http * feat(replay): Add `sendReplay` method for Hybrid SDKs * fix apiDump * Address PR review * Capture motion events as incremental rrweb events * Spotless * Revert * Changelog * release: 7.9.0-alpha.1 * Fix test * WIP * Adhere to rrweb move event expectations * formatting * Align breadcrumbs with frontend and iOS * Add tests and fix deserialization * Rotate buffered motion events in buffer mode * Add Nullables * Address PR feedback * Formatting * Rotate current events until segment end exclusively * Allow rrweb breadcrumb customization from hybrid SDKs * Fix proguard rules * WIP * Add tests * Detect obscured views * revert some thigns * Remove commented code * Suppress lint * Support multi-touch gestures * Address PR feedback * Changelog * release: 7.11.0-alpha.2 * Make multi-touch work * Fix tests * WIP * Capture screen names as urls for replay * Fix * Ignore warning * Address PR feedback * Tests * Add quality settings * Fix redacting out of sync * Remove time measuring * Mark isEnableScreenTracking as experimental * Format code * Address PR feedback * Clean up * Spotless * Format code * Changelog * release: 7.12.0-alpha.3 * [SR] Add `redactClasses` option (#3546) Co-authored-by: Roman Zavarnitsyn <[email protected]> * misc(changelog): Prepare for next alpha * fix(changelog): Bump alpha version number * release: 7.12.0-alpha.4 * Redaction fixes for RN * Add stopgap for offline session recording * Recycle unused bitmap * Add tests for sentry * Add ReplayIntegrationTest * Replay SmokeTest * Fix test * Fix test * Fix events linking with buffered replays * Changelog --------- Co-authored-by: Sentry Github Bot <[email protected]> Co-authored-by: Markus Hintersteiner <[email protected]> Co-authored-by: getsentry-bot <[email protected]> Co-authored-by: getsentry-bot <[email protected]> Co-authored-by: Krystof Woldrich <[email protected]> Co-authored-by: Krystof Woldrich <[email protected]>
1 parent 25f1ca4 commit e34c467

File tree

197 files changed

+12153
-452
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

197 files changed

+12153
-452
lines changed

CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,34 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Features
6+
7+
- Session Replay Public Beta ([#3339](https://github.com/getsentry/sentry-java/pull/3339))
8+
9+
To enable Replay use the `sessionReplay.sessionSampleRate` or `sessionReplay.errorSampleRate` experimental options.
10+
11+
```kotlin
12+
import io.sentry.SentryReplayOptions
13+
import io.sentry.android.core.SentryAndroid
14+
15+
SentryAndroid.init(context) { options ->
16+
17+
// Currently under experimental options:
18+
options.experimental.sessionReplay.sessionSampleRate = 1.0
19+
options.experimental.sessionReplay.errorSampleRate = 1.0
20+
21+
// To change default redaction behavior (defaults to true)
22+
options.experimental.sessionReplay.redactAllImages = true
23+
options.experimental.sessionReplay.redactAllText = true
24+
25+
// To change quality of the recording (defaults to MEDIUM)
26+
options.experimental.sessionReplay.quality = SentryReplayOptions.SentryReplayQuality.MEDIUM // (LOW|MEDIUM|HIGH)
27+
}
28+
```
29+
30+
To learn more visit [Sentry's Mobile Session Replay](https://docs.sentry.io/product/explore/session-replay/mobile/) documentation page.
31+
332
## 7.11.0
433

534
### Features

build.gradle.kts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ subprojects {
112112
"sentry-android-ndk",
113113
"sentry-android-okhttp",
114114
"sentry-android-sqlite",
115+
"sentry-android-replay",
115116
"sentry-android-timber"
116117
)
117118
if (jacocoAndroidModules.contains(name)) {
@@ -296,7 +297,9 @@ private val androidLibs = setOf(
296297
"sentry-android-navigation",
297298
"sentry-android-okhttp",
298299
"sentry-android-timber",
299-
"sentry-compose-android"
300+
"sentry-compose-android",
301+
"sentry-android-sqlite",
302+
"sentry-android-replay"
300303
)
301304

302305
private val androidXLibs = listOf(

buildSrc/src/main/java/Config.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ object Config {
3434

3535
val minSdkVersion = 19
3636
val minSdkVersionOkHttp = 21
37+
val minSdkVersionReplay = 19
3738
val minSdkVersionNdk = 19
3839
val minSdkVersionCompose = 21
3940
val targetSdkVersion = sdkVersion
@@ -194,6 +195,7 @@ object Config {
194195
val jsonUnit = "net.javacrumbs.json-unit:json-unit:2.32.0"
195196
val hsqldb = "org.hsqldb:hsqldb:2.6.1"
196197
val javaFaker = "com.github.javafaker:javafaker:1.0.2"
198+
val msgpack = "org.msgpack:msgpack-core:0.9.8"
197199
}
198200

199201
object QualityPlugins {

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ android.useAndroidX=true
1010
android.defaults.buildfeatures.buildconfig=true
1111

1212
# Release information
13-
versionName=7.11.0
13+
versionName=7.12.0-alpha.4
1414

1515
# Override the SDK name on native crashes on Android
1616
sentryAndroidSdkName=sentry.native.android

sentry-android-core/api/sentry-android-core.api

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,11 @@ public final class io/sentry/android/core/CurrentActivityIntegration : android/a
184184
public final class io/sentry/android/core/DeviceInfoUtil {
185185
public fun <init> (Landroid/content/Context;Lio/sentry/android/core/SentryAndroidOptions;)V
186186
public fun collectDeviceInformation (ZZ)Lio/sentry/protocol/Device;
187+
public static fun getBatteryLevel (Landroid/content/Intent;Lio/sentry/SentryOptions;)Ljava/lang/Float;
187188
public static fun getInstance (Landroid/content/Context;Lio/sentry/android/core/SentryAndroidOptions;)Lio/sentry/android/core/DeviceInfoUtil;
188189
public fun getOperatingSystem ()Lio/sentry/protocol/OperatingSystem;
189190
public fun getSideLoadedInfo ()Lio/sentry/android/core/ContextUtils$SideLoadedInfo;
191+
public static fun isCharging (Landroid/content/Intent;Lio/sentry/SentryOptions;)Ljava/lang/Boolean;
190192
public static fun resetInstance ()V
191193
}
192194

sentry-android-core/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ dependencies {
7676
api(projects.sentry)
7777
compileOnly(projects.sentryAndroidFragment)
7878
compileOnly(projects.sentryAndroidTimber)
79+
compileOnly(projects.sentryAndroidReplay)
7980
compileOnly(projects.sentryCompose)
8081
compileOnly(projects.sentryComposeHelper)
8182

@@ -104,6 +105,7 @@ dependencies {
104105
testImplementation(projects.sentryTestSupport)
105106
testImplementation(projects.sentryAndroidFragment)
106107
testImplementation(projects.sentryAndroidTimber)
108+
testImplementation(projects.sentryAndroidReplay)
107109
testImplementation(projects.sentryComposeHelper)
108110
testImplementation(projects.sentryAndroidNdk)
109111
testRuntimeOnly(Config.Libs.composeUi)

sentry-android-core/proguard-rules.pro

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,9 @@
7272
-keepnames class io.sentry.exception.SentryHttpClientException
7373

7474
##---------------End: proguard configuration for sentry-okhttp ----------
75+
76+
##---------------Begin: proguard configuration for sentry-android-replay ----------
77+
-dontwarn io.sentry.android.replay.ReplayIntegration
78+
-dontwarn io.sentry.android.replay.DefaultReplayBreadcrumbConverter
79+
-keepnames class io.sentry.android.replay.ReplayIntegration
80+
##---------------End: proguard configuration for sentry-android-replay ----------

sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ private void finishTransaction(
371371
public synchronized void onActivityCreated(
372372
final @NotNull Activity activity, final @Nullable Bundle savedInstanceState) {
373373
setColdStart(savedInstanceState);
374-
if (hub != null) {
374+
if (hub != null && options != null && options.isEnableScreenTracking()) {
375375
final @Nullable String activityClassName = ClassUtil.getClassName(activity);
376376
hub.configureScope(scope -> scope.setScreen(activityClassName));
377377
}

sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,16 @@
2222
import io.sentry.android.core.internal.util.SentryFrameMetricsCollector;
2323
import io.sentry.android.core.performance.AppStartMetrics;
2424
import io.sentry.android.fragment.FragmentLifecycleIntegration;
25+
import io.sentry.android.replay.DefaultReplayBreadcrumbConverter;
26+
import io.sentry.android.replay.ReplayIntegration;
2527
import io.sentry.android.timber.SentryTimberIntegration;
2628
import io.sentry.cache.PersistingOptionsObserver;
2729
import io.sentry.cache.PersistingScopeObserver;
2830
import io.sentry.compose.gestures.ComposeGestureTargetLocator;
2931
import io.sentry.compose.viewhierarchy.ComposeViewHierarchyExporter;
3032
import io.sentry.internal.gestures.GestureTargetLocator;
3133
import io.sentry.internal.viewhierarchy.ViewHierarchyExporter;
34+
import io.sentry.transport.CurrentDateProvider;
3235
import io.sentry.transport.NoOpEnvelopeCache;
3336
import io.sentry.util.LazyEvaluator;
3437
import io.sentry.util.Objects;
@@ -237,7 +240,8 @@ static void installDefaultIntegrations(
237240
final @NotNull LoadClass loadClass,
238241
final @NotNull ActivityFramesTracker activityFramesTracker,
239242
final boolean isFragmentAvailable,
240-
final boolean isTimberAvailable) {
243+
final boolean isTimberAvailable,
244+
final boolean isReplayAvailable) {
241245

242246
// Integration MUST NOT cache option values in ctor, as they will be configured later by the
243247
// user
@@ -302,6 +306,13 @@ static void installDefaultIntegrations(
302306
new NetworkBreadcrumbsIntegration(context, buildInfoProvider, options.getLogger()));
303307
options.addIntegration(new TempSensorBreadcrumbsIntegration(context));
304308
options.addIntegration(new PhoneStateBreadcrumbsIntegration(context));
309+
if (isReplayAvailable) {
310+
final ReplayIntegration replay =
311+
new ReplayIntegration(context, CurrentDateProvider.getInstance());
312+
replay.setBreadcrumbConverter(new DefaultReplayBreadcrumbConverter());
313+
options.addIntegration(replay);
314+
options.setReplayController(replay);
315+
}
305316
}
306317

307318
/**

sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import io.sentry.SentryBaseEvent;
1111
import io.sentry.SentryEvent;
1212
import io.sentry.SentryLevel;
13+
import io.sentry.SentryReplayEvent;
1314
import io.sentry.android.core.internal.util.AndroidMainThreadChecker;
1415
import io.sentry.android.core.performance.AppStartMetrics;
1516
import io.sentry.android.core.performance.TimeSpan;
@@ -303,4 +304,17 @@ private void setSideLoadedInfo(final @NotNull SentryBaseEvent event) {
303304

304305
return transaction;
305306
}
307+
308+
@Override
309+
public @NotNull SentryReplayEvent process(
310+
final @NotNull SentryReplayEvent event, final @NotNull Hint hint) {
311+
final boolean applyScopeData = shouldApplyScopeData(event, hint);
312+
if (applyScopeData) {
313+
processNonCachedEvent(event, hint);
314+
}
315+
316+
setCommons(event, false, applyScopeData);
317+
318+
return event;
319+
}
306320
}

0 commit comments

Comments
 (0)