Skip to content

Commit 9421616

Browse files
krystofwoldrichvaindgetsentry-botgetsentry-botromtsn
authored
feat(replay): Add Mobile Replay (#3830)
* 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]>
1 parent 7dc213a commit 9421616

File tree

63 files changed

+3061
-106
lines changed

Some content is hidden

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

63 files changed

+3061
-106
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,6 @@ yalc.lock
7474

7575
# E2E tests
7676
test/react-native/versions
77+
78+
# Created by Sentry Metro Plugin
79+
.sentry/

CHANGELOG.md

Lines changed: 128 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,58 @@
22

33
## Unreleased
44

5+
### Features
6+
7+
- Session Replay Public Beta ([#3830](https://github.com/getsentry/sentry-react-native/pull/3830))
8+
9+
To enable Replay use the `replaysSessionSampleRate` or `replaysOnErrorSampleRate` options.
10+
11+
```js
12+
import * as Sentry from '@sentry/react-native';
13+
14+
Sentry.init({
15+
_experiments: {
16+
replaysSessionSampleRate: 1.0,
17+
replaysOnErrorSampleRate: 1.0,
18+
},
19+
});
20+
```
21+
22+
To add React Component Names use `annotateReactComponents` in `metro.config.js`.
23+
24+
```js
25+
// For Expo
26+
const { getSentryExpoConfig } = require("@sentry/react-native/metro");
27+
const config = getSentryExpoConfig(__dirname, { annotateReactComponents: true });
28+
29+
// For RN
30+
const { getDefaultConfig } = require('@react-native/metro-config');
31+
const { withSentryConfig } = require('@sentry/react-native/metro');
32+
module.exports = withSentryConfig(getDefaultConfig(__dirname), { annotateReactComponents: true });
33+
```
34+
35+
To change default redaction behavior add the `mobileReplayIntegration`.
36+
37+
```js
38+
import * as Sentry from '@sentry/react-native';
39+
40+
Sentry.init({
41+
_experiments: {
42+
replaysSessionSampleRate: 1.0,
43+
replaysOnErrorSampleRate: 1.0,
44+
},
45+
integrations: [
46+
Sentry.mobileReplayIntegration({
47+
maskAllImages: true,
48+
maskAllVectors: true,
49+
maskAllText: true,
50+
}),
51+
],
52+
});
53+
```
54+
55+
To learn more visit [Sentry's Mobile Session Replay](https://docs.sentry.io/product/explore/session-replay/mobile/) documentation page.
56+
557
### Dependencies
658

759
- Bump Cocoa SDK from v8.30.0 to v8.31.1 ([#3954](https://github.com/getsentry/sentry-react-native/pull/3954))
@@ -34,6 +86,30 @@
3486
- [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#7110)
3587
- [diff](https://github.com/getsentry/sentry-java/compare/7.10.0...7.11.0)
3688

89+
## 5.25.0-alpha.2
90+
91+
### Features
92+
93+
- 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))
94+
- Add replay breadcrumbs for touch & navigation events ([#3846](https://github.com/getsentry/sentry-react-native/pull/3846))
95+
- Add network data to Session Replays ([#3912](https://github.com/getsentry/sentry-react-native/pull/3912))
96+
- Filter Sentry Event Breadcrumbs from Mobile Replays ([#3925](https://github.com/getsentry/sentry-react-native/pull/3925))
97+
98+
### Fixes
99+
100+
- `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))
101+
102+
### Dependencies
103+
104+
- Bump Cocoa SDK from v8.25.0-alpha.0 to v8.30.0 ([#3914](https://github.com/getsentry/sentry-react-native/pull/3914))
105+
- [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8300)
106+
- [diff](https://github.com/getsentry/sentry-cocoa/compare/8.25.0-alpha.0...8.30.0)
107+
- 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))
108+
- [changelog](https://github.com/getsentry/sentry-java/blob/7.11.0-alpha.2/CHANGELOG.md#7110-alpha2)
109+
- [diff](https://github.com/getsentry/sentry-java/compare/7.9.0-alpha.1...7.11.0-alpha.2)
110+
111+
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/)
112+
37113
## 5.24.1
38114

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

212+
## 5.23.0-alpha.1
213+
214+
### Fixes
215+
216+
- Pass `replaysSessionSampleRate` option to Android ([#3714](https://github.com/getsentry/sentry-react-native/pull/3714))
217+
218+
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/)
219+
136220
## 5.22.3
137221

138222
### Fixes
@@ -166,6 +250,47 @@ This release does *not* build on iOS. Please use `5.23.1` or newer.
166250
- [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8250)
167251
- [diff](https://github.com/getsentry/sentry-cocoa/compare/8.24.0...8.25.0)
168252

253+
## 5.23.0-alpha.0
254+
255+
### Features
256+
257+
- Mobile Session Replay Alpha ([#3714](https://github.com/getsentry/sentry-react-native/pull/3714))
258+
259+
To enable Replay for React Native on mobile and web add the following options.
260+
261+
```js
262+
Sentry.init({
263+
_experiments: {
264+
replaysSessionSampleRate: 1.0,
265+
replaysOnErrorSampleRate: 1.0,
266+
},
267+
});
268+
```
269+
270+
To change the default Mobile Replay options add the `mobileReplayIntegration`.
271+
272+
```js
273+
Sentry.init({
274+
_experiments: {
275+
replaysSessionSampleRate: 1.0,
276+
replaysOnErrorSampleRate: 1.0,
277+
},
278+
integration: [
279+
Sentry.mobileReplayIntegration({
280+
maskAllText: true,
281+
maskAllImages: true,
282+
}),
283+
],
284+
});
285+
```
286+
287+
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/)
288+
289+
### Dependencies
290+
291+
- Bump Cocoa SDK to [8.25.0-alpha.0](https://github.com/getsentry/sentry-cocoa/releases/tag/8.25.0-alpha.0)
292+
- Bump Android SDK to [7.9.0-alpha.1](https://github.com/getsentry/sentry-java/releases/tag/7.9.0-alpha.1)
293+
169294
## 5.22.0
170295

171296
### Features
@@ -444,7 +569,7 @@ see [the Expo guide](https://docs.sentry.io/platforms/react-native/manual-setup/
444569
const { getSentryExpoConfig } = require("@sentry/react-native/metro");
445570

446571
// const config = getDefaultConfig(__dirname);
447-
const config = getSentryExpoConfig(config, {});
572+
const config = getSentryExpoConfig(__dirname);
448573
```
449574

450575
- 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))
@@ -676,7 +801,7 @@ This release is compatible with `[email protected]` and newer.
676801
});
677802
```
678803

679-
Read more at https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md#7690
804+
Read more at <https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md#7690>
680805

681806
- Report current screen in `contexts.app.view_names` ([#3339](https://github.com/getsentry/sentry-react-native/pull/3339))
682807

@@ -2715,7 +2840,7 @@ We are looking into ways making this more stable and plan to re-enable it again
27152840

27162841
## v0.23.2
27172842

2718-
- Fixed #228 again ¯\\_(ツ)_
2843+
- Fixed #228 again ¯\\*(ツ)*
27192844

27202845
## v0.23.1
27212846

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
package io.sentry.rnsentryandroidtester
2+
3+
import io.sentry.Breadcrumb
4+
import io.sentry.SentryLevel
5+
import io.sentry.react.RNSentryReplayBreadcrumbConverter
6+
import io.sentry.rrweb.RRWebBreadcrumbEvent
7+
import io.sentry.rrweb.RRWebEventType
8+
import org.junit.Assert.assertEquals
9+
import org.junit.Test
10+
import org.junit.runner.RunWith
11+
import org.junit.runners.JUnit4
12+
13+
@RunWith(JUnit4::class)
14+
class RNSentryReplayBreadcrumbConverterTest {
15+
16+
@Test
17+
fun convertNavigationBreadcrumb() {
18+
val converter = RNSentryReplayBreadcrumbConverter()
19+
val testBreadcrumb = Breadcrumb()
20+
testBreadcrumb.level = SentryLevel.INFO
21+
testBreadcrumb.type = "navigation"
22+
testBreadcrumb.category = "navigation"
23+
testBreadcrumb.setData("from", "HomeScreen")
24+
testBreadcrumb.setData("to", "ProfileScreen")
25+
val actual = converter.convert(testBreadcrumb) as RRWebBreadcrumbEvent
26+
27+
assertRRWebBreadcrumbDefaults(actual)
28+
assertEquals(SentryLevel.INFO, actual.level)
29+
assertEquals("navigation", actual.category)
30+
assertEquals("HomeScreen", actual.data?.get("from"))
31+
assertEquals("ProfileScreen", actual.data?.get("to"))
32+
}
33+
34+
@Test
35+
fun convertNavigationBreadcrumbWithOnlyTo() {
36+
val converter = RNSentryReplayBreadcrumbConverter()
37+
val testBreadcrumb = Breadcrumb()
38+
testBreadcrumb.level = SentryLevel.INFO
39+
testBreadcrumb.type = "navigation"
40+
testBreadcrumb.category = "navigation"
41+
testBreadcrumb.setData("to", "ProfileScreen")
42+
val actual = converter.convert(testBreadcrumb) as RRWebBreadcrumbEvent
43+
44+
assertRRWebBreadcrumbDefaults(actual)
45+
assertEquals(SentryLevel.INFO, actual.level)
46+
assertEquals("navigation", actual.category)
47+
assertEquals(null, actual.data?.get("from"))
48+
assertEquals("ProfileScreen", actual.data?.get("to"))
49+
}
50+
51+
@Test
52+
fun convertForegroundBreadcrumb() {
53+
val converter = RNSentryReplayBreadcrumbConverter()
54+
val testBreadcrumb = Breadcrumb()
55+
testBreadcrumb.type = "navigation"
56+
testBreadcrumb.category = "app.lifecycle"
57+
testBreadcrumb.setData("state", "foreground");
58+
val actual = converter.convert(testBreadcrumb) as RRWebBreadcrumbEvent
59+
60+
assertRRWebBreadcrumbDefaults(actual)
61+
assertEquals("app.foreground", actual.category)
62+
}
63+
64+
@Test
65+
fun convertBackgroundBreadcrumb() {
66+
val converter = RNSentryReplayBreadcrumbConverter()
67+
val testBreadcrumb = Breadcrumb()
68+
testBreadcrumb.type = "navigation"
69+
testBreadcrumb.category = "app.lifecycle"
70+
testBreadcrumb.setData("state", "background");
71+
val actual = converter.convert(testBreadcrumb) as RRWebBreadcrumbEvent
72+
73+
assertRRWebBreadcrumbDefaults(actual)
74+
assertEquals("app.background", actual.category)
75+
}
76+
77+
@Test
78+
fun doesNotConvertSentryEventBreadcrumb() {
79+
val converter = RNSentryReplayBreadcrumbConverter()
80+
val testBreadcrumb = Breadcrumb();
81+
testBreadcrumb.category = "sentry.event"
82+
val actual = converter.convert(testBreadcrumb)
83+
assertEquals(null, actual)
84+
}
85+
86+
@Test
87+
fun doesNotConvertSentryTransactionBreadcrumb() {
88+
val converter = RNSentryReplayBreadcrumbConverter()
89+
val testBreadcrumb = Breadcrumb();
90+
testBreadcrumb.category = "sentry.transaction"
91+
val actual = converter.convert(testBreadcrumb)
92+
assertEquals(null, actual)
93+
}
94+
95+
@Test
96+
fun convertTouchBreadcrumb() {
97+
val converter = RNSentryReplayBreadcrumbConverter()
98+
val testBreadcrumb = Breadcrumb()
99+
testBreadcrumb.level = SentryLevel.INFO
100+
testBreadcrumb.type = "user"
101+
testBreadcrumb.category = "touch"
102+
testBreadcrumb.message = "this won't be used for replay"
103+
testBreadcrumb.setData(
104+
"path",
105+
arrayListOf(mapOf(
106+
"element" to "element4",
107+
"file" to "file4")))
108+
val actual = converter.convert(testBreadcrumb) as RRWebBreadcrumbEvent
109+
110+
assertRRWebBreadcrumbDefaults(actual)
111+
assertEquals(SentryLevel.INFO, actual.level)
112+
assertEquals("ui.tap", actual.category)
113+
assertEquals(1, actual.data?.keys?.size)
114+
assertEquals(
115+
arrayListOf(mapOf(
116+
"element" to "element4",
117+
"file" to "file4")),
118+
actual.data?.get("path"))
119+
}
120+
121+
@Test
122+
fun doesNotConvertNullPath() {
123+
val actual = RNSentryReplayBreadcrumbConverter.getTouchPathMessage(null)
124+
assertEquals(null, actual)
125+
}
126+
127+
@Test
128+
fun doesNotConvertPathContainingNull() {
129+
val actual = RNSentryReplayBreadcrumbConverter.getTouchPathMessage(arrayListOf(arrayOfNulls<Any>(1)))
130+
assertEquals(null, actual)
131+
}
132+
133+
@Test
134+
fun doesNotConvertPathWithValuesMissingNameAndLevel() {
135+
val actual = RNSentryReplayBreadcrumbConverter.getTouchPathMessage(arrayListOf(mapOf(
136+
"element" to "element4",
137+
"file" to "file4")))
138+
assertEquals(null, actual)
139+
}
140+
141+
@Test
142+
fun doesConvertValidPathExample1() {
143+
val actual = RNSentryReplayBreadcrumbConverter.getTouchPathMessage(listOf(
144+
mapOf("label" to "label0"),
145+
mapOf("name" to "name1"),
146+
mapOf("name" to "item2", "label" to "label2"),
147+
mapOf("name" to "item3", "label" to "label3", "element" to "element3"),
148+
mapOf("name" to "item4", "label" to "label4", "file" to "file4"),
149+
mapOf("name" to "item5", "label" to "label5", "element" to "element5", "file" to "file5")))
150+
assertEquals("label3(element3) > label2 > name1 > label0", actual)
151+
}
152+
153+
@Test
154+
fun doesConvertValidPathExample2() {
155+
val actual = RNSentryReplayBreadcrumbConverter.getTouchPathMessage(listOf(
156+
mapOf("name" to "item2", "label" to "label2"),
157+
mapOf("name" to "item3", "label" to "label3", "element" to "element3"),
158+
mapOf("name" to "item4", "label" to "label4", "file" to "file4"),
159+
mapOf("name" to "item5", "label" to "label5", "element" to "element5", "file" to "file5"),
160+
mapOf("label" to "label6"),
161+
mapOf("name" to "name7")))
162+
assertEquals("label5(element5, file5) > label4(file4) > label3(element3) > label2", actual)
163+
}
164+
165+
private fun assertRRWebBreadcrumbDefaults(actual: RRWebBreadcrumbEvent) {
166+
assertEquals("default", actual.breadcrumbType)
167+
assertEquals(actual.breadcrumbTimestamp * 1000, actual.timestamp.toDouble(), 0.05)
168+
assert(actual.breadcrumbTimestamp > 0)
169+
}
170+
}

0 commit comments

Comments
 (0)