Skip to content

Commit

Permalink
feat(replay): Add Mobile Replay (#3830)
Browse files Browse the repository at this point in the history
* feat(replay): Add Mobile Replay Alpha (#3714)

* feat(sample): add running indicator (animation overlay) (#3903)

* feat(replay): Add breadcrumbs mapping from RN to RRWeb format (#3846)

* feat(replay): Add network breadcrumbs (#3912)

* fix(replay): Add tests for touch events (#3924)

* feat(replay): Filter Sentry event breadcrumbs (#3925)

* fix(changelog): Add latest native SDKs details

* release: 5.25.0-alpha.2

* misc(samples): Add console anything examples for replay testing (#3928)

* feat: Add Sentry Babel Transformer (#3916)

* fix(replay): Add app lifecycle breadcrumbs conversion tests (#3932)

* chore(deps): bump sentry-android to 7.12.0-alpha.3

* chore(deps): bump sentry-android to 7.12.0-alpha.4

* fix(replay): Mask SVGs from `react-native-svg` when `maskAllVectors=true` (#3930)

* fix(replay): Add missing properties to android nav breadcrumbs (#3942)

* release: 5.26.0-alpha.3

* misc(replay): Add Mobile Replay Public Beta changelog (#3943)

---------

Co-authored-by: Ivan Dlugos <[email protected]>
Co-authored-by: Ivan Dlugos <[email protected]>
Co-authored-by: getsentry-bot <[email protected]>
Co-authored-by: getsentry-bot <[email protected]>
Co-authored-by: Roman Zavarnitsyn <[email protected]>
Co-authored-by: Bruno Garcia <[email protected]>
  • Loading branch information
7 people committed Jul 15, 2024
1 parent 7dc213a commit 9421616
Show file tree
Hide file tree
Showing 63 changed files with 3,061 additions and 106 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,6 @@ yalc.lock

# E2E tests
test/react-native/versions

# Created by Sentry Metro Plugin
.sentry/
131 changes: 128 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,58 @@

## Unreleased

### Features

- Session Replay Public Beta ([#3830](https://github.com/getsentry/sentry-react-native/pull/3830))

To enable Replay use the `replaysSessionSampleRate` or `replaysOnErrorSampleRate` options.

```js
import * as Sentry from '@sentry/react-native';

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

To add React Component Names use `annotateReactComponents` in `metro.config.js`.

```js
// For Expo
const { getSentryExpoConfig } = require("@sentry/react-native/metro");
const config = getSentryExpoConfig(__dirname, { annotateReactComponents: true });
// For RN
const { getDefaultConfig } = require('@react-native/metro-config');
const { withSentryConfig } = require('@sentry/react-native/metro');
module.exports = withSentryConfig(getDefaultConfig(__dirname), { annotateReactComponents: true });
```

To change default redaction behavior add the `mobileReplayIntegration`.

```js
import * as Sentry from '@sentry/react-native';
Sentry.init({
_experiments: {
replaysSessionSampleRate: 1.0,
replaysOnErrorSampleRate: 1.0,
},
integrations: [
Sentry.mobileReplayIntegration({
maskAllImages: true,
maskAllVectors: true,
maskAllText: true,
}),
],
});
```

To learn more visit [Sentry's Mobile Session Replay](https://docs.sentry.io/product/explore/session-replay/mobile/) documentation page.
### Dependencies
- Bump Cocoa SDK from v8.30.0 to v8.31.1 ([#3954](https://github.com/getsentry/sentry-react-native/pull/3954))
Expand Down Expand Up @@ -34,6 +86,30 @@
- [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#7110)
- [diff](https://github.com/getsentry/sentry-java/compare/7.10.0...7.11.0)
## 5.25.0-alpha.2
### Features
- Improve touch event component info if annotated with [`@sentry/babel-plugin-component-annotate`](https://www.npmjs.com/package/@sentry/babel-plugin-component-annotate) ([#3899](https://github.com/getsentry/sentry-react-native/pull/3899))
- Add replay breadcrumbs for touch & navigation events ([#3846](https://github.com/getsentry/sentry-react-native/pull/3846))
- Add network data to Session Replays ([#3912](https://github.com/getsentry/sentry-react-native/pull/3912))
- Filter Sentry Event Breadcrumbs from Mobile Replays ([#3925](https://github.com/getsentry/sentry-react-native/pull/3925))
### Fixes
- `sentry-expo-upload-sourcemaps` no longer requires Sentry url when uploading sourcemaps to `sentry.io` ([#3915](https://github.com/getsentry/sentry-react-native/pull/3915))
### Dependencies
- Bump Cocoa SDK from v8.25.0-alpha.0 to v8.30.0 ([#3914](https://github.com/getsentry/sentry-react-native/pull/3914))
- [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8300)
- [diff](https://github.com/getsentry/sentry-cocoa/compare/8.25.0-alpha.0...8.30.0)
- Bump Android SDK from v7.9.0-alpha.1 to v7.11.0-alpha.2 ([#3830](https://github.com/getsentry/sentry-react-native/pull/3830))
- [changelog](https://github.com/getsentry/sentry-java/blob/7.11.0-alpha.2/CHANGELOG.md#7110-alpha2)
- [diff](https://github.com/getsentry/sentry-java/compare/7.9.0-alpha.1...7.11.0-alpha.2)
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/)

## 5.24.1

### Fixes
Expand Down Expand Up @@ -133,6 +209,14 @@ This release does *not* build on iOS. Please use `5.23.1` or newer.
- [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8270)
- [diff](https://github.com/getsentry/sentry-cocoa/compare/8.26.0...8.27.0)

## 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/)
## 5.22.3
### Fixes
Expand Down Expand Up @@ -166,6 +250,47 @@ This release does *not* build on iOS. Please use `5.23.1` or newer.
- [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 Expand Up @@ -444,7 +569,7 @@ see [the Expo guide](https://docs.sentry.io/platforms/react-native/manual-setup/
const { getSentryExpoConfig } = require("@sentry/react-native/metro");

// const config = getDefaultConfig(__dirname);
const config = getSentryExpoConfig(config, {});
const config = getSentryExpoConfig(__dirname);
```

- New `npx sentry-expo-upload-sourcemaps` for simple EAS Update (`npx expo export`) source maps upload ([#3491](https://github.com/getsentry/sentry-react-native/pull/3491), [#3510](https://github.com/getsentry/sentry-react-native/pull/3510), [#3515](https://github.com/getsentry/sentry-react-native/pull/3515), [#3507](https://github.com/getsentry/sentry-react-native/pull/3507))
Expand Down Expand Up @@ -676,7 +801,7 @@ This release is compatible with `[email protected]` and newer.
});
```
Read more at https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md#7690
Read more at <https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md#7690>
- Report current screen in `contexts.app.view_names` ([#3339](https://github.com/getsentry/sentry-react-native/pull/3339))
Expand Down Expand Up @@ -2715,7 +2840,7 @@ We are looking into ways making this more stable and plan to re-enable it again
## v0.23.2
- Fixed #228 again ¯\\_(ツ)_
- Fixed #228 again ¯\\*(ツ)*/¯

## v0.23.1

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package io.sentry.rnsentryandroidtester

import io.sentry.Breadcrumb
import io.sentry.SentryLevel
import io.sentry.react.RNSentryReplayBreadcrumbConverter
import io.sentry.rrweb.RRWebBreadcrumbEvent
import io.sentry.rrweb.RRWebEventType
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4

@RunWith(JUnit4::class)
class RNSentryReplayBreadcrumbConverterTest {

@Test
fun convertNavigationBreadcrumb() {
val converter = RNSentryReplayBreadcrumbConverter()
val testBreadcrumb = Breadcrumb()
testBreadcrumb.level = SentryLevel.INFO
testBreadcrumb.type = "navigation"
testBreadcrumb.category = "navigation"
testBreadcrumb.setData("from", "HomeScreen")
testBreadcrumb.setData("to", "ProfileScreen")
val actual = converter.convert(testBreadcrumb) as RRWebBreadcrumbEvent

assertRRWebBreadcrumbDefaults(actual)
assertEquals(SentryLevel.INFO, actual.level)
assertEquals("navigation", actual.category)
assertEquals("HomeScreen", actual.data?.get("from"))
assertEquals("ProfileScreen", actual.data?.get("to"))
}

@Test
fun convertNavigationBreadcrumbWithOnlyTo() {
val converter = RNSentryReplayBreadcrumbConverter()
val testBreadcrumb = Breadcrumb()
testBreadcrumb.level = SentryLevel.INFO
testBreadcrumb.type = "navigation"
testBreadcrumb.category = "navigation"
testBreadcrumb.setData("to", "ProfileScreen")
val actual = converter.convert(testBreadcrumb) as RRWebBreadcrumbEvent

assertRRWebBreadcrumbDefaults(actual)
assertEquals(SentryLevel.INFO, actual.level)
assertEquals("navigation", actual.category)
assertEquals(null, actual.data?.get("from"))
assertEquals("ProfileScreen", actual.data?.get("to"))
}

@Test
fun convertForegroundBreadcrumb() {
val converter = RNSentryReplayBreadcrumbConverter()
val testBreadcrumb = Breadcrumb()
testBreadcrumb.type = "navigation"
testBreadcrumb.category = "app.lifecycle"
testBreadcrumb.setData("state", "foreground");
val actual = converter.convert(testBreadcrumb) as RRWebBreadcrumbEvent

assertRRWebBreadcrumbDefaults(actual)
assertEquals("app.foreground", actual.category)
}

@Test
fun convertBackgroundBreadcrumb() {
val converter = RNSentryReplayBreadcrumbConverter()
val testBreadcrumb = Breadcrumb()
testBreadcrumb.type = "navigation"
testBreadcrumb.category = "app.lifecycle"
testBreadcrumb.setData("state", "background");
val actual = converter.convert(testBreadcrumb) as RRWebBreadcrumbEvent

assertRRWebBreadcrumbDefaults(actual)
assertEquals("app.background", actual.category)
}

@Test
fun doesNotConvertSentryEventBreadcrumb() {
val converter = RNSentryReplayBreadcrumbConverter()
val testBreadcrumb = Breadcrumb();
testBreadcrumb.category = "sentry.event"
val actual = converter.convert(testBreadcrumb)
assertEquals(null, actual)
}

@Test
fun doesNotConvertSentryTransactionBreadcrumb() {
val converter = RNSentryReplayBreadcrumbConverter()
val testBreadcrumb = Breadcrumb();
testBreadcrumb.category = "sentry.transaction"
val actual = converter.convert(testBreadcrumb)
assertEquals(null, actual)
}

@Test
fun convertTouchBreadcrumb() {
val converter = RNSentryReplayBreadcrumbConverter()
val testBreadcrumb = Breadcrumb()
testBreadcrumb.level = SentryLevel.INFO
testBreadcrumb.type = "user"
testBreadcrumb.category = "touch"
testBreadcrumb.message = "this won't be used for replay"
testBreadcrumb.setData(
"path",
arrayListOf(mapOf(
"element" to "element4",
"file" to "file4")))
val actual = converter.convert(testBreadcrumb) as RRWebBreadcrumbEvent

assertRRWebBreadcrumbDefaults(actual)
assertEquals(SentryLevel.INFO, actual.level)
assertEquals("ui.tap", actual.category)
assertEquals(1, actual.data?.keys?.size)
assertEquals(
arrayListOf(mapOf(
"element" to "element4",
"file" to "file4")),
actual.data?.get("path"))
}

@Test
fun doesNotConvertNullPath() {
val actual = RNSentryReplayBreadcrumbConverter.getTouchPathMessage(null)
assertEquals(null, actual)
}

@Test
fun doesNotConvertPathContainingNull() {
val actual = RNSentryReplayBreadcrumbConverter.getTouchPathMessage(arrayListOf(arrayOfNulls<Any>(1)))
assertEquals(null, actual)
}

@Test
fun doesNotConvertPathWithValuesMissingNameAndLevel() {
val actual = RNSentryReplayBreadcrumbConverter.getTouchPathMessage(arrayListOf(mapOf(
"element" to "element4",
"file" to "file4")))
assertEquals(null, actual)
}

@Test
fun doesConvertValidPathExample1() {
val actual = RNSentryReplayBreadcrumbConverter.getTouchPathMessage(listOf(
mapOf("label" to "label0"),
mapOf("name" to "name1"),
mapOf("name" to "item2", "label" to "label2"),
mapOf("name" to "item3", "label" to "label3", "element" to "element3"),
mapOf("name" to "item4", "label" to "label4", "file" to "file4"),
mapOf("name" to "item5", "label" to "label5", "element" to "element5", "file" to "file5")))
assertEquals("label3(element3) > label2 > name1 > label0", actual)
}

@Test
fun doesConvertValidPathExample2() {
val actual = RNSentryReplayBreadcrumbConverter.getTouchPathMessage(listOf(
mapOf("name" to "item2", "label" to "label2"),
mapOf("name" to "item3", "label" to "label3", "element" to "element3"),
mapOf("name" to "item4", "label" to "label4", "file" to "file4"),
mapOf("name" to "item5", "label" to "label5", "element" to "element5", "file" to "file5"),
mapOf("label" to "label6"),
mapOf("name" to "name7")))
assertEquals("label5(element5, file5) > label4(file4) > label3(element3) > label2", actual)
}

private fun assertRRWebBreadcrumbDefaults(actual: RRWebBreadcrumbEvent) {
assertEquals("default", actual.breadcrumbType)
assertEquals(actual.breadcrumbTimestamp * 1000, actual.timestamp.toDouble(), 0.05)
assert(actual.breadcrumbTimestamp > 0)
}
}
Loading

0 comments on commit 9421616

Please sign in to comment.