Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
60d07df
feat(replay): Add Mobile Replay Alpha (#3714)
krystofwoldrich May 21, 2024
41f816a
Merge branch 'main' into feat/replay
vaind Jun 4, 2024
c3ff79f
Merge branch 'main' into feat/replay
vaind Jun 18, 2024
13a9360
feat(sample): add running indicator (animation overlay) (#3903)
krystofwoldrich Jun 21, 2024
1f1e41e
Merge branch 'main' into feat/replay
vaind Jun 26, 2024
38d8d7c
feat(replay): Add breadcrumbs mapping from RN to RRWeb format (#3846)
vaind Jun 26, 2024
ac72abc
feat(replay): Add network breadcrumbs (#3912)
krystofwoldrich Jun 27, 2024
5f3a5c8
fix(replay): Add tests for touch events (#3924)
krystofwoldrich Jul 2, 2024
b4aaa68
feat(replay): Filter Sentry event breadcrumbs (#3925)
krystofwoldrich Jul 2, 2024
00aa520
Merge branch 'main' into feat/replay
krystofwoldrich Jul 2, 2024
cfd5aee
fix(changelog): Add latest native SDKs details
krystofwoldrich Jul 2, 2024
83f5a0c
release: 5.25.0-alpha.2
getsentry-bot Jul 2, 2024
8e9c3a0
Merge branch 'release/5.25.0-alpha.2' into feat/replay
Jul 2, 2024
9672e88
misc(samples): Add console anything examples for replay testing (#3928)
krystofwoldrich Jul 3, 2024
6067ecc
feat: Add Sentry Babel Transformer (#3916)
krystofwoldrich Jul 3, 2024
3b28c40
fix(replay): Add app lifecycle breadcrumbs conversion tests (#3932)
krystofwoldrich Jul 5, 2024
e25da10
Merge remote-tracking branch 'origin/main' into feat/replay
krystofwoldrich Jul 9, 2024
6d8c4dd
chore(deps): bump sentry-android to 7.12.0-alpha.3
krystofwoldrich Jul 9, 2024
6fd2a34
chore(deps): bump sentry-android to 7.12.0-alpha.4
krystofwoldrich Jul 9, 2024
3dcf57b
fix(replay): Mask SVGs from `react-native-svg` when `maskAllVectors=t…
krystofwoldrich Jul 10, 2024
361867e
Merge remote-tracking branch 'origin/main' into feat/replay
krystofwoldrich Jul 10, 2024
f96cf53
Merge remote-tracking branch 'origin/main' into feat/replay
krystofwoldrich Jul 12, 2024
254b772
fix(replay): Add missing properties to android nav breadcrumbs (#3942)
krystofwoldrich Jul 12, 2024
7b9baca
release: 5.26.0-alpha.3
getsentry-bot Jul 12, 2024
222c9dd
Merge branch 'release/5.26.0-alpha.3' into feat/replay
Jul 12, 2024
0b74944
misc(replay): Add Mobile Replay Public Beta changelog (#3943)
krystofwoldrich Jul 15, 2024
4088ea8
Merge branch 'main' into feat/replay
romtsn Jul 15, 2024
a1da3bf
Merge branch 'main' into feat/replay
bruno-garcia Jul 15, 2024
b9a7f9d
Merge branch 'main' into feat/replay
bruno-garcia Jul 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat(replay): Add Mobile Replay Alpha (#3714)
  • Loading branch information
krystofwoldrich authored May 21, 2024
commit 60d07df95e9ab29ca29be25c5106327458ef5a75
49 changes: 48 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Changelog

## Unreleased
## 5.23.0-alpha.1

### Fixes

- Pass `replaysSessionSampleRate` option to Android ([#3714](https://github.com/getsentry/sentry-react-native/pull/3714))

Access to Mobile Replay is limited to early access orgs on Sentry. If you're interested, [sign up for the waitlist](https://sentry.io/lp/mobile-replay-beta/)

### Features

Expand Down Expand Up @@ -69,6 +75,47 @@
- [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8250)
- [diff](https://github.com/getsentry/sentry-cocoa/compare/8.24.0...8.25.0)

## 5.23.0-alpha.0

### Features

- Mobile Session Replay Alpha ([#3714](https://github.com/getsentry/sentry-react-native/pull/3714))

To enable Replay for React Native on mobile and web add the following options.

```js
Sentry.init({
_experiments: {
replaysSessionSampleRate: 1.0,
replaysOnErrorSampleRate: 1.0,
},
});
```

To change the default Mobile Replay options add the `mobileReplayIntegration`.

```js
Sentry.init({
_experiments: {
replaysSessionSampleRate: 1.0,
replaysOnErrorSampleRate: 1.0,
},
integration: [
Sentry.mobileReplayIntegration({
maskAllText: true,
maskAllImages: true,
}),
],
});
```

Access is limited to early access orgs on Sentry. If you're interested, [sign up for the waitlist](https://sentry.io/lp/mobile-replay-beta/)

### Dependencies

- Bump Cocoa SDK to [8.25.0-alpha.0](https://github.com/getsentry/sentry-cocoa/releases/tag/8.25.0-alpha.0)
- Bump Android SDK to [7.9.0-alpha.1](https://github.com/getsentry/sentry-java/releases/tag/7.9.0-alpha.1)

## 5.22.0

### Features
Expand Down
2 changes: 1 addition & 1 deletion RNSentry.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Pod::Spec.new do |s|
s.preserve_paths = '*.js'

s.dependency 'React-Core'
s.dependency 'Sentry/HybridSDK', '8.25.2'
s.dependency 'Sentry/HybridSDK', '8.25.0-alpha.0'

s.source_files = 'ios/**/*.{h,m,mm}'
s.public_header_files = 'ios/RNSentry.h'
Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,5 @@ android {

dependencies {
implementation 'com.facebook.react:react-native:+'
api 'io.sentry:sentry-android:7.8.0'
api 'io.sentry:sentry-android:7.9.0-alpha.1'
}
55 changes: 54 additions & 1 deletion android/src/main/java/io/sentry/react/RNSentryModuleImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
import io.sentry.SentryExecutorService;
import io.sentry.SentryLevel;
import io.sentry.SentryOptions;
import io.sentry.SentryReplayOptions;
import io.sentry.UncaughtExceptionHandlerIntegration;
import io.sentry.android.core.AndroidLogger;
import io.sentry.android.core.AndroidProfiler;
Expand All @@ -79,6 +80,7 @@
import io.sentry.android.core.performance.AppStartMetrics;
import io.sentry.protocol.SdkVersion;
import io.sentry.protocol.SentryException;
import io.sentry.protocol.SentryId;
import io.sentry.protocol.SentryPackage;
import io.sentry.protocol.User;
import io.sentry.protocol.ViewHierarchy;
Expand Down Expand Up @@ -252,7 +254,9 @@ public void initNativeSdk(final ReadableMap rnOptions, Promise promise) {
if (rnOptions.hasKey("enableNdk")) {
options.setEnableNdk(rnOptions.getBoolean("enableNdk"));
}

if (rnOptions.hasKey("_experiments")) {
options.getExperimental().setSessionReplay(getReplayOptions(rnOptions));
}
options.setBeforeSend((event, hint) -> {
// React native internally throws a JavascriptException
// Since we catch it before that, we don't want to send this one
Expand Down Expand Up @@ -293,6 +297,37 @@ public void initNativeSdk(final ReadableMap rnOptions, Promise promise) {
promise.resolve(true);
}

private SentryReplayOptions getReplayOptions(@NotNull ReadableMap rnOptions) {
@NotNull final SentryReplayOptions androidReplayOptions = new SentryReplayOptions();

@Nullable final ReadableMap rnExperimentsOptions = rnOptions.getMap("_experiments");
if (rnExperimentsOptions == null) {
return androidReplayOptions;
}

if (!(rnExperimentsOptions.hasKey("replaysSessionSampleRate") || rnExperimentsOptions.hasKey("replaysOnErrorSampleRate"))) {
return androidReplayOptions;
}

androidReplayOptions.setSessionSampleRate(rnExperimentsOptions.hasKey("replaysSessionSampleRate")
? rnExperimentsOptions.getDouble("replaysSessionSampleRate") : null);
androidReplayOptions.setErrorSampleRate(rnExperimentsOptions.hasKey("replaysOnErrorSampleRate")
? rnExperimentsOptions.getDouble("replaysOnErrorSampleRate") : null);

if (!rnOptions.hasKey("mobileReplayOptions")) {
return androidReplayOptions;
}
@Nullable final ReadableMap rnMobileReplayOptions = rnOptions.getMap("mobileReplayOptions");
if (rnMobileReplayOptions == null) {
return androidReplayOptions;
}

androidReplayOptions.setRedactAllText(!rnMobileReplayOptions.hasKey("maskAllText") || rnMobileReplayOptions.getBoolean("maskAllText"));
androidReplayOptions.setRedactAllImages(!rnMobileReplayOptions.hasKey("maskAllImages") || rnMobileReplayOptions.getBoolean("maskAllImages"));

return androidReplayOptions;
}

public void crash() {
throw new RuntimeException("TEST - Sentry Client Crash (only works in release mode)");
}
Expand Down Expand Up @@ -410,6 +445,24 @@ public void fetchNativeFrames(Promise promise) {
}
}

public void captureReplay(boolean isHardCrash, Promise promise) {
Sentry.getCurrentHub().getOptions().getReplayController().sendReplay(isHardCrash, null, null);
promise.resolve(getCurrentReplayId());
}

public @Nullable String getCurrentReplayId() {
final @Nullable IScope scope = InternalSentrySdk.getCurrentScope();
if (scope == null) {
return null;
}

final @NotNull SentryId id = scope.getReplayId();
if (id == SentryId.EMPTY_ID) {
return null;
}
return id.toString();
}

public void captureEnvelope(String rawBytes, ReadableMap options, Promise promise) {
byte[] bytes = Base64.decode(rawBytes, Base64.DEFAULT);

Expand Down
10 changes: 10 additions & 0 deletions android/src/newarch/java/io/sentry/react/RNSentryModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,14 @@ public WritableMap fetchNativeStackFramesBy(ReadableArray instructionsAddr) {
// Not used on Android
return null;
}

@Override
public void captureReplay(boolean isHardCrash, Promise promise) {
this.impl.captureReplay(isHardCrash, promise);
}

@Override
public String getCurrentReplayId() {
return this.impl.getCurrentReplayId();
}
}
10 changes: 10 additions & 0 deletions android/src/oldarch/java/io/sentry/react/RNSentryModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,14 @@ public WritableMap fetchNativeStackFramesBy(ReadableArray instructionsAddr) {
// Not used on Android
return null;
}

@ReactMethod
public void captureReplay(boolean isHardCrash, Promise promise) {
this.impl.captureReplay(isHardCrash, promise);
}

@ReactMethod(isBlockingSynchronousMethod = true)
public String getCurrentReplayId() {
return this.impl.getCurrentReplayId();
}
}
48 changes: 47 additions & 1 deletion ios/RNSentry.mm
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ - (SentryOptions *_Nullable)createOptionsWithDictionary:(NSDictionary *_Nonnull)
// Because we sent it already before the app crashed.
if (nil != event.exceptions.firstObject.type &&
[event.exceptions.firstObject.type rangeOfString:@"Unhandled JS Exception"].location != NSNotFound) {
NSLog(@"Unhandled JS Exception");
return nil;
}

Expand All @@ -135,6 +134,28 @@ - (SentryOptions *_Nullable)createOptionsWithDictionary:(NSDictionary *_Nonnull)
[mutableOptions removeObjectForKey:@"tracesSampler"];
[mutableOptions removeObjectForKey:@"enableTracing"];

if ([mutableOptions valueForKey:@"_experiments"] != nil) {
NSDictionary *experiments = mutableOptions[@"_experiments"];
if (experiments[@"replaysSessionSampleRate"] != nil || experiments[@"replaysOnErrorSampleRate"] != nil) {
[mutableOptions setValue:@{
@"sessionReplay": @{
@"sessionSampleRate": experiments[@"replaysSessionSampleRate"] ?: [NSNull null],
@"errorSampleRate": experiments[@"replaysOnErrorSampleRate"] ?: [NSNull null],
@"redactAllImages": mutableOptions[@"mobileReplayOptions"] != nil &&
mutableOptions[@"mobileReplayOptions"][@"maskAllImages"] != nil
? mutableOptions[@"mobileReplayOptions"][@"maskAllImages"]
: [NSNull null],
@"redactAllText": mutableOptions[@"mobileReplayOptions"] != nil &&
mutableOptions[@"mobileReplayOptions"][@"maskAllText"] != nil
? mutableOptions[@"mobileReplayOptions"][@"maskAllText"]
: [NSNull null],
}
} forKey:@"experimental"];
[self addReplayRNRedactClasses: mutableOptions[@"mobileReplayOptions"]];
}
[mutableOptions removeObjectForKey:@"_experiments"];
}

SentryOptions *sentryOptions = [[SentryOptions alloc] initWithDict:mutableOptions didFailWithError:errorPointer];
if (*errorPointer != nil) {
return nil;
Expand Down Expand Up @@ -644,6 +665,31 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray<NSNumber*>*)instructionsAdd
// the 'tracesSampleRate' or 'tracesSampler' option.
}

RCT_EXPORT_METHOD(captureReplay: (BOOL)isHardCrash
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
[PrivateSentrySDKOnly captureReplay];
resolve([PrivateSentrySDKOnly getReplayId]);
}

RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSString *, getCurrentReplayId)
{
return [PrivateSentrySDKOnly getReplayId];
}

- (void) addReplayRNRedactClasses: (NSDictionary *_Nullable)replayOptions
{
NSMutableArray *_Nonnull classesToRedact = [[NSMutableArray alloc] init];
if ([replayOptions[@"maskAllImages"] boolValue] == YES) {
[classesToRedact addObject: NSClassFromString(@"RCTImageView")];
}
if ([replayOptions[@"maskAllText"] boolValue] == YES) {
[classesToRedact addObject: NSClassFromString(@"RCTTextView")];
}
[PrivateSentrySDKOnly addReplayRedactClasses: classesToRedact];
}

static NSString* const enabledProfilingMessage = @"Enable Hermes to use Sentry Profiling.";
static SentryId* nativeProfileTraceId = nil;
static uint64_t nativeProfileStartTime = 0;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@sentry/react-native",
"homepage": "https://github.com/getsentry/sentry-react-native",
"repository": "https://github.com/getsentry/sentry-react-native",
"version": "5.22.2",
"version": "5.23.0-alpha.1",
"description": "Official Sentry SDK for react-native",
"typings": "dist/js/index.d.ts",
"types": "dist/js/index.d.ts",
Expand Down
6 changes: 3 additions & 3 deletions samples/expo/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"slug": "sentry-react-native-expo-sample",
"jsEngine": "hermes",
"scheme": "sentry-expo-sample",
"version": "5.22.2",
"version": "5.23.0-alpha.1",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
Expand All @@ -19,15 +19,15 @@
"ios": {
"supportsTablet": true,
"bundleIdentifier": "io.sentry.expo.sample",
"buildNumber": "6"
"buildNumber": "7"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"package": "io.sentry.expo.sample",
"versionCode": 6
"versionCode": 7
},
"web": {
"bundler": "metro",
Expand Down
2 changes: 2 additions & 0 deletions samples/expo/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ process.env.EXPO_SKIP_DURING_EXPORT !== 'true' && Sentry.init({
// dist: `1`,
_experiments: {
profilesSampleRate: 0,
// replaysOnErrorSampleRate: 1.0,
replaysSessionSampleRate: 1.0,
},
enableSpotlight: true,
});
Expand Down
2 changes: 1 addition & 1 deletion samples/expo/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sentry-react-native-expo-sample",
"version": "5.22.2",
"version": "5.23.0-alpha.1",
"main": "expo-router/entry",
"scripts": {
"start": "expo start",
Expand Down
4 changes: 2 additions & 2 deletions samples/react-native/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ android {
applicationId "io.sentry.reactnative.sample"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 13
versionName "5.22.2"
versionCode 14
versionName "5.23.0-alpha.1"
}

signingConfigs {
Expand Down
4 changes: 2 additions & 2 deletions samples/react-native/ios/sentryreactnativesample/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>5.22.2</string>
<string>5.23.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>13</string>
<string>14</string>
<key>LSRequiresIPhoneOS</key>
<true />
<key>NSAppTransportSecurity</key>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>5.22.2</string>
<string>5.23.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>13</string>
<string>14</string>
</dict>
</plist>
2 changes: 1 addition & 1 deletion samples/react-native/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sentry-react-native-sample",
"version": "5.22.2",
"version": "5.23.0-alpha.1",
"private": true,
"scripts": {
"postinstall": "patch-package",
Expand Down
Loading