From 39932dbdf61b3a656e1db61b0955255fed6ee32c Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Wed, 5 Jun 2024 09:04:31 +0000 Subject: [PATCH 01/23] release: 5.23.0 --- CHANGELOG.md | 2 +- package.json | 2 +- samples/expo/app.json | 6 +++--- samples/expo/package.json | 2 +- samples/react-native/android/app/build.gradle | 4 ++-- samples/react-native/ios/sentryreactnativesample/Info.plist | 4 ++-- .../ios/sentryreactnativesampleTests/Info.plist | 4 ++-- samples/react-native/package.json | 2 +- src/js/version.ts | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46fdba2f08..af52f13b78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## Unreleased +## 5.23.0 ### Features diff --git a/package.json b/package.json index 342dd154a6..9b057f79fa 100644 --- a/package.json +++ b/package.json @@ -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.3", + "version": "5.23.0", "description": "Official Sentry SDK for react-native", "typings": "dist/js/index.d.ts", "types": "dist/js/index.d.ts", diff --git a/samples/expo/app.json b/samples/expo/app.json index 07dc6e2483..1548874a6d 100644 --- a/samples/expo/app.json +++ b/samples/expo/app.json @@ -4,7 +4,7 @@ "slug": "sentry-react-native-expo-sample", "jsEngine": "hermes", "scheme": "sentry-expo-sample", - "version": "5.22.3", + "version": "5.23.0", "orientation": "portrait", "icon": "./assets/icon.png", "userInterfaceStyle": "light", @@ -19,7 +19,7 @@ "ios": { "supportsTablet": true, "bundleIdentifier": "io.sentry.expo.sample", - "buildNumber": "7" + "buildNumber": "8" }, "android": { "adaptiveIcon": { @@ -27,7 +27,7 @@ "backgroundColor": "#ffffff" }, "package": "io.sentry.expo.sample", - "versionCode": 7 + "versionCode": 8 }, "web": { "bundler": "metro", diff --git a/samples/expo/package.json b/samples/expo/package.json index e3b94ee609..031dfa95f7 100644 --- a/samples/expo/package.json +++ b/samples/expo/package.json @@ -1,6 +1,6 @@ { "name": "sentry-react-native-expo-sample", - "version": "5.22.3", + "version": "5.23.0", "main": "expo-router/entry", "scripts": { "start": "expo start", diff --git a/samples/react-native/android/app/build.gradle b/samples/react-native/android/app/build.gradle index e808e3ced1..5a36e277dd 100644 --- a/samples/react-native/android/app/build.gradle +++ b/samples/react-native/android/app/build.gradle @@ -134,8 +134,8 @@ android { applicationId "io.sentry.reactnative.sample" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 14 - versionName "5.22.3" + versionCode 15 + versionName "5.23.0" } signingConfigs { diff --git a/samples/react-native/ios/sentryreactnativesample/Info.plist b/samples/react-native/ios/sentryreactnativesample/Info.plist index 3e6dc74cb1..ac21923349 100644 --- a/samples/react-native/ios/sentryreactnativesample/Info.plist +++ b/samples/react-native/ios/sentryreactnativesample/Info.plist @@ -17,11 +17,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 5.22.3 + 5.23.0 CFBundleSignature ???? CFBundleVersion - 14 + 15 LSRequiresIPhoneOS NSAppTransportSecurity diff --git a/samples/react-native/ios/sentryreactnativesampleTests/Info.plist b/samples/react-native/ios/sentryreactnativesampleTests/Info.plist index 44fa0a4a8e..6dbb1c42ad 100644 --- a/samples/react-native/ios/sentryreactnativesampleTests/Info.plist +++ b/samples/react-native/ios/sentryreactnativesampleTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 5.22.3 + 5.23.0 CFBundleSignature ???? CFBundleVersion - 14 + 15 diff --git a/samples/react-native/package.json b/samples/react-native/package.json index e20ea4942f..a09243a575 100644 --- a/samples/react-native/package.json +++ b/samples/react-native/package.json @@ -1,6 +1,6 @@ { "name": "sentry-react-native-sample", - "version": "5.22.3", + "version": "5.23.0", "private": true, "scripts": { "postinstall": "patch-package", diff --git a/src/js/version.ts b/src/js/version.ts index c8616d8b0a..f65f3d86e7 100644 --- a/src/js/version.ts +++ b/src/js/version.ts @@ -1,3 +1,3 @@ export const SDK_PACKAGE_NAME = 'npm:@sentry/react-native'; export const SDK_NAME = 'sentry.javascript.react-native'; -export const SDK_VERSION = '5.22.3'; +export const SDK_VERSION = '5.23.0'; From 0019f64e4d91eddd0c5c8cdc369778caecc4815c Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Wed, 5 Jun 2024 13:55:02 +0200 Subject: [PATCH 02/23] ref(ios): Move breadcrumbs conversion to pure obj-c to ensure compatibility with the swift implementation (#3854) --- .../project.pbxproj | 6 +++ .../RNSentryBreadcrumbTests.m | 40 +++++++++++++++++++ ios/RNSentry.mm | 28 +------------ ios/RNSentryBreadcrumb.h | 9 +++++ ios/RNSentryBreadcrumb.m | 33 +++++++++++++++ 5 files changed, 90 insertions(+), 26 deletions(-) create mode 100644 RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryBreadcrumbTests.m create mode 100644 ios/RNSentryBreadcrumb.h create mode 100644 ios/RNSentryBreadcrumb.m diff --git a/RNSentryCocoaTester/RNSentryCocoaTester.xcodeproj/project.pbxproj b/RNSentryCocoaTester/RNSentryCocoaTester.xcodeproj/project.pbxproj index dc1b56e0b3..a5f58926c2 100644 --- a/RNSentryCocoaTester/RNSentryCocoaTester.xcodeproj/project.pbxproj +++ b/RNSentryCocoaTester/RNSentryCocoaTester.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 330F308C2C0F3840002A0D4E /* RNSentryBreadcrumbTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 330F308B2C0F3840002A0D4E /* RNSentryBreadcrumbTests.m */; }; 33958C692BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33958C682BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m */; }; 33AFDFED2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33AFDFEC2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m */; }; 33AFDFF12B8D15E500AAB120 /* RNSentryDependencyContainerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33AFDFF02B8D15E500AAB120 /* RNSentryDependencyContainerTests.m */; }; @@ -16,6 +17,8 @@ /* Begin PBXFileReference section */ 1482D5685A340AB93348A43D /* Pods-RNSentryCocoaTesterTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNSentryCocoaTesterTests.release.xcconfig"; path = "Target Support Files/Pods-RNSentryCocoaTesterTests/Pods-RNSentryCocoaTesterTests.release.xcconfig"; sourceTree = ""; }; + 330F308B2C0F3840002A0D4E /* RNSentryBreadcrumbTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNSentryBreadcrumbTests.m; sourceTree = ""; }; + 330F308D2C0F385A002A0D4E /* RNSentryBreadcrumb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSentryBreadcrumb.h; path = ../ios/RNSentryBreadcrumb.h; sourceTree = ""; }; 3360898D29524164007C7730 /* RNSentryCocoaTesterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RNSentryCocoaTesterTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 338739072A7D7D2800950DDD /* RNSentryTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNSentryTests.h; sourceTree = ""; }; 33958C672BFCEF5A00AD1FB6 /* RNSentryOnDrawReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSentryOnDrawReporter.h; path = ../ios/RNSentryOnDrawReporter.h; sourceTree = ""; }; @@ -80,6 +83,7 @@ 33AFDFF02B8D15E500AAB120 /* RNSentryDependencyContainerTests.m */, 33AFDFF22B8D15F600AAB120 /* RNSentryDependencyContainerTests.h */, 33958C682BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m */, + 330F308B2C0F3840002A0D4E /* RNSentryBreadcrumbTests.m */, ); path = RNSentryCocoaTesterTests; sourceTree = ""; @@ -87,6 +91,7 @@ 33AFE0122B8F319000AAB120 /* RNSentry */ = { isa = PBXGroup; children = ( + 330F308D2C0F385A002A0D4E /* RNSentryBreadcrumb.h */, 33958C672BFCEF5A00AD1FB6 /* RNSentryOnDrawReporter.h */, 33AFE0132B8F31AF00AAB120 /* RNSentryDependencyContainer.h */, ); @@ -204,6 +209,7 @@ 33AFDFF12B8D15E500AAB120 /* RNSentryDependencyContainerTests.m in Sources */, 33F58AD02977037D008F60EA /* RNSentryTests.mm in Sources */, 33958C692BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m in Sources */, + 330F308C2C0F3840002A0D4E /* RNSentryBreadcrumbTests.m in Sources */, 33AFDFED2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryBreadcrumbTests.m b/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryBreadcrumbTests.m new file mode 100644 index 0000000000..f9609f06eb --- /dev/null +++ b/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryBreadcrumbTests.m @@ -0,0 +1,40 @@ +#import +#import "RNSentryBreadcrumb.h" +@import Sentry; + +@interface RNSentryBreadcrumbTests : XCTestCase + +@end + +@implementation RNSentryBreadcrumbTests + +- (void)testGeneratesSentryBreadcrumbFromNSDictionary +{ + SentryBreadcrumb* actualCrumb = [RNSentryBreadcrumb from:@{ + @"level": @"error", + @"category": @"testCategory", + @"type": @"testType", + @"message": @"testMessage", + @"data": @{ + @"test": @"data" + } + }]; + + XCTAssertEqual(actualCrumb.level, kSentryLevelError); + XCTAssertEqual(actualCrumb.category, @"testCategory"); + XCTAssertEqual(actualCrumb.type, @"testType"); + XCTAssertEqual(actualCrumb.message, @"testMessage"); + XCTAssertTrue([actualCrumb.data isKindOfClass:[NSDictionary class]]); + XCTAssertEqual(actualCrumb.data[@"test"], @"data"); +} + +- (void)testUsesInfoAsDefaultSentryLevel +{ + SentryBreadcrumb* actualCrumb = [RNSentryBreadcrumb from:@{ + @"message": @"testMessage", + }]; + + XCTAssertEqual(actualCrumb.level, kSentryLevelInfo); +} + +@end diff --git a/ios/RNSentry.mm b/ios/RNSentry.mm index 0e122e1e66..6c0b91b60f 100644 --- a/ios/RNSentry.mm +++ b/ios/RNSentry.mm @@ -23,6 +23,7 @@ #import #import #import "RNSentryId.h" +#import "RNSentryBreadcrumb.h" // This guard prevents importing Hermes in JSC apps #if SENTRY_PROFILING_ENABLED @@ -557,32 +558,7 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray*)instructionsAdd RCT_EXPORT_METHOD(addBreadcrumb:(NSDictionary *)breadcrumb) { [SentrySDK configureScope:^(SentryScope * _Nonnull scope) { - SentryBreadcrumb* breadcrumbInstance = [[SentryBreadcrumb alloc] init]; - - NSString * levelString = breadcrumb[@"level"]; - SentryLevel sentryLevel; - if ([levelString isEqualToString:@"fatal"]) { - sentryLevel = kSentryLevelFatal; - } else if ([levelString isEqualToString:@"warning"]) { - sentryLevel = kSentryLevelWarning; - } else if ([levelString isEqualToString:@"error"]) { - sentryLevel = kSentryLevelError; - } else if ([levelString isEqualToString:@"debug"]) { - sentryLevel = kSentryLevelDebug; - } else { - sentryLevel = kSentryLevelInfo; - } - [breadcrumbInstance setLevel:sentryLevel]; - - [breadcrumbInstance setCategory:breadcrumb[@"category"]]; - - [breadcrumbInstance setType:breadcrumb[@"type"]]; - - [breadcrumbInstance setMessage:breadcrumb[@"message"]]; - - [breadcrumbInstance setData:breadcrumb[@"data"]]; - - [scope addBreadcrumb:breadcrumbInstance]; + [scope addBreadcrumb:[RNSentryBreadcrumb from:breadcrumb]]; }]; } diff --git a/ios/RNSentryBreadcrumb.h b/ios/RNSentryBreadcrumb.h new file mode 100644 index 0000000000..35e5501ae1 --- /dev/null +++ b/ios/RNSentryBreadcrumb.h @@ -0,0 +1,9 @@ +#import + +@class SentryBreadcrumb; + +@interface RNSentryBreadcrumb : NSObject + ++ (SentryBreadcrumb *)from: (NSDictionary *) dict; + +@end diff --git a/ios/RNSentryBreadcrumb.m b/ios/RNSentryBreadcrumb.m new file mode 100644 index 0000000000..928033e99c --- /dev/null +++ b/ios/RNSentryBreadcrumb.m @@ -0,0 +1,33 @@ +#import "RNSentryBreadcrumb.h" +@import Sentry; + +@implementation RNSentryBreadcrumb + ++(SentryBreadcrumb*) from: (NSDictionary *) dict +{ + SentryBreadcrumb* crumb = [[SentryBreadcrumb alloc] init]; + + NSString * levelString = dict[@"level"]; + SentryLevel sentryLevel; + if ([levelString isEqualToString:@"fatal"]) { + sentryLevel = kSentryLevelFatal; + } else if ([levelString isEqualToString:@"warning"]) { + sentryLevel = kSentryLevelWarning; + } else if ([levelString isEqualToString:@"error"]) { + sentryLevel = kSentryLevelError; + } else if ([levelString isEqualToString:@"debug"]) { + sentryLevel = kSentryLevelDebug; + } else { + sentryLevel = kSentryLevelInfo; + } + + [crumb setLevel:sentryLevel]; + [crumb setCategory:dict[@"category"]]; + [crumb setType:dict[@"type"]]; + [crumb setMessage:dict[@"message"]]; + [crumb setData:dict[@"data"]]; + + return crumb; +} + +@end From aefb75bc5972fbcfcc0c12983d61f2bf096aa225 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Thu, 6 Jun 2024 14:51:05 +0200 Subject: [PATCH 03/23] fix(logs): Add missing App Start logs when the span is dropped (#3861) --- CHANGELOG.md | 6 ++++++ src/js/tracing/reactnativetracing.ts | 12 ++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af52f13b78..cf78e56d87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fix + +- Add missing logs to dropped App Start spans ([#3861](https://github.com/getsentry/sentry-react-native/pull/3861)) + ## 5.23.0 ### Features diff --git a/src/js/tracing/reactnativetracing.ts b/src/js/tracing/reactnativetracing.ts index 397cc1ee50..a85f26cd3a 100644 --- a/src/js/tracing/reactnativetracing.ts +++ b/src/js/tracing/reactnativetracing.ts @@ -422,11 +422,18 @@ export class ReactNativeTracing implements Integration { const appStart = await NATIVE.fetchNativeAppStart(); - if (!appStart || appStart.didFetchAppStart) { + if (!appStart) { + logger.warn('[ReactNativeTracing] Not instrumenting App Start because native returned null.'); + return; + } + + if (appStart.didFetchAppStart) { + logger.warn('[ReactNativeTracing] Not instrumenting App Start because this start was already reported.'); return; } if (!this.useAppStartWithProfiler) { + logger.warn('[ReactNativeTracing] `Sentry.wrap` not detected, using JS context init as app start end.'); this._appStartFinishTimestamp = getTimeOriginMilliseconds() / 1000; } @@ -450,7 +457,7 @@ export class ReactNativeTracing implements Integration { private _addAppStartData(transaction: IdleTransaction, appStart: NativeAppStartResponse): void { const appStartDurationMilliseconds = this._getAppStartDurationMilliseconds(appStart); if (!appStartDurationMilliseconds) { - logger.warn('App start was never finished.'); + logger.warn('[ReactNativeTracing] App start end has not been recorded, not adding app start span.'); return; } @@ -458,6 +465,7 @@ export class ReactNativeTracing implements Integration { // this could be due to many different reasons. // we've seen app starts with hours, days and even months. if (appStartDurationMilliseconds >= ReactNativeTracing._maxAppStart) { + logger.warn('[ReactNativeTracing] App start duration is over a minute long, not adding app start span.'); return; } From 6a87eded808590c9e92c48f5da28fba8db71cabb Mon Sep 17 00:00:00 2001 From: Ivan Dlugos <6349682+vaind@users.noreply.github.com> Date: Thu, 6 Jun 2024 17:46:52 +0200 Subject: [PATCH 04/23] ci(ios): allow larger app size diff (up to 1 MiB) (#3864) --- test/perf/metrics-ios.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/perf/metrics-ios.yml b/test/perf/metrics-ios.yml index 7b515c263b..1f745c5825 100644 --- a/test/perf/metrics-ios.yml +++ b/test/perf/metrics-ios.yml @@ -10,5 +10,5 @@ startupTimeTest: diffMax: 150 binarySizeTest: - diffMin: 200 KiB - diffMax: 600 KiB + diffMin: 600 KiB + diffMax: 1000 KiB From 0601fb82e04ce67525c54829bab1b4c62e8dfb9a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 21:15:32 -0300 Subject: [PATCH 05/23] chore: update scripts/update-cocoa.sh to 8.28.0 (#3866) Co-authored-by: GitHub --- CHANGELOG.md | 6 ++++++ RNSentry.podspec | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf78e56d87..569d084ee4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ - Add missing logs to dropped App Start spans ([#3861](https://github.com/getsentry/sentry-react-native/pull/3861)) +### Dependencies + +- Bump Cocoa SDK from v8.27.0 to v8.28.0 ([#3866](https://github.com/getsentry/sentry-react-native/pull/3866)) + - [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8280) + - [diff](https://github.com/getsentry/sentry-cocoa/compare/8.27.0...8.28.0) + ## 5.23.0 ### Features diff --git a/RNSentry.podspec b/RNSentry.podspec index 393a8f6171..fc7c319313 100644 --- a/RNSentry.podspec +++ b/RNSentry.podspec @@ -33,7 +33,7 @@ Pod::Spec.new do |s| s.preserve_paths = '*.js' s.dependency 'React-Core' - s.dependency 'Sentry/HybridSDK', '8.27.0' + s.dependency 'Sentry/HybridSDK', '8.28.0' s.source_files = 'ios/**/*.{h,m,mm}' s.public_header_files = 'ios/RNSentry.h' From 837def06552d4f5a9c1d7a7a3325e2a2a2f06e20 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 7 Jun 2024 10:20:45 +0200 Subject: [PATCH 06/23] chore(deps): update Android SDK to v7.9.0 (#3805) Co-authored-by: GitHub --- CHANGELOG.md | 3 +++ android/build.gradle | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 569d084ee4..56140f77ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ - Bump Cocoa SDK from v8.27.0 to v8.28.0 ([#3866](https://github.com/getsentry/sentry-react-native/pull/3866)) - [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8280) - [diff](https://github.com/getsentry/sentry-cocoa/compare/8.27.0...8.28.0) +- Bump Android SDK from v7.8.0 to v7.10.0 ([#3805](https://github.com/getsentry/sentry-react-native/pull/3805)) + - [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#7100) + - [diff](https://github.com/getsentry/sentry-java/compare/7.8.0...7.10.0) ## 5.23.0 diff --git a/android/build.gradle b/android/build.gradle index 704f34f91c..b89eb7750d 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -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.10.0' } From 229ffc0140684430d4a66c9a2372e0c2ba642744 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Fri, 7 Jun 2024 11:17:25 +0200 Subject: [PATCH 07/23] fix(ttd): Add span ids to time to display debug logs (#3868) --- CHANGELOG.md | 1 + src/js/tracing/timetodisplay.tsx | 14 ++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56140f77ff..97dc213651 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Fix - Add missing logs to dropped App Start spans ([#3861](https://github.com/getsentry/sentry-react-native/pull/3861)) +- Add Span IDs to Time to Display debug logs ([#3868](https://github.com/getsentry/sentry-react-native/pull/3868)) ### Dependencies diff --git a/src/js/tracing/timetodisplay.tsx b/src/js/tracing/timetodisplay.tsx index 75fc92bedd..3f4d1a4134 100644 --- a/src/js/tracing/timetodisplay.tsx +++ b/src/js/tracing/timetodisplay.tsx @@ -224,6 +224,7 @@ function updateInitialDisplaySpan(frameTimestampSeconds: number): void { if (fullDisplayBeforeInitialDisplay.has(activeSpan)) { fullDisplayBeforeInitialDisplay.delete(activeSpan); + logger.debug(`[TimeToDisplay] Updating full display with initial display (${span.spanContext().spanId}) end.`); updateFullDisplaySpan(frameTimestampSeconds, span); } @@ -233,7 +234,7 @@ function updateInitialDisplaySpan(frameTimestampSeconds: number): void { function updateFullDisplaySpan(frameTimestampSeconds: number, passedInitialDisplaySpan?: Span): void { const activeSpan = getActiveSpan(); if (!activeSpan) { - logger.warn(`[TimeToDisplay] No active span found to attach ui.load.full_display to.`); + logger.warn(`[TimeToDisplay] No active span found to update ui.load.full_display in.`); return; } @@ -247,25 +248,26 @@ function updateFullDisplaySpan(frameTimestampSeconds: number, passedInitialDispl const initialDisplayEndTimestamp = existingInitialDisplaySpan && spanToJSON(existingInitialDisplaySpan).timestamp; if (!initialDisplayEndTimestamp) { fullDisplayBeforeInitialDisplay.set(activeSpan, true); - logger.warn(`[TimeToDisplay] Full display called before initial display for active span.`); + logger.warn(`[TimeToDisplay] Full display called before initial display for active span (${activeSpan.spanContext().spanId}).`); return; } const span = startTimeToFullDisplaySpan(); if (!span) { - logger.warn(`[TimeToDisplay] No span found or created, possibly performance is disabled.`); + logger.warn(`[TimeToDisplay] No TimeToFullDisplay span found or created, possibly performance is disabled.`); return; } - if (spanToJSON(span).timestamp) { - logger.warn(`[TimeToDisplay] ${spanToJSON(span).description} span already ended.`); + const spanJSON = spanToJSON(span); + if (spanJSON.timestamp) { + logger.warn(`[TimeToDisplay] ${spanJSON.description} (${spanJSON.span_id}) span already ended.`); return; } span.end(frameTimestampSeconds); span.setStatus('ok'); - logger.debug(`[TimeToDisplay] ${spanToJSON(span).description} span updated with end timestamp.`); + logger.debug(`[TimeToDisplay] ${spanJSON.description} (${spanJSON.span_id}) span updated with end timestamp.`); setSpanDurationAsMeasurement('time_to_full_display', span); } From 10d066c02a38ca7db07a127bbe04277809179535 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Fri, 7 Jun 2024 12:20:58 +0200 Subject: [PATCH 08/23] fix(ttd): Make all options of startTTID optional (#3867) --- CHANGELOG.md | 1 + src/js/tracing/timetodisplay.tsx | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97dc213651..e0b25d27b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Fix - Add missing logs to dropped App Start spans ([#3861](https://github.com/getsentry/sentry-react-native/pull/3861)) +- Make all options of `startTimeToInitialDisplaySpan` optional ([#3867](https://github.com/getsentry/sentry-react-native/pull/3867)) - Add Span IDs to Time to Display debug logs ([#3868](https://github.com/getsentry/sentry-react-native/pull/3868)) ### Dependencies diff --git a/src/js/tracing/timetodisplay.tsx b/src/js/tracing/timetodisplay.tsx index 3f4d1a4134..b57f0dd6fa 100644 --- a/src/js/tracing/timetodisplay.tsx +++ b/src/js/tracing/timetodisplay.tsx @@ -86,7 +86,10 @@ function TimeToDisplay(props: { * Returns current span if already exists in the currently active span. */ export function startTimeToInitialDisplaySpan( - options?: Exclude & { name?: string; isAutoInstrumented?: boolean }, + options?: Omit & { + name?: string; + isAutoInstrumented?: boolean + }, ): Span | undefined { const activeSpan = getActiveSpan(); if (!activeSpan) { From 04e24441d2db827a382ff64fd82ac615c210c9c6 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Fri, 7 Jun 2024 12:31:38 +0200 Subject: [PATCH 09/23] fix(ttfd): Use TTID end timestamp when TTFD should be updated with an earlier timestamp (#3869) --- CHANGELOG.md | 1 + src/js/tracing/timetodisplay.tsx | 7 +++++- test/tracing/timetodisplay.test.tsx | 36 +++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0b25d27b9..e6802263ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Add missing logs to dropped App Start spans ([#3861](https://github.com/getsentry/sentry-react-native/pull/3861)) - Make all options of `startTimeToInitialDisplaySpan` optional ([#3867](https://github.com/getsentry/sentry-react-native/pull/3867)) - Add Span IDs to Time to Display debug logs ([#3868](https://github.com/getsentry/sentry-react-native/pull/3868)) +- Use TTID end timestamp when TTFD should be updated with an earlier timestamp ([#3869](https://github.com/getsentry/sentry-react-native/pull/3869)) ### Dependencies diff --git a/src/js/tracing/timetodisplay.tsx b/src/js/tracing/timetodisplay.tsx index b57f0dd6fa..972374d94c 100644 --- a/src/js/tracing/timetodisplay.tsx +++ b/src/js/tracing/timetodisplay.tsx @@ -267,7 +267,12 @@ function updateFullDisplaySpan(frameTimestampSeconds: number, passedInitialDispl return; } - span.end(frameTimestampSeconds); + if (initialDisplayEndTimestamp > frameTimestampSeconds) { + logger.warn(`[TimeToDisplay] Using initial display end. Full display end frame timestamp is before initial display end.`); + span.end(initialDisplayEndTimestamp); + } else { + span.end(frameTimestampSeconds); + } span.setStatus('ok'); logger.debug(`[TimeToDisplay] ${spanJSON.description} (${spanJSON.span_id}) span updated with end timestamp.`); diff --git a/test/tracing/timetodisplay.test.tsx b/test/tracing/timetodisplay.test.tsx index 42db2c115b..9abe22bed4 100644 --- a/test/tracing/timetodisplay.test.tsx +++ b/test/tracing/timetodisplay.test.tsx @@ -241,6 +241,42 @@ describe('TimeToDisplay', () => { expect(spanToJSON(fullDisplaySpan!).timestamp).toEqual(initialDisplayEndTimestampMs / 1_000); }); + test('full display which ended before but processed after initial display is extended to initial display end', async () => { + const fullDisplayEndTimestampMs = secondInFutureTimestampMs(); + const initialDisplayEndTimestampMs = secondInFutureTimestampMs() + 500; + const [initialDisplaySpan, fullDisplaySpan, activeSpan] = startSpanManual( + { + name: 'Root Manual Span', + startTime: secondAgoTimestampMs(), + }, + (activeSpan: Span | undefined) => { + const initialDisplaySpan = startTimeToInitialDisplaySpan(); + const fullDisplaySpan = startTimeToFullDisplaySpan(); + + const timeToDisplayComponent = TestRenderer.create(<>); + timeToDisplayComponent.update(<>); + + emitNativeInitialDisplayEvent(initialDisplayEndTimestampMs); + emitNativeFullDisplayEvent(fullDisplayEndTimestampMs); + + activeSpan?.end(); + return [initialDisplaySpan, fullDisplaySpan, activeSpan]; + }, + ); + + await jest.runOnlyPendingTimersAsync(); + await client.flush(); + + expectFinishedInitialDisplaySpan(initialDisplaySpan, activeSpan); + expectFinishedFullDisplaySpan(fullDisplaySpan, activeSpan); + + expectInitialDisplayMeasurementOnSpan(client.event!); + expectFullDisplayMeasurementOnSpan(client.event!); + + expect(spanToJSON(initialDisplaySpan!).timestamp).toEqual(initialDisplayEndTimestampMs / 1_000); + expect(spanToJSON(fullDisplaySpan!).timestamp).toEqual(initialDisplayEndTimestampMs / 1_000); + }); + test('consequent renders do not update display end', async () => { const initialDisplayEndTimestampMs = secondInFutureTimestampMs(); const fullDisplayEndTimestampMs = secondInFutureTimestampMs() + 500; From 1b137924e4399d5aee7fc5ed1e6b14bc6c525dba Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Fri, 7 Jun 2024 12:51:21 +0200 Subject: [PATCH 10/23] fix(changelog): Add entry for missing SentryLevel fix on iOS (#3872) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6802263ab..fff0286712 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Fix +- Fix failing iOS builds due to missing SentryLevel ([#3854](https://github.com/getsentry/sentry-react-native/pull/3854)) - Add missing logs to dropped App Start spans ([#3861](https://github.com/getsentry/sentry-react-native/pull/3861)) - Make all options of `startTimeToInitialDisplaySpan` optional ([#3867](https://github.com/getsentry/sentry-react-native/pull/3867)) - Add Span IDs to Time to Display debug logs ([#3868](https://github.com/getsentry/sentry-react-native/pull/3868)) From 88661972b0629c47a06ad06eaaf60b17723737cc Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Fri, 7 Jun 2024 16:30:44 +0200 Subject: [PATCH 11/23] chore(release): Hotfix v5.23.1 (#3873) --- CHANGELOG.md | 20 +++++++++++-------- package.json | 2 +- samples/expo/app.json | 6 +++--- samples/expo/package.json | 2 +- samples/react-native/android/app/build.gradle | 4 ++-- .../ios/sentryreactnativesample/Info.plist | 4 ++-- .../sentryreactnativesampleTests/Info.plist | 4 ++-- samples/react-native/package.json | 2 +- src/js/version.ts | 2 +- 9 files changed, 25 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fff0286712..75dadafde4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,14 +2,6 @@ ## Unreleased -### Fix - -- Fix failing iOS builds due to missing SentryLevel ([#3854](https://github.com/getsentry/sentry-react-native/pull/3854)) -- Add missing logs to dropped App Start spans ([#3861](https://github.com/getsentry/sentry-react-native/pull/3861)) -- Make all options of `startTimeToInitialDisplaySpan` optional ([#3867](https://github.com/getsentry/sentry-react-native/pull/3867)) -- Add Span IDs to Time to Display debug logs ([#3868](https://github.com/getsentry/sentry-react-native/pull/3868)) -- Use TTID end timestamp when TTFD should be updated with an earlier timestamp ([#3869](https://github.com/getsentry/sentry-react-native/pull/3869)) - ### Dependencies - Bump Cocoa SDK from v8.27.0 to v8.28.0 ([#3866](https://github.com/getsentry/sentry-react-native/pull/3866)) @@ -19,8 +11,20 @@ - [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#7100) - [diff](https://github.com/getsentry/sentry-java/compare/7.8.0...7.10.0) +## 5.23.1 + +### Fixes + +- Fix failing iOS builds due to missing SentryLevel ([#3854](https://github.com/getsentry/sentry-react-native/pull/3854)) +- Add missing logs to dropped App Start spans ([#3861](https://github.com/getsentry/sentry-react-native/pull/3861)) +- Make all options of `startTimeToInitialDisplaySpan` optional ([#3867](https://github.com/getsentry/sentry-react-native/pull/3867)) +- Add Span IDs to Time to Display debug logs ([#3868](https://github.com/getsentry/sentry-react-native/pull/3868)) +- Use TTID end timestamp when TTFD should be updated with an earlier timestamp ([#3869](https://github.com/getsentry/sentry-react-native/pull/3869)) + ## 5.23.0 +This release does *not* build on iOS. Please use `5.23.1` or newer. + ### Features - Functional integrations ([#3814](https://github.com/getsentry/sentry-react-native/pull/3814)) diff --git a/package.json b/package.json index 9b057f79fa..8cc0f35f78 100644 --- a/package.json +++ b/package.json @@ -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.23.0", + "version": "5.23.1", "description": "Official Sentry SDK for react-native", "typings": "dist/js/index.d.ts", "types": "dist/js/index.d.ts", diff --git a/samples/expo/app.json b/samples/expo/app.json index 1548874a6d..6f1f8dc31e 100644 --- a/samples/expo/app.json +++ b/samples/expo/app.json @@ -4,7 +4,7 @@ "slug": "sentry-react-native-expo-sample", "jsEngine": "hermes", "scheme": "sentry-expo-sample", - "version": "5.23.0", + "version": "5.23.1", "orientation": "portrait", "icon": "./assets/icon.png", "userInterfaceStyle": "light", @@ -19,7 +19,7 @@ "ios": { "supportsTablet": true, "bundleIdentifier": "io.sentry.expo.sample", - "buildNumber": "8" + "buildNumber": "9" }, "android": { "adaptiveIcon": { @@ -27,7 +27,7 @@ "backgroundColor": "#ffffff" }, "package": "io.sentry.expo.sample", - "versionCode": 8 + "versionCode": 9 }, "web": { "bundler": "metro", diff --git a/samples/expo/package.json b/samples/expo/package.json index 031dfa95f7..b6f72a1234 100644 --- a/samples/expo/package.json +++ b/samples/expo/package.json @@ -1,6 +1,6 @@ { "name": "sentry-react-native-expo-sample", - "version": "5.23.0", + "version": "5.23.1", "main": "expo-router/entry", "scripts": { "start": "expo start", diff --git a/samples/react-native/android/app/build.gradle b/samples/react-native/android/app/build.gradle index 5a36e277dd..d44e636d9f 100644 --- a/samples/react-native/android/app/build.gradle +++ b/samples/react-native/android/app/build.gradle @@ -134,8 +134,8 @@ android { applicationId "io.sentry.reactnative.sample" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 15 - versionName "5.23.0" + versionCode 16 + versionName "5.23.1" } signingConfigs { diff --git a/samples/react-native/ios/sentryreactnativesample/Info.plist b/samples/react-native/ios/sentryreactnativesample/Info.plist index ac21923349..e518440c38 100644 --- a/samples/react-native/ios/sentryreactnativesample/Info.plist +++ b/samples/react-native/ios/sentryreactnativesample/Info.plist @@ -17,11 +17,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 5.23.0 + 5.23.1 CFBundleSignature ???? CFBundleVersion - 15 + 16 LSRequiresIPhoneOS NSAppTransportSecurity diff --git a/samples/react-native/ios/sentryreactnativesampleTests/Info.plist b/samples/react-native/ios/sentryreactnativesampleTests/Info.plist index 6dbb1c42ad..c2535824a3 100644 --- a/samples/react-native/ios/sentryreactnativesampleTests/Info.plist +++ b/samples/react-native/ios/sentryreactnativesampleTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 5.23.0 + 5.23.1 CFBundleSignature ???? CFBundleVersion - 15 + 16 diff --git a/samples/react-native/package.json b/samples/react-native/package.json index a09243a575..6138220c4f 100644 --- a/samples/react-native/package.json +++ b/samples/react-native/package.json @@ -1,6 +1,6 @@ { "name": "sentry-react-native-sample", - "version": "5.23.0", + "version": "5.23.1", "private": true, "scripts": { "postinstall": "patch-package", diff --git a/src/js/version.ts b/src/js/version.ts index f65f3d86e7..953fed74ac 100644 --- a/src/js/version.ts +++ b/src/js/version.ts @@ -1,3 +1,3 @@ export const SDK_PACKAGE_NAME = 'npm:@sentry/react-native'; export const SDK_NAME = 'sentry.javascript.react-native'; -export const SDK_VERSION = '5.23.0'; +export const SDK_VERSION = '5.23.1'; From 08840767b4a065389465ab6796c9e66b9911203f Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Mon, 10 Jun 2024 14:06:22 +0200 Subject: [PATCH 12/23] feat(tracing): Add native application start spans (#3855) --- CHANGELOG.md | 5 ++ .../io/sentry/react/RNSentryModuleImpl.java | 25 ++---- ios/RNSentry.mm | 24 +++-- src/js/NativeRNSentry.ts | 11 ++- src/js/tracing/reactnativetracing.ts | 40 +++++++-- test/tracing/reactnativetracing.test.ts | 89 +++++++++++++++---- test/tracing/reactnavigation.ttid.test.tsx | 7 +- 7 files changed, 139 insertions(+), 62 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75dadafde4..8dd19d92e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## Unreleased +### Features + +- Add native application start spans ([#3855](https://github.com/getsentry/sentry-react-native/pull/3855)) + - This doesn't change the app start measurement length, but add child spans (more detail) into the existing app start span + ### Dependencies - Bump Cocoa SDK from v8.27.0 to v8.28.0 ([#3866](https://github.com/getsentry/sentry-react-native/pull/3866)) diff --git a/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java b/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java index 4c69337e2b..9b9195d4dd 100644 --- a/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java +++ b/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java @@ -103,7 +103,7 @@ public class RNSentryModuleImpl { private FrameMetricsAggregator frameMetricsAggregator = null; private boolean androidXAvailable; - private static boolean didFetchAppStart; + private static boolean hasFetchedAppStart; // 700ms to constitute frozen frames. private static final int FROZEN_FRAME_THRESHOLD = 700; @@ -334,28 +334,17 @@ public void fetchNativeRelease(Promise promise) { } public void fetchNativeAppStart(Promise promise) { - final AppStartMetrics appStartInstance = AppStartMetrics.getInstance(); - final SentryDate appStartTime = appStartInstance.getAppStartTimeSpan().getStartTimestamp(); - final boolean isColdStart = appStartInstance.getAppStartType() == AppStartMetrics.AppStartType.COLD; + final Map measurement = InternalSentrySdk.getAppStartMeasurement(); - if (appStartTime == null) { - logger.log(SentryLevel.WARNING, "App start won't be sent due to missing appStartTime."); - promise.resolve(null); - } else { - final double appStartTimestampMs = DateUtils.nanosToMillis(appStartTime.nanoTimestamp()); - - WritableMap appStart = Arguments.createMap(); + WritableMap mutableMeasurement = (WritableMap) RNSentryMapConverter.convertToWritable(measurement); + mutableMeasurement.putBoolean("has_fetched", hasFetchedAppStart); - appStart.putDouble("appStartTime", appStartTimestampMs); - appStart.putBoolean("isColdStart", isColdStart); - appStart.putBoolean("didFetchAppStart", didFetchAppStart); - - promise.resolve(appStart); - } // This is always set to true, as we would only allow an app start fetch to only // happen once in the case of a JS bundle reload, we do not want it to be // instrumented again. - didFetchAppStart = true; + hasFetchedAppStart = true; + + promise.resolve(mutableMeasurement); } /** diff --git a/ios/RNSentry.mm b/ios/RNSentry.mm index 6c0b91b60f..1ae62f71e8 100644 --- a/ios/RNSentry.mm +++ b/ios/RNSentry.mm @@ -55,7 +55,7 @@ + (void)storeEnvelope:(SentryEnvelope *)envelope; @end -static bool didFetchAppStart; +static bool hasFetchedAppStart; static NSString* const nativeSdkName = @"sentry.cocoa.react-native"; @@ -380,24 +380,20 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray*)instructionsAdd rejecter:(RCTPromiseRejectBlock)reject) { #if SENTRY_HAS_UIKIT - SentryAppStartMeasurement *appStartMeasurement = PrivateSentrySDKOnly.appStartMeasurement; - - if (appStartMeasurement == nil) { + NSDictionary *measurements = [PrivateSentrySDKOnly appStartMeasurementWithSpans]; + if (measurements == nil) { resolve(nil); - } else { - BOOL isColdStart = appStartMeasurement.type == SentryAppStartTypeCold; - - resolve(@{ - @"isColdStart": [NSNumber numberWithBool:isColdStart], - @"appStartTime": [NSNumber numberWithDouble:(appStartMeasurement.appStartTimestamp.timeIntervalSince1970 * 1000)], - @"didFetchAppStart": [NSNumber numberWithBool:didFetchAppStart], - }); - + return; } + NSMutableDictionary *mutableMeasurements = [[NSMutableDictionary alloc] initWithDictionary:measurements]; + [mutableMeasurements setValue:[NSNumber numberWithBool:hasFetchedAppStart] forKey:@"has_fetched"]; + // This is always set to true, as we would only allow an app start fetch to only happen once // in the case of a JS bundle reload, we do not want it to be instrumented again. - didFetchAppStart = true; + hasFetchedAppStart = true; + + resolve(mutableMeasurements); #else resolve(nil); #endif diff --git a/src/js/NativeRNSentry.ts b/src/js/NativeRNSentry.ts index b76ce28485..3af21faae6 100644 --- a/src/js/NativeRNSentry.ts +++ b/src/js/NativeRNSentry.ts @@ -90,9 +90,14 @@ export type NativeStackFrames = { }; export type NativeAppStartResponse = { - isColdStart: boolean; - appStartTime: number; - didFetchAppStart: boolean; + type: 'cold' | 'warm' | 'unknown'; + has_fetched: boolean; + app_start_timestamp_ms?: number; + spans: { + description: string; + start_timestamp_ms: number; + end_timestamp_ms: number; + }[]; }; export type NativeFramesResponse = { diff --git a/src/js/tracing/reactnativetracing.ts b/src/js/tracing/reactnativetracing.ts index a85f26cd3a..a242ab3492 100644 --- a/src/js/tracing/reactnativetracing.ts +++ b/src/js/tracing/reactnativetracing.ts @@ -7,6 +7,7 @@ import type { Event, EventProcessor, Integration, + Span, Transaction as TransactionType, TransactionContext, } from '@sentry/types'; @@ -404,11 +405,11 @@ export class ReactNativeTracing implements Integration { * Returns the App Start Duration in Milliseconds. Also returns undefined if not able do * define the duration. */ - private _getAppStartDurationMilliseconds(appStart: NativeAppStartResponse): number | undefined { + private _getAppStartDurationMilliseconds(appStartTimestampMs: number): number | undefined { if (!this._appStartFinishTimestamp) { return undefined; } - return this._appStartFinishTimestamp * 1000 - appStart.appStartTime; + return this._appStartFinishTimestamp * 1000 - appStartTimestampMs; } /** @@ -427,7 +428,7 @@ export class ReactNativeTracing implements Integration { return; } - if (appStart.didFetchAppStart) { + if (appStart.has_fetched) { logger.warn('[ReactNativeTracing] Not instrumenting App Start because this start was already reported.'); return; } @@ -455,7 +456,13 @@ export class ReactNativeTracing implements Integration { * Adds app start measurements and starts a child span on a transaction. */ private _addAppStartData(transaction: IdleTransaction, appStart: NativeAppStartResponse): void { - const appStartDurationMilliseconds = this._getAppStartDurationMilliseconds(appStart); + const appStartTimestampMs = appStart.app_start_timestamp_ms; + if (!appStartTimestampMs) { + logger.warn('App start timestamp could not be loaded from the native layer.'); + return; + } + + const appStartDurationMilliseconds = this._getAppStartDurationMilliseconds(appStartTimestampMs); if (!appStartDurationMilliseconds) { logger.warn('[ReactNativeTracing] App start end has not been recorded, not adding app start span.'); return; @@ -469,7 +476,7 @@ export class ReactNativeTracing implements Integration { return; } - const appStartTimeSeconds = appStart.appStartTime / 1000; + const appStartTimeSeconds = appStartTimestampMs / 1000; transaction.startTimestamp = appStartTimeSeconds; @@ -485,18 +492,33 @@ export class ReactNativeTracing implements Integration { setSpanDurationAsMeasurement('time_to_full_display', maybeTtfdSpan); } - const op = appStart.isColdStart ? APP_START_COLD_OP : APP_START_WARM_OP; - transaction.startChild({ - description: appStart.isColdStart ? 'Cold App Start' : 'Warm App Start', + const op = appStart.type === 'cold' ? APP_START_COLD_OP : APP_START_WARM_OP; + const appStartSpan = transaction.startChild({ + description: appStart.type === 'cold' ? 'Cold App Start' : 'Warm App Start', op, startTimestamp: appStartTimeSeconds, endTimestamp: this._appStartFinishTimestamp, }); + this._addNativeSpansTo(appStartSpan, appStart.spans); - const measurement = appStart.isColdStart ? APP_START_COLD : APP_START_WARM; + const measurement = appStart.type === 'cold' ? APP_START_COLD : APP_START_WARM; transaction.setMeasurement(measurement, appStartDurationMilliseconds, 'millisecond'); } + /** + * Adds native spans to the app start span. + */ + private _addNativeSpansTo(appStartSpan: Span, nativeSpans: NativeAppStartResponse['spans']): void { + nativeSpans.forEach(span => { + appStartSpan.startChild({ + op: appStartSpan.op, + description: span.description, + startTimestamp: span.start_timestamp_ms / 1000, + endTimestamp: span.end_timestamp_ms / 1000, + }); + }); + } + /** To be called when the route changes, but BEFORE the components of the new route mount. */ private _onRouteWillChange(context: TransactionContext): TransactionType | undefined { return this._createRouteTransaction(context); diff --git a/test/tracing/reactnativetracing.test.ts b/test/tracing/reactnativetracing.test.ts index ff1dfd9b6a..d786cfdd1d 100644 --- a/test/tracing/reactnativetracing.test.ts +++ b/test/tracing/reactnativetracing.test.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import * as SentryBrowser from '@sentry/browser'; -import type { Event } from '@sentry/types'; +import type { Event, SpanJSON } from '@sentry/types'; import type { NativeAppStartResponse } from '../../src/js/NativeRNSentry'; import { RoutingInstrumentation } from '../../src/js/tracing/routingInstrumentation'; @@ -269,9 +269,10 @@ describe('ReactNativeTracing', () => { const timeOriginMilliseconds = Date.now(); const appStartTimeMilliseconds = timeOriginMilliseconds - 65000; const mockAppStartResponse: NativeAppStartResponse = { - isColdStart: false, - appStartTime: appStartTimeMilliseconds, - didFetchAppStart: false, + type: 'warm', + app_start_timestamp_ms: appStartTimeMilliseconds, + has_fetched: false, + spans: [], }; mockFunction(getTimeOriginMilliseconds).mockReturnValue(timeOriginMilliseconds); @@ -295,9 +296,10 @@ describe('ReactNativeTracing', () => { const timeOriginMilliseconds = Date.now(); const appStartTimeMilliseconds = timeOriginMilliseconds - 65000; const mockAppStartResponse: NativeAppStartResponse = { - isColdStart: false, - appStartTime: appStartTimeMilliseconds, - didFetchAppStart: false, + type: 'warm', + app_start_timestamp_ms: appStartTimeMilliseconds, + has_fetched: false, + spans: [], }; mockFunction(getTimeOriginMilliseconds).mockReturnValue(timeOriginMilliseconds); @@ -315,10 +317,10 @@ describe('ReactNativeTracing', () => { expect(transaction?.start_timestamp).toBeGreaterThanOrEqual(timeOriginMilliseconds / 1000); }); - it('Does not create app start transaction if didFetchAppStart == true', async () => { + it('Does not create app start transaction if has_fetched == true', async () => { const integration = new ReactNativeTracing(); - mockAppStartResponse({ cold: false, didFetchAppStart: true }); + mockAppStartResponse({ cold: false, has_fetched: true }); setup(integration); @@ -328,6 +330,46 @@ describe('ReactNativeTracing', () => { const transaction = client.event; expect(transaction).toBeUndefined(); }); + + it('adds native spans as a child of the main app start span', async () => { + const integration = new ReactNativeTracing(); + + const [timeOriginMilliseconds] = mockAppStartResponse({ + cold: true, + enableNativeSpans: true, + }); + + setup(integration); + + await jest.advanceTimersByTimeAsync(500); + await jest.runOnlyPendingTimersAsync(); + + const transaction = client.event; + + const appStartRootSpan = transaction!.spans!.find(({ description }) => description === 'Cold App Start'); + const nativeSpan = transaction!.spans!.find(({ description }) => description === 'test native app start span'); + const nativeSpanJSON = spanToJSON(nativeSpan!); + const appStartRootSpanJSON = spanToJSON(appStartRootSpan!); + + expect(appStartRootSpan).toBeDefined(); + expect(nativeSpan).toBeDefined(); + expect(appStartRootSpanJSON).toEqual( + expect.objectContaining({ + description: 'Cold App Start', + span_id: expect.any(String), + op: APP_START_COLD_OP, + }), + ); + expect(nativeSpanJSON).toEqual( + expect.objectContaining({ + description: 'test native app start span', + start_timestamp: (timeOriginMilliseconds - 100) / 1000, + timestamp: (timeOriginMilliseconds - 50) / 1000, + parent_span_id: spanToJSON(appStartRootSpan!).span_id, // parent is the root app start span + op: spanToJSON(appStartRootSpan!).op, // op is the same as the root app start span + }), + ); + }); }); describe('With routing instrumentation', () => { @@ -438,14 +480,14 @@ describe('ReactNativeTracing', () => { expect(span!.timestamp).toBe(timeOriginMilliseconds / 1000); }); - it('Does not update route transaction if didFetchAppStart == true', async () => { + it('Does not update route transaction if has_fetched == true', async () => { const routingInstrumentation = new RoutingInstrumentation(); const integration = new ReactNativeTracing({ enableStallTracking: false, routingInstrumentation, }); - const [, appStartTimeMilliseconds] = mockAppStartResponse({ cold: false, didFetchAppStart: true }); + const [, appStartTimeMilliseconds] = mockAppStartResponse({ cold: false, has_fetched: true }); setup(integration); // wait for internal promises to resolve, fetch app start data from mocked native @@ -914,13 +956,30 @@ describe('ReactNativeTracing', () => { }); }); -function mockAppStartResponse({ cold, didFetchAppStart }: { cold: boolean; didFetchAppStart?: boolean }) { +function mockAppStartResponse({ + cold, + has_fetched, + enableNativeSpans, +}: { + cold: boolean; + has_fetched?: boolean; + enableNativeSpans?: boolean; +}) { const timeOriginMilliseconds = Date.now(); const appStartTimeMilliseconds = timeOriginMilliseconds - 100; const mockAppStartResponse: NativeAppStartResponse = { - isColdStart: cold, - appStartTime: appStartTimeMilliseconds, - didFetchAppStart: didFetchAppStart ?? false, + type: cold ? 'cold' : 'warm', + app_start_timestamp_ms: appStartTimeMilliseconds, + has_fetched: has_fetched ?? false, + spans: enableNativeSpans + ? [ + { + description: 'test native app start span', + start_timestamp_ms: timeOriginMilliseconds - 100, + end_timestamp_ms: timeOriginMilliseconds - 50, + }, + ] + : [], }; mockFunction(getTimeOriginMilliseconds).mockReturnValue(timeOriginMilliseconds); diff --git a/test/tracing/reactnavigation.ttid.test.tsx b/test/tracing/reactnavigation.ttid.test.tsx index 200257957f..df840a3e13 100644 --- a/test/tracing/reactnavigation.ttid.test.tsx +++ b/test/tracing/reactnavigation.ttid.test.tsx @@ -36,9 +36,10 @@ describe('React Navigation - TTID', () => { (isHermesEnabled as jest.Mock).mockReturnValue(true); mockWrapper.NATIVE.fetchNativeAppStart.mockResolvedValue({ - appStartTime: mockedAppStartTimeSeconds * 1000, - didFetchAppStart: false, - isColdStart: true, + app_start_timestamp_ms: mockedAppStartTimeSeconds * 1000, + has_fetched: false, + type: 'cold', + spans: [], }); mockedEventEmitter = mockedSentryEventEmitter.createMockedSentryEventEmitter(); From 70e6261eb7fdf57e3aba1f72d12c3eb518bcad99 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Mon, 10 Jun 2024 15:50:23 +0200 Subject: [PATCH 13/23] feat(tracing): Add JS Bundle Execution to the App Start span (#3857) --- CHANGELOG.md | 1 + src/js/tracing/reactnativeprofiler.tsx | 10 +- src/js/tracing/reactnativetracing.ts | 38 +++++++ src/js/tracing/utils.ts | 26 ++++- src/js/utils/worldwide.ts | 2 + test/tracing/reactnativetracing.test.ts | 125 ++++++++++++++++++++++++ 6 files changed, 200 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dd19d92e7..014f3d0cab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Add native application start spans ([#3855](https://github.com/getsentry/sentry-react-native/pull/3855)) - This doesn't change the app start measurement length, but add child spans (more detail) into the existing app start span +- Added JS Bundle Execution start information to the application start measurements ([#3857](https://github.com/getsentry/sentry-react-native/pull/3857)) ### Dependencies diff --git a/src/js/tracing/reactnativeprofiler.tsx b/src/js/tracing/reactnativeprofiler.tsx index 71fcfb8434..2f5a2f65f1 100644 --- a/src/js/tracing/reactnativeprofiler.tsx +++ b/src/js/tracing/reactnativeprofiler.tsx @@ -1,4 +1,5 @@ -import { getCurrentHub, Profiler } from '@sentry/react'; +import { getClient, getCurrentHub, Profiler } from '@sentry/react'; +import { timestampInSeconds } from '@sentry/utils'; import { createIntegration } from '../integrations/factory'; import { ReactNativeTracing } from './reactnativetracing'; @@ -13,6 +14,13 @@ const ReactNativeProfilerGlobalState = { export class ReactNativeProfiler extends Profiler { public readonly name: string = 'ReactNativeProfiler'; + public constructor(props: ConstructorParameters[0]) { + const client = getClient(); + const integration = client && client.getIntegrationByName && client.getIntegrationByName('ReactNativeTracing'); + integration && integration.setRootComponentFirstConstructorCallTimestampMs(timestampInSeconds() * 1000); + super(props); + } + /** * Get the app root mount time. */ diff --git a/src/js/tracing/reactnativetracing.ts b/src/js/tracing/reactnativetracing.ts index a242ab3492..33f85be4d4 100644 --- a/src/js/tracing/reactnativetracing.ts +++ b/src/js/tracing/reactnativetracing.ts @@ -24,6 +24,7 @@ import { cancelInBackground, onlySampleIfChildSpans } from './transaction'; import type { BeforeNavigate, RouteChangeContextData } from './types'; import { adjustTransactionDuration, + getBundleStartTimestampMs, getTimeOriginMilliseconds, isNearToNow, setSpanDurationAsMeasurement, @@ -153,6 +154,7 @@ export class ReactNativeTracing implements Integration { private _hasSetTracePropagationTargets: boolean; private _hasSetTracingOrigins: boolean; private _currentViewName: string | undefined; + private _firstConstructorCallTimestampMs: number | undefined; public constructor(options: Partial = {}) { this._hasSetTracePropagationTargets = !!( @@ -295,6 +297,13 @@ export class ReactNativeTracing implements Integration { this._appStartFinishTimestamp = endTimestamp; } + /** + * Sets the root component first constructor call timestamp. + */ + public setRootComponentFirstConstructorCallTimestampMs(timestamp: number): void { + this._firstConstructorCallTimestampMs = timestamp; + } + /** * Starts a new transaction for a user interaction. * @param userInteractionId Consists of `op` representation UI Event and `elementId` unique element identifier on current screen. @@ -499,12 +508,41 @@ export class ReactNativeTracing implements Integration { startTimestamp: appStartTimeSeconds, endTimestamp: this._appStartFinishTimestamp, }); + this._addJSExecutionBeforeRoot(appStartSpan); this._addNativeSpansTo(appStartSpan, appStart.spans); const measurement = appStart.type === 'cold' ? APP_START_COLD : APP_START_WARM; transaction.setMeasurement(measurement, appStartDurationMilliseconds, 'millisecond'); } + /** + * Adds JS Execution before React Root. If `Sentry.wrap` is not used, create a span for the start of JS Bundle execution. + */ + private _addJSExecutionBeforeRoot(appStartSpan: Span): void { + const bundleStartTimestampMs = getBundleStartTimestampMs(); + if (!bundleStartTimestampMs) { + return; + } + + if (!this._firstConstructorCallTimestampMs) { + logger.warn('Missing the root component first constructor call timestamp.'); + appStartSpan.startChild({ + description: 'JS Bundle Execution Start', + op: appStartSpan.op, + startTimestamp: bundleStartTimestampMs / 1000, + endTimestamp: bundleStartTimestampMs / 1000, + }); + return; + } + + appStartSpan.startChild({ + description: 'JS Bundle Execution Before React Root', + op: appStartSpan.op, + startTimestamp: bundleStartTimestampMs / 1000, + endTimestamp: this._firstConstructorCallTimestampMs / 1000, + }); + } + /** * Adds native spans to the app start span. */ diff --git a/src/js/tracing/utils.ts b/src/js/tracing/utils.ts index de74bfe447..f154322d18 100644 --- a/src/js/tracing/utils.ts +++ b/src/js/tracing/utils.ts @@ -6,7 +6,9 @@ import { spanToJSON, } from '@sentry/core'; import type { Span, TransactionContext, TransactionSource } from '@sentry/types'; -import { timestampInSeconds } from '@sentry/utils'; +import { logger, timestampInSeconds } from '@sentry/utils'; + +import { RN_GLOBAL_OBJ } from '../utils/worldwide'; export const defaultTransactionSource: TransactionSource = 'component'; export const customTransactionSource: TransactionSource = 'custom'; @@ -111,3 +113,25 @@ export function setSpanDurationAsMeasurement(name: string, span: Span): void { setMeasurement(name, (spanEnd - spanStart) * 1000, 'millisecond'); } + +/** + * Returns unix timestamp in ms of the bundle start time. + * + * If not available, returns undefined. + */ +export function getBundleStartTimestampMs(): number | undefined { + const bundleStartTime = RN_GLOBAL_OBJ.__BUNDLE_START_TIME__; + if (!bundleStartTime) { + logger.warn('Missing the bundle start time on the global object.'); + return undefined; + } + + if (!RN_GLOBAL_OBJ.nativePerformanceNow) { + // bundleStartTime is Date.now() in milliseconds + return bundleStartTime; + } + + // nativePerformanceNow() is monotonic clock like performance.now() + const approxStartingTimeOrigin = Date.now() - RN_GLOBAL_OBJ.nativePerformanceNow(); + return approxStartingTimeOrigin + bundleStartTime; +} diff --git a/src/js/utils/worldwide.ts b/src/js/utils/worldwide.ts index 4eedca2992..4f1cfc4c7b 100644 --- a/src/js/utils/worldwide.ts +++ b/src/js/utils/worldwide.ts @@ -22,6 +22,8 @@ export interface ReactNativeInternalGlobal extends InternalGlobal { ___SENTRY_METRO_DEV_SERVER___?: string; }; }; + __BUNDLE_START_TIME__?: number; + nativePerformanceNow?: () => number; } /** Get's the global object for the current JavaScript runtime */ diff --git a/test/tracing/reactnativetracing.test.ts b/test/tracing/reactnativetracing.test.ts index d786cfdd1d..d14047d9af 100644 --- a/test/tracing/reactnativetracing.test.ts +++ b/test/tracing/reactnativetracing.test.ts @@ -331,6 +331,114 @@ describe('ReactNativeTracing', () => { expect(transaction).toBeUndefined(); }); + describe('bundle execution spans', () => { + afterEach(() => { + clearReactNativeBundleExecutionStartTimestamp(); + }); + + it('does not add bundle executions span if __BUNDLE_START_TIME__ is undefined', async () => { + const integration = new ReactNativeTracing(); + + mockAppStartResponse({ cold: true }); + + setup(integration); + + await jest.advanceTimersByTimeAsync(500); + await jest.runOnlyPendingTimersAsync(); + + const transaction = client.event; + + const bundleStartSpan = transaction!.spans!.find( + ({ description }) => + description === 'JS Bundle Execution Start' || description === 'JS Bundle Execution Before React Root', + ); + + expect(bundleStartSpan).toBeUndefined(); + }); + + it('adds bundle execution span', async () => { + const integration = new ReactNativeTracing(); + + const [timeOriginMilliseconds] = mockAppStartResponse({ cold: true }); + mockReactNativeBundleExecutionStartTimestamp(); + + setup(integration); + integration.onAppStartFinish(timeOriginMilliseconds + 200); + + await jest.advanceTimersByTimeAsync(500); + await jest.runOnlyPendingTimersAsync(); + + const transaction = client.event; + + const appStartRootSpan = transaction!.spans!.find(({ description }) => description === 'Cold App Start'); + const bundleStartSpan = transaction!.spans!.find( + ({ description }) => description === 'JS Bundle Execution Start', + ); + const appStartRootSpanJSON = spanToJSON(appStartRootSpan!); + const bundleStartSpanJSON = spanToJSON(bundleStartSpan!); + + expect(appStartRootSpan).toBeDefined(); + expect(bundleStartSpan).toBeDefined(); + expect(appStartRootSpanJSON).toEqual( + expect.objectContaining({ + description: 'Cold App Start', + span_id: expect.any(String), + op: APP_START_COLD_OP, + }), + ); + expect(bundleStartSpanJSON).toEqual( + expect.objectContaining({ + description: 'JS Bundle Execution Start', + start_timestamp: expect.closeTo((timeOriginMilliseconds - 50) / 1000), + timestamp: expect.closeTo((timeOriginMilliseconds - 50) / 1000), + parent_span_id: spanToJSON(appStartRootSpan!).span_id, // parent is the root app start span + op: spanToJSON(appStartRootSpan!).op, // op is the same as the root app start span + }), + ); + }); + + it('adds bundle execution before react root', async () => { + const integration = new ReactNativeTracing(); + + const [timeOriginMilliseconds] = mockAppStartResponse({ cold: true }); + mockReactNativeBundleExecutionStartTimestamp(); + + setup(integration); + integration.setRootComponentFirstConstructorCallTimestampMs(timeOriginMilliseconds - 10); + + await jest.advanceTimersByTimeAsync(500); + await jest.runOnlyPendingTimersAsync(); + + const transaction = client.event; + + const appStartRootSpan = transaction!.spans!.find(({ description }) => description === 'Cold App Start'); + const bundleStartSpan = transaction!.spans!.find( + ({ description }) => description === 'JS Bundle Execution Before React Root', + ); + const appStartRootSpanJSON = spanToJSON(appStartRootSpan!); + const bundleStartSpanJSON = spanToJSON(bundleStartSpan!); + + expect(appStartRootSpan).toBeDefined(); + expect(bundleStartSpan).toBeDefined(); + expect(appStartRootSpanJSON).toEqual( + expect.objectContaining({ + description: 'Cold App Start', + span_id: expect.any(String), + op: APP_START_COLD_OP, + }), + ); + expect(bundleStartSpanJSON).toEqual( + expect.objectContaining({ + description: 'JS Bundle Execution Before React Root', + start_timestamp: expect.closeTo((timeOriginMilliseconds - 50) / 1000), + timestamp: (timeOriginMilliseconds - 10) / 1000, + parent_span_id: spanToJSON(appStartRootSpan!).span_id, // parent is the root app start span + op: spanToJSON(appStartRootSpan!).op, // op is the same as the root app start span + }), + ); + }); + }); + it('adds native spans as a child of the main app start span', async () => { const integration = new ReactNativeTracing(); @@ -991,3 +1099,20 @@ function mockAppStartResponse({ function setup(integration: ReactNativeTracing) { integration.setupOnce(addGlobalEventProcessor, getCurrentHub); } + +/** + * Mocks RN Bundle Start Module + * `var __BUNDLE_START_TIME__=this.nativePerformanceNow?nativePerformanceNow():Date.now()` + */ +function mockReactNativeBundleExecutionStartTimestamp() { + RN_GLOBAL_OBJ.nativePerformanceNow = () => 100; // monotonic clock like `performance.now()` + RN_GLOBAL_OBJ.__BUNDLE_START_TIME__ = 50; // 50ms after time origin +} + +/** + * Removes mock added by mockReactNativeBundleExecutionStartTimestamp + */ +function clearReactNativeBundleExecutionStartTimestamp() { + delete RN_GLOBAL_OBJ.nativePerformanceNow; + delete RN_GLOBAL_OBJ.__BUNDLE_START_TIME__; +} From f2f339989e76d81d759c0898fd813ee549332348 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Thu, 13 Jun 2024 14:15:14 +0200 Subject: [PATCH 14/23] fix(performance): add more debug logs to native frames integration (#3880) --- CHANGELOG.md | 4 +++ src/js/tracing/nativeframes.ts | 54 +++++++++++++++++++++------- src/js/tracing/reactnativetracing.ts | 6 ++++ 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 014f3d0cab..7b8904b3c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ - This doesn't change the app start measurement length, but add child spans (more detail) into the existing app start span - Added JS Bundle Execution start information to the application start measurements ([#3857](https://github.com/getsentry/sentry-react-native/pull/3857)) +### Fixes + +- Add more expressive debug logs to Native Frames Integration ([#3880](https://github.com/getsentry/sentry-react-native/pull/3880)) + ### Dependencies - Bump Cocoa SDK from v8.27.0 to v8.28.0 ([#3866](https://github.com/getsentry/sentry-react-native/pull/3866)) diff --git a/src/js/tracing/nativeframes.ts b/src/js/tracing/nativeframes.ts index 84eab70ec5..6174091f60 100644 --- a/src/js/tracing/nativeframes.ts +++ b/src/js/tracing/nativeframes.ts @@ -6,6 +6,13 @@ import type { NativeFramesResponse } from '../NativeRNSentry'; import { NATIVE } from '../wrapper'; import { instrumentChildSpanFinish } from './utils'; +/** + * Timeout from the final native frames fetch to processing the associated transaction. + * If the transaction is not processed by this time, the native frames will be dropped + * and not added to the event. + */ +const FINAL_FRAMES_TIMEOUT_MS = 2000; + export interface FramesMeasurements extends Measurements { frames_total: { value: number; unit: MeasurementUnit }; frames_slow: { value: number; unit: MeasurementUnit }; @@ -45,14 +52,24 @@ export class NativeFramesInstrumentation { * Logs the native frames at this start point and instruments child span finishes. */ public onTransactionStart(transaction: Transaction): void { + logger.debug(`[NativeFrames] Fetching frames for root span start (${transaction.spanContext().spanId}).`); void NATIVE.fetchNativeFrames() .then(framesMetrics => { if (framesMetrics) { transaction.setData('__startFrames', framesMetrics); + } else { + logger.warn( + `[NativeFrames] Fetched frames for root span start (${ + transaction.spanContext().spanId + }), but no frames were returned.`, + ); } }) .then(undefined, error => { - logger.error(`[ReactNativeTracing] Error while fetching native frames: ${error}`); + logger.error( + `[NativeFrames] Error while fetching frames for root span start (${transaction.spanContext().spanId})`, + error, + ); }); instrumentChildSpanFinish(transaction, (_: Span, endTimestamp?: number) => { @@ -66,8 +83,11 @@ export class NativeFramesInstrumentation { * To be called when a transaction is finished */ public onTransactionFinish(transaction: Transaction): void { - this._fetchFramesForTransaction(transaction).then(undefined, (reason: unknown) => { - logger.error(`[ReactNativeTracing] Error while fetching native frames:`, reason); + this._fetchEndFramesForTransaction(transaction).then(undefined, (reason: unknown) => { + logger.error( + `[NativeFrames] Error while fetching frames for root span start (${transaction.spanContext().spanId})`, + reason, + ); }); } @@ -88,7 +108,7 @@ export class NativeFramesInstrumentation { } }) .then(undefined, error => { - logger.error(`[ReactNativeTracing] Error while fetching native frames: ${error}`); + logger.error(`[NativeFrames] Error while fetching frames for child span end.`, error); }); } @@ -101,17 +121,20 @@ export class NativeFramesInstrumentation { startFrames: NativeFramesResponse, ): Promise { if (_finishFrames.has(traceId)) { + logger.debug(`[NativeFrames] Native end frames already fetched for trace id (${traceId}).`); return this._prepareMeasurements(traceId, finalEndTimestamp, startFrames); } return new Promise(resolve => { const timeout = setTimeout(() => { + logger.debug(`[NativeFrames] Native end frames listener removed by timeout for trace id (${traceId}).`); _framesListeners.delete(traceId); resolve(null); }, 2000); _framesListeners.set(traceId, () => { + logger.debug(`[NativeFrames] Native end frames listener called for trace id (${traceId}).`); resolve(this._prepareMeasurements(traceId, finalEndTimestamp, startFrames)); clearTimeout(timeout); @@ -137,6 +160,7 @@ export class NativeFramesInstrumentation { // Must be in the margin of error of the actual transaction finish time (finalEndTimestamp) Math.abs(finish.timestamp - finalEndTimestamp) < MARGIN_OF_ERROR_SECONDS ) { + logger.debug(`[NativeFrames] Using frames from root span end (traceId, ${traceId}).`); finalFinishFrames = finish.nativeFrames; } else if ( this._lastSpanFinishFrames && @@ -144,8 +168,12 @@ export class NativeFramesInstrumentation { ) { // Fallback to the last span finish if it is within the margin of error of the actual finish timestamp. // This should be the case for trimEnd. + logger.debug(`[NativeFrames] Using native frames from last span end (traceId, ${traceId}).`); finalFinishFrames = this._lastSpanFinishFrames.nativeFrames; } else { + logger.warn( + `[NativeFrames] Frames were collected within larger than margin of error delay for traceId (${traceId}). Dropping the inaccurate values.`, + ); return null; } @@ -170,7 +198,7 @@ export class NativeFramesInstrumentation { /** * Fetch finish frames for a transaction at the current time. Calls any awaiting listeners. */ - private async _fetchFramesForTransaction(transaction: Transaction): Promise { + private async _fetchEndFramesForTransaction(transaction: Transaction): Promise { const startFrames = transaction.data.__startFrames as NativeFramesResponse | undefined; // This timestamp marks when the finish frames were retrieved. It should be pretty close to the transaction finish. @@ -187,13 +215,13 @@ export class NativeFramesInstrumentation { _framesListeners.get(transaction.traceId)?.(); - setTimeout(() => this._cancelFinishFrames(transaction), 2000); + setTimeout(() => this._cancelEndFrames(transaction), FINAL_FRAMES_TIMEOUT_MS); } /** * On a finish frames failure, we cancel the await. */ - private _cancelFinishFrames(transaction: Transaction): void { + private _cancelEndFrames(transaction: Transaction): void { if (_finishFrames.has(transaction.traceId)) { _finishFrames.delete(transaction.traceId); @@ -222,6 +250,12 @@ export class NativeFramesInstrumentation { const traceId = traceContext.trace_id; + if (!traceContext.data?.__startFrames) { + logger.warn( + `[NativeFrames] Start frames of transaction ${event.transaction} (eventId, ${event.event_id}) are missing, but it already ended.`, + ); + } + if (traceId && traceContext.data?.__startFrames && event.timestamp) { const measurements = await this._getFramesMeasurements( traceId, @@ -229,11 +263,7 @@ export class NativeFramesInstrumentation { traceContext.data.__startFrames as NativeFramesResponse, ); - if (!measurements) { - logger.log( - `[NativeFrames] Could not fetch native frames for ${traceContext.op} transaction ${event.transaction}. Not adding native frames measurements.`, - ); - } else { + if (measurements) { logger.log( `[Measurements] Adding measurements to ${traceContext.op} transaction ${ event.transaction diff --git a/src/js/tracing/reactnativetracing.ts b/src/js/tracing/reactnativetracing.ts index 33f85be4d4..285f1c52a5 100644 --- a/src/js/tracing/reactnativetracing.ts +++ b/src/js/tracing/reactnativetracing.ts @@ -279,6 +279,12 @@ export class ReactNativeTracing implements Integration { // Only if this method is called at or within margin of error to the start timestamp. this.nativeFramesInstrumentation?.onTransactionStart(transaction); this.stallTrackingInstrumentation?.onTransactionStart(transaction); + } else { + logger.warn( + `[ReactNativeTracing] onTransactionStart called with delay (larger than margin of error) for transaction ${ + transaction.description + } (${transaction.spanContext().spanId}). Not fetching native frames or tracking stalls.`, + ); } } From 9fc8151e684420e1d9477788fd60a3481d7dff9b Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Thu, 13 Jun 2024 14:19:00 +0200 Subject: [PATCH 15/23] fix(client): use `_setupIntegrations` to extend both `init` and public `setupIntegrations` (#3882) --- CHANGELOG.md | 1 + src/js/client.ts | 4 ++-- test/client.test.ts | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b8904b3c3..675ae3447b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ ### Fixes - Add more expressive debug logs to Native Frames Integration ([#3880](https://github.com/getsentry/sentry-react-native/pull/3880)) +- Add missing tracing integrations when using `client.init()` ([#3882](https://github.com/getsentry/sentry-react-native/pull/3882)) ### Dependencies diff --git a/src/js/client.ts b/src/js/client.ts index 5512081e49..a251e2092f 100644 --- a/src/js/client.ts +++ b/src/js/client.ts @@ -109,8 +109,8 @@ export class ReactNativeClient extends BaseClient { /** * Sets up the integrations */ - public setupIntegrations(): void { - super.setupIntegrations(); + protected _setupIntegrations(): void { + super._setupIntegrations(); const tracing = this.getIntegration(ReactNativeTracing); const routingName = tracing?.options.routingInstrumentation?.name; if (routingName) { diff --git a/test/client.test.ts b/test/client.test.ts index ffdefc9547..562009d834 100644 --- a/test/client.test.ts +++ b/test/client.test.ts @@ -667,6 +667,22 @@ describe('Tests ReactNativeClient', () => { expect(client.getIntegrationById('ReactNativeUserInteractionTracing')).toBeTruthy(); }); + test('register user interactions tracing - init()', () => { + const client = new ReactNativeClient( + mockedOptions({ + dsn: EXAMPLE_DSN, + integrations: [ + new ReactNativeTracing({ + enableUserInteractionTracing: true, + }), + ], + }), + ); + client.init(); + + expect(client.getIntegrationById('ReactNativeUserInteractionTracing')).toBeTruthy(); + }); + test('do not register user interactions tracing', () => { const client = new ReactNativeClient( mockedOptions({ @@ -682,6 +698,22 @@ describe('Tests ReactNativeClient', () => { expect(client.getIntegrationById('ReactNativeUserInteractionTracing')).toBeUndefined(); }); + + test('do not register user interactions tracing - init()', () => { + const client = new ReactNativeClient( + mockedOptions({ + dsn: EXAMPLE_DSN, + integrations: [ + new ReactNativeTracing({ + enableUserInteractionTracing: false, + }), + ], + }), + ); + client.init(); + + expect(client.getIntegrationById('ReactNativeUserInteractionTracing')).toBeUndefined(); + }); }); }); From 785b7373a6b018fddd7d4ab6bfea19d56dd15187 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Thu, 13 Jun 2024 14:24:15 +0200 Subject: [PATCH 16/23] fix(xcode): Xcode command line builds fail with `--allow-failure` (#3887) --- CHANGELOG.md | 2 ++ scripts/sentry-xcode-debug-files.sh | 11 ++++++++++- scripts/sentry-xcode.sh | 11 ++++++++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 675ae3447b..23e33245ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ - Add more expressive debug logs to Native Frames Integration ([#3880](https://github.com/getsentry/sentry-react-native/pull/3880)) - Add missing tracing integrations when using `client.init()` ([#3882](https://github.com/getsentry/sentry-react-native/pull/3882)) +- Ensure `sentry-cli` doesn't trigger Xcode `error:` prefix ([#3887](https://github.com/getsentry/sentry-react-native/pull/3887)) + - Fixes `--allow-failure` failing Xcode builds ### Dependencies diff --git a/scripts/sentry-xcode-debug-files.sh b/scripts/sentry-xcode-debug-files.sh index 8fcc403fbd..236a4df7d1 100755 --- a/scripts/sentry-xcode-debug-files.sh +++ b/scripts/sentry-xcode-debug-files.sh @@ -35,5 +35,14 @@ if [ "$SENTRY_DISABLE_AUTO_UPLOAD" == true ]; then elif echo "$XCODE_BUILD_CONFIGURATION" | grep -iq "debug"; then # case insensitive check for "debug" echo "Skipping debug files upload for *Debug* configuration" else - /bin/sh -c "\"$LOCAL_NODE_BINARY\" $UPLOAD_DEBUG_FILES" + # 'warning:' triggers a warning in Xcode, 'error:' triggers an error + set +x +e # disable printing commands otherwise we might print `error:` by accident and allow continuing on error + SENTRY_UPLOAD_COMMAND_OUTPUT=$(/bin/sh -c "\"$LOCAL_NODE_BINARY\" $UPLOAD_DEBUG_FILES" 2>&1) + if [ $? -eq 0 ]; then + echo "$SENTRY_UPLOAD_COMMAND_OUTPUT" | awk '{print "output: sentry-cli - " $0}' + else + echo "error: sentry-cli - To disable native debug files auto upload, set SENTRY_DISABLE_AUTO_UPLOAD=true in your environment variables. Or to allow failing upload, set SENTRY_ALLOW_FAILURE=true" + echo "error: sentry-cli - $SENTRY_UPLOAD_COMMAND_OUTPUT" + fi + set -x -e # re-enable fi diff --git a/scripts/sentry-xcode.sh b/scripts/sentry-xcode.sh index 3752345c3d..e36fa74e03 100755 --- a/scripts/sentry-xcode.sh +++ b/scripts/sentry-xcode.sh @@ -23,7 +23,16 @@ ARGS="$NO_AUTO_RELEASE $SENTRY_CLI_EXTRA_ARGS $SENTRY_CLI_RN_XCODE_EXTRA_ARGS" REACT_NATIVE_XCODE_WITH_SENTRY="\"$SENTRY_CLI_EXECUTABLE\" react-native xcode $ARGS \"$REACT_NATIVE_XCODE\"" if [ "$SENTRY_DISABLE_AUTO_UPLOAD" != true ]; then - /bin/sh -c "\"$LOCAL_NODE_BINARY\" $REACT_NATIVE_XCODE_WITH_SENTRY" + # 'warning:' triggers a warning in Xcode, 'error:' triggers an error + set +x +e # disable printing commands otherwise we might print `error:` by accident and allow continuing on error + SENTRY_XCODE_COMMAND_OUTPUT=$(/bin/sh -c "\"$LOCAL_NODE_BINARY\" $REACT_NATIVE_XCODE_WITH_SENTRY" 2>&1) + if [ $? -eq 0 ]; then + echo "$SENTRY_XCODE_COMMAND_OUTPUT" | awk '{print "output: sentry-cli - " $0}' + else + echo "error: sentry-cli - To disable source maps auto upload, set SENTRY_DISABLE_AUTO_UPLOAD=true in your environment variables. Or to allow failing upload, set SENTRY_ALLOW_FAILURE=true" + echo "error: sentry-cli - $SENTRY_XCODE_COMMAND_OUTPUT" + fi + set -x -e # re-enable else echo "SENTRY_DISABLE_AUTO_UPLOAD=true, skipping sourcemaps upload" /bin/sh -c "$REACT_NATIVE_XCODE" From f7a4d29cc4cc575fc51ce4f8a612d291bd8638b8 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Mon, 17 Jun 2024 10:38:39 +0200 Subject: [PATCH 17/23] fix(performance): UIKit can't end after JS execution starts (#3884) --- CHANGELOG.md | 2 +- src/js/tracing/reactnativetracing.ts | 31 ++++++++++ test/tracing/reactnativetracing.test.ts | 79 +++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23e33245ec..c601b39b91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Features -- Add native application start spans ([#3855](https://github.com/getsentry/sentry-react-native/pull/3855)) +- Add native application start spans ([#3855](https://github.com/getsentry/sentry-react-native/pull/3855), [#3884](https://github.com/getsentry/sentry-react-native/pull/3884)) - This doesn't change the app start measurement length, but add child spans (more detail) into the existing app start span - Added JS Bundle Execution start information to the application start measurements ([#3857](https://github.com/getsentry/sentry-react-native/pull/3857)) diff --git a/src/js/tracing/reactnativetracing.ts b/src/js/tracing/reactnativetracing.ts index 285f1c52a5..26fad0d053 100644 --- a/src/js/tracing/reactnativetracing.ts +++ b/src/js/tracing/reactnativetracing.ts @@ -554,6 +554,10 @@ export class ReactNativeTracing implements Integration { */ private _addNativeSpansTo(appStartSpan: Span, nativeSpans: NativeAppStartResponse['spans']): void { nativeSpans.forEach(span => { + if (span.description === 'UIKit init') { + return this._createUIKitSpan(appStartSpan, span); + } + appStartSpan.startChild({ op: appStartSpan.op, description: span.description, @@ -563,6 +567,33 @@ export class ReactNativeTracing implements Integration { }); } + /** + * UIKit init is measured by the native layers till the native SDK start + * RN initializes the native SDK later, the end timestamp would be wrong + */ + private _createUIKitSpan(parentSpan: Span, nativeUIKitSpan: NativeAppStartResponse['spans'][number]): void { + const bundleStart = getBundleStartTimestampMs(); + + // If UIKit init ends after the bundle start, the native SDK was auto-initialized + // and so the end timestamp is incorrect. + // The timestamps can't equal, as RN initializes after UIKit. + if (bundleStart && bundleStart < nativeUIKitSpan.end_timestamp_ms) { + parentSpan.startChild({ + op: parentSpan.op, + description: 'UIKit Init to JS Exec Start', + startTimestamp: nativeUIKitSpan.start_timestamp_ms / 1000, + endTimestamp: bundleStart / 1000, + }); + } else { + parentSpan.startChild({ + op: parentSpan.op, + description: 'UIKit Init', + startTimestamp: nativeUIKitSpan.start_timestamp_ms / 1000, + endTimestamp: nativeUIKitSpan.end_timestamp_ms / 1000, + }); + } + } + /** To be called when the route changes, but BEFORE the components of the new route mount. */ private _onRouteWillChange(context: TransactionContext): TransactionType | undefined { return this._createRouteTransaction(context); diff --git a/test/tracing/reactnativetracing.test.ts b/test/tracing/reactnativetracing.test.ts index d14047d9af..38c9a846ee 100644 --- a/test/tracing/reactnativetracing.test.ts +++ b/test/tracing/reactnativetracing.test.ts @@ -478,6 +478,82 @@ describe('ReactNativeTracing', () => { }), ); }); + + it('adds ui kit init full length as a child of the main app start span', async () => { + const integration = new ReactNativeTracing(); + + const timeOriginMilliseconds = Date.now(); + mockAppStartResponse({ + cold: true, + enableNativeSpans: true, + customNativeSpans: [ + { + description: 'UIKit init', + start_timestamp_ms: timeOriginMilliseconds - 100, + end_timestamp_ms: timeOriginMilliseconds - 60, + }, + ], + }); + mockReactNativeBundleExecutionStartTimestamp(); + + setup(integration); + + await jest.advanceTimersByTimeAsync(500); + await jest.runOnlyPendingTimersAsync(); + + const transaction = client.event; + + const nativeSpan = transaction!.spans!.find(({ description }) => description?.startsWith('UIKit Init')); + const nativeSpanJSON = spanToJSON(nativeSpan!); + + expect(nativeSpan).toBeDefined(); + expect(nativeSpanJSON).toEqual( + expect.objectContaining({ + description: 'UIKit Init', + start_timestamp: (timeOriginMilliseconds - 100) / 1000, + timestamp: (timeOriginMilliseconds - 60) / 1000, + }), + ); + }); + + it('adds ui kit init start mark as a child of the main app start span', async () => { + const integration = new ReactNativeTracing(); + + const timeOriginMilliseconds = Date.now(); + mockAppStartResponse({ + cold: true, + enableNativeSpans: true, + customNativeSpans: [ + { + description: 'UIKit init', + start_timestamp_ms: timeOriginMilliseconds - 100, + end_timestamp_ms: timeOriginMilliseconds - 20, // After mocked bundle execution start + }, + ], + }); + mockReactNativeBundleExecutionStartTimestamp(); + + setup(integration); + + await jest.advanceTimersByTimeAsync(500); + await jest.runOnlyPendingTimersAsync(); + + const transaction = client.event; + + const nativeRuntimeInitSpan = transaction!.spans!.find(({ description }) => + description?.startsWith('UIKit Init to JS Exec Start'), + ); + const nativeRuntimeInitSpanJSON = spanToJSON(nativeRuntimeInitSpan!); + + expect(nativeRuntimeInitSpanJSON).toBeDefined(); + expect(nativeRuntimeInitSpanJSON).toEqual( + expect.objectContaining({ + description: 'UIKit Init to JS Exec Start', + start_timestamp: (timeOriginMilliseconds - 100) / 1000, + timestamp: (timeOriginMilliseconds - 50) / 1000, + }), + ); + }); }); describe('With routing instrumentation', () => { @@ -1068,10 +1144,12 @@ function mockAppStartResponse({ cold, has_fetched, enableNativeSpans, + customNativeSpans, }: { cold: boolean; has_fetched?: boolean; enableNativeSpans?: boolean; + customNativeSpans?: NativeAppStartResponse['spans']; }) { const timeOriginMilliseconds = Date.now(); const appStartTimeMilliseconds = timeOriginMilliseconds - 100; @@ -1086,6 +1164,7 @@ function mockAppStartResponse({ start_timestamp_ms: timeOriginMilliseconds - 100, end_timestamp_ms: timeOriginMilliseconds - 50, }, + ...(customNativeSpans ?? []), ] : [], }; From 534977cb359723762808b5bb569fc968625c5c16 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 11:14:41 +0200 Subject: [PATCH 18/23] chore(deps): update JavaScript SDK to v7.117.0 (#3806) Co-authored-by: Krystof Woldrich --- CHANGELOG.md | 3 + package.json | 20 ++--- yarn.lock | 221 +++++++++++++++++++++++---------------------------- 3 files changed, 111 insertions(+), 133 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c601b39b91..77599e9080 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,9 @@ - Bump Android SDK from v7.8.0 to v7.10.0 ([#3805](https://github.com/getsentry/sentry-react-native/pull/3805)) - [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#7100) - [diff](https://github.com/getsentry/sentry-java/compare/7.8.0...7.10.0) +- Bump JavaScript SDK from v7.113.0 to v7.117.0 ([#3806](https://github.com/getsentry/sentry-react-native/pull/3806)) + - [changelog](https://github.com/getsentry/sentry-javascript/blob/v7/CHANGELOG.md#71170) + - [diff](https://github.com/getsentry/sentry-javascript/compare/7.113.0...7.117.0) ## 5.23.1 diff --git a/package.json b/package.json index 8cc0f35f78..59fa39584f 100644 --- a/package.json +++ b/package.json @@ -67,22 +67,22 @@ "react-native": ">=0.65.0" }, "dependencies": { - "@sentry/browser": "7.113.0", + "@sentry/browser": "7.117.0", "@sentry/cli": "2.31.2", - "@sentry/core": "7.113.0", - "@sentry/hub": "7.113.0", - "@sentry/integrations": "7.113.0", - "@sentry/react": "7.113.0", - "@sentry/types": "7.113.0", - "@sentry/utils": "7.113.0" + "@sentry/core": "7.117.0", + "@sentry/hub": "7.117.0", + "@sentry/integrations": "7.117.0", + "@sentry/react": "7.117.0", + "@sentry/types": "7.117.0", + "@sentry/utils": "7.117.0" }, "devDependencies": { "@babel/core": "^7.23.5", "@expo/metro-config": "0.17.5", "@mswjs/interceptors": "^0.25.15", - "@sentry-internal/eslint-config-sdk": "7.113.0", - "@sentry-internal/eslint-plugin-sdk": "7.113.0", - "@sentry-internal/typescript": "7.113.0", + "@sentry-internal/eslint-config-sdk": "7.117.0", + "@sentry-internal/eslint-plugin-sdk": "7.117.0", + "@sentry-internal/typescript": "7.117.0", "@sentry/wizard": "3.16.3", "@types/jest": "^29.5.3", "@types/node": "^20.9.3", diff --git a/yarn.lock b/yarn.lock index 02c15e9e27..d36f2dd66b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3739,13 +3739,13 @@ component-type "^1.2.1" join-component "^1.1.0" -"@sentry-internal/eslint-config-sdk@7.113.0": - version "7.113.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/eslint-config-sdk/-/eslint-config-sdk-7.113.0.tgz#37a86b7bdf71cfab47d1108d27306f763bc37862" - integrity sha512-VaIVKbSymUq4FjehYZe+l/VhyD+KDf32HCL/7zdENbZXlgH+SO/oS4Iq1T2hc/W54D3rC1V8+YViaKQEbVmhcg== +"@sentry-internal/eslint-config-sdk@7.117.0": + version "7.117.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/eslint-config-sdk/-/eslint-config-sdk-7.117.0.tgz#27e9923a727d6ca56060047aab7af60a9d0360f4" + integrity sha512-LBj5oYTbdqCulebIZVeAj4LPs0UhFK2ZrBXyUgtKchZWahTk1L7eioXd2fmtIuJ9pFmvczS2UMJ0oRdtKy08Mg== dependencies: - "@sentry-internal/eslint-plugin-sdk" "7.113.0" - "@sentry-internal/typescript" "7.113.0" + "@sentry-internal/eslint-plugin-sdk" "7.117.0" + "@sentry-internal/typescript" "7.117.0" "@typescript-eslint/eslint-plugin" "^5.48.0" "@typescript-eslint/parser" "^5.48.0" eslint-config-prettier "^6.11.0" @@ -3755,40 +3755,40 @@ eslint-plugin-jsdoc "^30.0.3" eslint-plugin-simple-import-sort "^5.0.3" -"@sentry-internal/eslint-plugin-sdk@7.113.0": - version "7.113.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/eslint-plugin-sdk/-/eslint-plugin-sdk-7.113.0.tgz#cafb9b2bc8560c9baf8ffe05eb93703229492e5b" - integrity sha512-c4EGfRX4BECKB9EB9eS1oOvnkPXXRe4i9N3AlVHJrbamoS0Qqrxx1PRDvl3Gd8iI5NEw+1gAlLc2NgR9qRJ2bw== +"@sentry-internal/eslint-plugin-sdk@7.117.0": + version "7.117.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/eslint-plugin-sdk/-/eslint-plugin-sdk-7.117.0.tgz#110aae111143a13f8fdb196b09a1e721bc964dad" + integrity sha512-M6IuQCc+DPP4YqBS8HQI4B5B8+iB0Dwb3YvTO7mIfDOCmRIM//7j8Mn1rvOBpTeb3qwJnYsmlHg15jiSgtiLzQ== dependencies: requireindex "~1.1.0" -"@sentry-internal/feedback@7.113.0": - version "7.113.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-7.113.0.tgz#90a3c5493e289d589cfde79330fca549a24f41a4" - integrity sha512-eEmL8QXauUnM3FXGv0GT29RpL0Jo0pkn/uMu3aqjhQo7JKNqUGVYIUxJxiGWbVMbDXqPQ7L66bjjMS3FR1GM2g== +"@sentry-internal/feedback@7.117.0": + version "7.117.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-7.117.0.tgz#4ca62cc469611720e76877a756cf24b792cb178e" + integrity sha512-4X+NnnY17W74TymgLFH7/KPTVYpEtoMMJh8HzVdCmHTOE6j32XKBeBMRaXBhmNYmEgovgyRKKf2KvtSfgw+V1Q== dependencies: - "@sentry/core" "7.113.0" - "@sentry/types" "7.113.0" - "@sentry/utils" "7.113.0" + "@sentry/core" "7.117.0" + "@sentry/types" "7.117.0" + "@sentry/utils" "7.117.0" -"@sentry-internal/replay-canvas@7.113.0": - version "7.113.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-7.113.0.tgz#8a0165494b0a0ba7b1ae45166ca90a8749c38b7a" - integrity sha512-K8uA42aobNF/BAXf14el15iSAi9fonLBUrjZi6nPDq7zaA8rPvfcTL797hwCbqkETz2zDf52Jz7I3WFCshDoUw== +"@sentry-internal/replay-canvas@7.117.0": + version "7.117.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-7.117.0.tgz#d6b3b711453c88e040f31ebab1d4bc627b4a6505" + integrity sha512-7hjIhwEcoosr+BIa0AyEssB5xwvvlzUpvD5fXu4scd3I3qfX8gdnofO96a8r+LrQm3bSj+eN+4TfKEtWb7bU5A== dependencies: - "@sentry/core" "7.113.0" - "@sentry/replay" "7.113.0" - "@sentry/types" "7.113.0" - "@sentry/utils" "7.113.0" + "@sentry/core" "7.117.0" + "@sentry/replay" "7.117.0" + "@sentry/types" "7.117.0" + "@sentry/utils" "7.117.0" -"@sentry-internal/tracing@7.113.0": - version "7.113.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.113.0.tgz#936f23205ab53be62f1753b923eddc243cefde86" - integrity sha512-8MDnYENRMnEfQjvN4gkFYFaaBSiMFSU/6SQZfY9pLI3V105z6JQ4D0PGMAUVowXilwNZVpKNYohE7XByuhEC7Q== +"@sentry-internal/tracing@7.117.0": + version "7.117.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.117.0.tgz#c7d2357dae8d7ea2bc130e4513ac4ffc8dc7553c" + integrity sha512-fAIyijNvKBZNA12IcKo+dOYDRTNrzNsdzbm3DP37vJRKVQu19ucqP4Y6InvKokffDP2HZPzFPDoGXYuXkDhUZg== dependencies: - "@sentry/core" "7.113.0" - "@sentry/types" "7.113.0" - "@sentry/utils" "7.113.0" + "@sentry/core" "7.117.0" + "@sentry/types" "7.117.0" + "@sentry/utils" "7.117.0" "@sentry-internal/tracing@7.76.0": version "7.76.0" @@ -3799,24 +3799,24 @@ "@sentry/types" "7.76.0" "@sentry/utils" "7.76.0" -"@sentry-internal/typescript@7.113.0": - version "7.113.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/typescript/-/typescript-7.113.0.tgz#beb089d537f5267578e81d5dca47f0cf7fdb5875" - integrity sha512-zUjWxuBzY/ROXyeU487xvTq88BMDi9HRgKJ/XBgkse+tR+gtDTygPdToxNEVEMceLaPsHxi817/cAXIEJ5zyXQ== - -"@sentry/browser@7.113.0": - version "7.113.0" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.113.0.tgz#09b77812cbf476eacdccdc714ba4e4ba2c170a88" - integrity sha512-PdyVHPOprwoxGfKGsP2dXDWO0MBDW1eyP7EZlfZvM1A4hjk6ZRNfCv30g+TrqX4hiZDKzyqN3+AdP7N/J2IX0Q== - dependencies: - "@sentry-internal/feedback" "7.113.0" - "@sentry-internal/replay-canvas" "7.113.0" - "@sentry-internal/tracing" "7.113.0" - "@sentry/core" "7.113.0" - "@sentry/integrations" "7.113.0" - "@sentry/replay" "7.113.0" - "@sentry/types" "7.113.0" - "@sentry/utils" "7.113.0" +"@sentry-internal/typescript@7.117.0": + version "7.117.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/typescript/-/typescript-7.117.0.tgz#bd43fc07a222e98861e6ab8a85ddd60e7399cd47" + integrity sha512-SylReCEo1FiTuir6XiZuV+sWBOBERDL0C3YmdHhczOh0aeu50FUja7uJfoXMx0LTEwaUAXq62dWUvb9WetluOQ== + +"@sentry/browser@7.117.0": + version "7.117.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.117.0.tgz#3030073f360974dadcf5a5f2e1542497b3be2482" + integrity sha512-29X9HlvDEKIaWp6XKlNPPSNND0U6P/ede5WA2nVHfs1zJLWdZ7/ijuMc0sH/CueEkqHe/7gt94hBcI7HOU/wSw== + dependencies: + "@sentry-internal/feedback" "7.117.0" + "@sentry-internal/replay-canvas" "7.117.0" + "@sentry-internal/tracing" "7.117.0" + "@sentry/core" "7.117.0" + "@sentry/integrations" "7.117.0" + "@sentry/replay" "7.117.0" + "@sentry/types" "7.117.0" + "@sentry/utils" "7.117.0" "@sentry/cli-darwin@2.31.2": version "2.31.2" @@ -3885,13 +3885,13 @@ proxy-from-env "^1.1.0" which "^2.0.2" -"@sentry/core@7.113.0": - version "7.113.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.113.0.tgz#84307eabf03ece9304894ad24ee15581a220c5c7" - integrity sha512-pg75y3C5PG2+ur27A0Re37YTCEnX0liiEU7EOxWDGutH17x3ySwlYqLQmZsFZTSnvzv7t3MGsNZ8nT5O0746YA== +"@sentry/core@7.117.0": + version "7.117.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.117.0.tgz#eebdb6e700d5fbdf3102c4abfb4ff92ef79ae9a5" + integrity sha512-1XZ4/d/DEwnfM2zBMloXDwX+W7s76lGKQMgd8bwgPJZjjEztMJ7X0uopKAGwlQcjn242q+hsCBR6C+fSuI5kvg== dependencies: - "@sentry/types" "7.113.0" - "@sentry/utils" "7.113.0" + "@sentry/types" "7.117.0" + "@sentry/utils" "7.117.0" "@sentry/core@7.76.0": version "7.76.0" @@ -3901,23 +3901,23 @@ "@sentry/types" "7.76.0" "@sentry/utils" "7.76.0" -"@sentry/hub@7.113.0": - version "7.113.0" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.113.0.tgz#12f14071f43e657cd36174ba8b06cc955da5492f" - integrity sha512-aoerhlAw3vnY9a27eKAoK862oMXFbyMFWbaZuCeR5gfg7sHsOkVQkCl3yiYfF5hfw9MbwbbY6GqWbCrA89Ci/A== +"@sentry/hub@7.117.0": + version "7.117.0" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.117.0.tgz#924462cd083b57b45559eb5a25850e5b3004a7f8" + integrity sha512-pQrXnbzsRHCUsVIqz/sZ0vggnxuuHqsmyjoy2Ha1qn1Ya4QbyAWEEGoZTnZx6I/Vt3dzVvRnR3YCywatdkaFxg== dependencies: - "@sentry/core" "7.113.0" - "@sentry/types" "7.113.0" - "@sentry/utils" "7.113.0" + "@sentry/core" "7.117.0" + "@sentry/types" "7.117.0" + "@sentry/utils" "7.117.0" -"@sentry/integrations@7.113.0": - version "7.113.0" - resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.113.0.tgz#cce71e07cf90c4bf9b22f85c3ce22d9ba926ae5a" - integrity sha512-w0sspGBQ+6+V/9bgCkpuM3CGwTYoQEVeTW6iNebFKbtN7MrM3XsGAM9I2cW1jVxFZROqCBPFtd2cs5n0j14aAg== +"@sentry/integrations@7.117.0": + version "7.117.0" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.117.0.tgz#4613dae3bc1d257c3c870461327fd4f70dbda229" + integrity sha512-U3suSZysmU9EiQqg0ga5CxveAyNbi9IVdsapMDq5EQGNcVDvheXtULs+BOc11WYP3Kw2yWB38VDqLepfc/Fg2g== dependencies: - "@sentry/core" "7.113.0" - "@sentry/types" "7.113.0" - "@sentry/utils" "7.113.0" + "@sentry/core" "7.117.0" + "@sentry/types" "7.117.0" + "@sentry/utils" "7.117.0" localforage "^1.8.1" "@sentry/node@^7.69.0": @@ -3931,43 +3931,43 @@ "@sentry/utils" "7.76.0" https-proxy-agent "^5.0.0" -"@sentry/react@7.113.0": - version "7.113.0" - resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.113.0.tgz#8e21c92e9691ea881639596d7e60a996b23ba229" - integrity sha512-+zVPz+h5Wydq4ntekw3/dXq5jeHIpZoQ2iqhB96PA9Y94JIq178i/xIP204S1h6rN7cmWAqtR93vnPKdxnlUbQ== +"@sentry/react@7.117.0": + version "7.117.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.117.0.tgz#0a6e729f5d17782a02a48728821536ede569bc8d" + integrity sha512-aK+yaEP2esBhaczGU96Y7wkqB4umSIlRAzobv7ER88EGHzZulRaocTpQO8HJJGDHm4D8rD+E893BHnghkoqp4Q== dependencies: - "@sentry/browser" "7.113.0" - "@sentry/core" "7.113.0" - "@sentry/types" "7.113.0" - "@sentry/utils" "7.113.0" + "@sentry/browser" "7.117.0" + "@sentry/core" "7.117.0" + "@sentry/types" "7.117.0" + "@sentry/utils" "7.117.0" hoist-non-react-statics "^3.3.2" -"@sentry/replay@7.113.0": - version "7.113.0" - resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.113.0.tgz#db41b792e5d9966a9b1ca4eb1695ad7100f39b50" - integrity sha512-UD2IaphOWKFdeGR+ZiaNAQ+wFsnwbJK6PNwcW6cHmWKv9COlKufpFt06lviaqFZ8jmNrM4H+r+R8YVTrqCuxgg== +"@sentry/replay@7.117.0": + version "7.117.0" + resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.117.0.tgz#c41844b60ad5d711d663a562e2df77fe14c51bbb" + integrity sha512-V4DfU+x4UsA4BsufbQ8jHYa5H0q5PYUgso2X1PR31g1fpx7yiYguSmCfz1UryM6KkH92dfTnqXapDB44kXOqzQ== dependencies: - "@sentry-internal/tracing" "7.113.0" - "@sentry/core" "7.113.0" - "@sentry/types" "7.113.0" - "@sentry/utils" "7.113.0" + "@sentry-internal/tracing" "7.117.0" + "@sentry/core" "7.117.0" + "@sentry/types" "7.117.0" + "@sentry/utils" "7.117.0" -"@sentry/types@7.113.0": - version "7.113.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.113.0.tgz#2193c9933838302c82814771b03a8647fa684ffb" - integrity sha512-PJbTbvkcPu/LuRwwXB1He8m+GjDDLKBtu3lWg5xOZaF5IRdXQU2xwtdXXsjge4PZR00tF7MO7X8ZynTgWbYaew== +"@sentry/types@7.117.0": + version "7.117.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.117.0.tgz#c4d89aba487c05f4e5cbfa2f1c65180b536393b4" + integrity sha512-5dtdulcUttc3F0Te7ekZmpSp/ebt/CA71ELx0uyqVGjWsSAINwskFD77sdcjqvZWek//WjiYX1+GRKlpJ1QqsA== "@sentry/types@7.76.0": version "7.76.0" resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.76.0.tgz#628c9899bfa82ea762708314c50fd82f2138587d" integrity sha512-vj6z+EAbVrKAXmJPxSv/clpwS9QjPqzkraMFk2hIdE/kii8s8kwnkBwTSpIrNc8GnzV3qYC4r3qD+BXDxAGPaw== -"@sentry/utils@7.113.0": - version "7.113.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.113.0.tgz#1e6e790c9d84e4809b2bb529bbd33a506b6db7bd" - integrity sha512-nzKsErwmze1mmEsbW2AwL2oB+I5v6cDEJY4sdfLekA4qZbYZ8pV5iWza6IRl4XfzGTE1qpkZmEjPU9eyo0yvYw== +"@sentry/utils@7.117.0": + version "7.117.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.117.0.tgz#ac367a6f623bd09440b39d947437009c0ffe52b2" + integrity sha512-KkcLY8643SGBiDyPvMQOubBkwVX5IPknMHInc7jYC8pDVncGp7C65Wi506bCNPpKCWspUd/0VDNWOOen51/qKA== dependencies: - "@sentry/types" "7.113.0" + "@sentry/types" "7.117.0" "@sentry/utils@7.76.0": version "7.76.0" @@ -12955,7 +12955,7 @@ string-length@^5.0.1: char-regex "^2.0.0" strip-ansi "^7.0.1" -"string-width-cjs@npm:string-width@^4.2.0": +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -12973,15 +12973,6 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" @@ -13133,7 +13124,7 @@ stringify-object@^3.2.1: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -13168,13 +13159,6 @@ strip-ansi@^6.0.0: dependencies: ansi-regex "^5.0.0" -strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -14170,7 +14154,7 @@ word-wrap@^1.2.3, word-wrap@~1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -14188,15 +14172,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" From c00f96ac3f89cf834a9f83d3addfc8ee0ab31438 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Mon, 17 Jun 2024 13:47:37 +0000 Subject: [PATCH 19/23] release: 5.24.0 --- CHANGELOG.md | 2 +- package.json | 2 +- samples/expo/app.json | 6 +++--- samples/expo/package.json | 2 +- samples/react-native/android/app/build.gradle | 4 ++-- samples/react-native/ios/sentryreactnativesample/Info.plist | 4 ++-- .../ios/sentryreactnativesampleTests/Info.plist | 4 ++-- samples/react-native/package.json | 2 +- src/js/version.ts | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77599e9080..36e4256dc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## Unreleased +## 5.24.0 ### Features diff --git a/package.json b/package.json index 59fa39584f..24b110ef17 100644 --- a/package.json +++ b/package.json @@ -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.23.1", + "version": "5.24.0", "description": "Official Sentry SDK for react-native", "typings": "dist/js/index.d.ts", "types": "dist/js/index.d.ts", diff --git a/samples/expo/app.json b/samples/expo/app.json index 6f1f8dc31e..2a78d85622 100644 --- a/samples/expo/app.json +++ b/samples/expo/app.json @@ -4,7 +4,7 @@ "slug": "sentry-react-native-expo-sample", "jsEngine": "hermes", "scheme": "sentry-expo-sample", - "version": "5.23.1", + "version": "5.24.0", "orientation": "portrait", "icon": "./assets/icon.png", "userInterfaceStyle": "light", @@ -19,7 +19,7 @@ "ios": { "supportsTablet": true, "bundleIdentifier": "io.sentry.expo.sample", - "buildNumber": "9" + "buildNumber": "10" }, "android": { "adaptiveIcon": { @@ -27,7 +27,7 @@ "backgroundColor": "#ffffff" }, "package": "io.sentry.expo.sample", - "versionCode": 9 + "versionCode": 10 }, "web": { "bundler": "metro", diff --git a/samples/expo/package.json b/samples/expo/package.json index b6f72a1234..33ddac8db8 100644 --- a/samples/expo/package.json +++ b/samples/expo/package.json @@ -1,6 +1,6 @@ { "name": "sentry-react-native-expo-sample", - "version": "5.23.1", + "version": "5.24.0", "main": "expo-router/entry", "scripts": { "start": "expo start", diff --git a/samples/react-native/android/app/build.gradle b/samples/react-native/android/app/build.gradle index d44e636d9f..34d4746754 100644 --- a/samples/react-native/android/app/build.gradle +++ b/samples/react-native/android/app/build.gradle @@ -134,8 +134,8 @@ android { applicationId "io.sentry.reactnative.sample" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 16 - versionName "5.23.1" + versionCode 17 + versionName "5.24.0" } signingConfigs { diff --git a/samples/react-native/ios/sentryreactnativesample/Info.plist b/samples/react-native/ios/sentryreactnativesample/Info.plist index e518440c38..aff21d5781 100644 --- a/samples/react-native/ios/sentryreactnativesample/Info.plist +++ b/samples/react-native/ios/sentryreactnativesample/Info.plist @@ -17,11 +17,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 5.23.1 + 5.24.0 CFBundleSignature ???? CFBundleVersion - 16 + 17 LSRequiresIPhoneOS NSAppTransportSecurity diff --git a/samples/react-native/ios/sentryreactnativesampleTests/Info.plist b/samples/react-native/ios/sentryreactnativesampleTests/Info.plist index c2535824a3..2e556bc4be 100644 --- a/samples/react-native/ios/sentryreactnativesampleTests/Info.plist +++ b/samples/react-native/ios/sentryreactnativesampleTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 5.23.1 + 5.24.0 CFBundleSignature ???? CFBundleVersion - 16 + 17 diff --git a/samples/react-native/package.json b/samples/react-native/package.json index 6138220c4f..c90a691c46 100644 --- a/samples/react-native/package.json +++ b/samples/react-native/package.json @@ -1,6 +1,6 @@ { "name": "sentry-react-native-sample", - "version": "5.23.1", + "version": "5.24.0", "private": true, "scripts": { "postinstall": "patch-package", diff --git a/src/js/version.ts b/src/js/version.ts index 953fed74ac..f5f3daa25e 100644 --- a/src/js/version.ts +++ b/src/js/version.ts @@ -1,3 +1,3 @@ export const SDK_PACKAGE_NAME = 'npm:@sentry/react-native'; export const SDK_NAME = 'sentry.javascript.react-native'; -export const SDK_VERSION = '5.23.1'; +export const SDK_VERSION = '5.24.0'; From d6c19001c79bbb20c820822a6c1e49dace4a2255 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Mon, 17 Jun 2024 15:55:33 +0200 Subject: [PATCH 20/23] fix(ci): Remove JS V8 dropped packages from the update CI (#3894) * fix(ci): Remove JS V8 dropped packages from the update CI * remove tmp --- scripts/update-javascript.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update-javascript.sh b/scripts/update-javascript.sh index ca464d280f..a9cd10b23a 100755 --- a/scripts/update-javascript.sh +++ b/scripts/update-javascript.sh @@ -3,7 +3,7 @@ set -euo pipefail tagPrefix='' repo="https://github.com/getsentry/sentry-javascript.git" -packages=('@sentry/browser' '@sentry/core' '@sentry/hub' '@sentry/integrations' '@sentry/react' '@sentry/types' '@sentry/utils' '@sentry-internal/typescript') +packages=('@sentry/browser' '@sentry/core' '@sentry/react' '@sentry/types' '@sentry/utils' '@sentry-internal/typescript') packages+=('@sentry-internal/eslint-config-sdk' '@sentry-internal/eslint-plugin-sdk') . $(dirname "$0")/update-package-json.sh From 95cfe1f50b6d33ce5642687a714b34daaf5f4a2c Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Mon, 17 Jun 2024 16:41:39 +0200 Subject: [PATCH 21/23] fix(performance): app start frames can start with zeroed values (#3881) --- CHANGELOG.md | 6 ++ .../io/sentry/react/RNSentryModuleImpl.java | 5 -- ios/RNSentry.mm | 6 -- src/js/tracing/nativeframes.ts | 11 +++ test/tracing/nativeframes.test.ts | 74 +++++++++++++++++++ 5 files changed, 91 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36e4256dc0..21c34c634b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fixes + +- App Start Native Frames can start with zeroed values ([#3881](https://github.com/getsentry/sentry-react-native/pull/3881)) + ## 5.24.0 ### Features diff --git a/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java b/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java index 9b9195d4dd..b73bf6a753 100644 --- a/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java +++ b/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java @@ -381,11 +381,6 @@ public void fetchNativeFrames(Promise promise) { } } - if (totalFrames == 0 && slowFrames == 0 && frozenFrames == 0) { - promise.resolve(null); - return; - } - WritableMap map = Arguments.createMap(); map.putInt("totalFrames", totalFrames); map.putInt("slowFrames", slowFrames); diff --git a/ios/RNSentry.mm b/ios/RNSentry.mm index 1ae62f71e8..8c774ddbb7 100644 --- a/ios/RNSentry.mm +++ b/ios/RNSentry.mm @@ -415,12 +415,6 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray*)instructionsAdd NSNumber *total = [NSNumber numberWithLong:frames.total]; NSNumber *frozen = [NSNumber numberWithLong:frames.frozen]; NSNumber *slow = [NSNumber numberWithLong:frames.slow]; - NSNumber *zero = [NSNumber numberWithLong:0L]; - - if ([total isEqualToNumber:zero] && [frozen isEqualToNumber:zero] && [slow isEqualToNumber:zero]) { - resolve(nil); - return; - } resolve(@{ @"totalFrames": total, diff --git a/src/js/tracing/nativeframes.ts b/src/js/tracing/nativeframes.ts index 6174091f60..9f6e441563 100644 --- a/src/js/tracing/nativeframes.ts +++ b/src/js/tracing/nativeframes.ts @@ -192,6 +192,17 @@ export class NativeFramesInstrumentation { }, }; + if ( + measurements.frames_frozen.value <= 0 && + measurements.frames_slow.value <= 0 && + measurements.frames_total.value <= 0 + ) { + logger.warn( + `[NativeFrames] Detected zero slow or frozen frames. Not adding measurements to traceId (${traceId}).`, + ); + return null; + } + return measurements; } diff --git a/test/tracing/nativeframes.test.ts b/test/tracing/nativeframes.test.ts index 821e92d94e..402fd8a330 100644 --- a/test/tracing/nativeframes.test.ts +++ b/test/tracing/nativeframes.test.ts @@ -98,6 +98,80 @@ describe('NativeFramesInstrumentation', () => { ); }); + it('sets native frames measurements on a transaction event (start frames zero)', async () => { + const startFrames = { + totalFrames: 0, + slowFrames: 0, + frozenFrames: 0, + }; + const finishFrames = { + totalFrames: 100, + slowFrames: 20, + frozenFrames: 5, + }; + mockFunction(NATIVE.fetchNativeFrames).mockResolvedValueOnce(startFrames).mockResolvedValueOnce(finishFrames); + + await startSpan({ name: 'test' }, async () => { + await Promise.resolve(); // native frames fetch is async call this will flush the start frames fetch promise + }); + + await jest.runOnlyPendingTimersAsync(); + await client.flush(); + + expect(client.event!).toEqual( + expect.objectContaining>({ + measurements: expect.objectContaining({ + frames_total: { + value: 100, + unit: 'none', + }, + frames_slow: { + value: 20, + unit: 'none', + }, + frames_frozen: { + value: 5, + unit: 'none', + }, + }), + }), + ); + }); + + it('does not sent zero value native frames measurements', async () => { + const startFrames = { + totalFrames: 100, + slowFrames: 20, + frozenFrames: 5, + }; + const finishFrames = { + totalFrames: 100, + slowFrames: 20, + frozenFrames: 5, + }; + mockFunction(NATIVE.fetchNativeFrames).mockResolvedValueOnce(startFrames).mockResolvedValueOnce(finishFrames); + + await startSpan({ name: 'test' }, async () => { + await Promise.resolve(); // native frames fetch is async call this will flush the start frames fetch promise + }); + + await jest.runOnlyPendingTimersAsync(); + await client.flush(); + + expect(client.event!).toEqual( + expect.objectContaining>({ + measurements: expect.toBeOneOf([ + expect.not.objectContaining({ + frames_total: expect.any(Object), + frames_slow: expect.any(Object), + frames_frozen: expect.any(Object), + }), + undefined, + ]), + }), + ); + }); + it('does not set measurements on transactions without startFrames', async () => { const startFrames = null; const finishFrames = { From c398f670f92b4271a2da58363ef9b1d567162273 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 16:47:54 +0200 Subject: [PATCH 22/23] chore(deps): update Cocoa SDK to v8.29.0 (#3890) Co-authored-by: GitHub --- CHANGELOG.md | 6 ++++++ RNSentry.podspec | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21c34c634b..04fd9ddbec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ - App Start Native Frames can start with zeroed values ([#3881](https://github.com/getsentry/sentry-react-native/pull/3881)) +### Dependencies + +- Bump Cocoa SDK from v8.28.0 to v8.29.1 ([#3890](https://github.com/getsentry/sentry-react-native/pull/3890)) + - [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8291) + - [diff](https://github.com/getsentry/sentry-cocoa/compare/8.28.0...8.29.1) + ## 5.24.0 ### Features diff --git a/RNSentry.podspec b/RNSentry.podspec index fc7c319313..c0bc242be2 100644 --- a/RNSentry.podspec +++ b/RNSentry.podspec @@ -33,7 +33,7 @@ Pod::Spec.new do |s| s.preserve_paths = '*.js' s.dependency 'React-Core' - s.dependency 'Sentry/HybridSDK', '8.28.0' + s.dependency 'Sentry/HybridSDK', '8.29.1' s.source_files = 'ios/**/*.{h,m,mm}' s.public_header_files = 'ios/RNSentry.h' From e31963ff1aaf91c3607f5c380c6c550c707361d2 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 18 Jun 2024 08:03:20 +0000 Subject: [PATCH 23/23] release: 5.24.1 --- CHANGELOG.md | 2 +- package.json | 2 +- samples/expo/app.json | 6 +++--- samples/expo/package.json | 2 +- samples/react-native/android/app/build.gradle | 4 ++-- samples/react-native/ios/sentryreactnativesample/Info.plist | 4 ++-- .../ios/sentryreactnativesampleTests/Info.plist | 4 ++-- samples/react-native/package.json | 2 +- src/js/version.ts | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04fd9ddbec..c2e7f8902a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## Unreleased +## 5.24.1 ### Fixes diff --git a/package.json b/package.json index 24b110ef17..11a1309f0e 100644 --- a/package.json +++ b/package.json @@ -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.24.0", + "version": "5.24.1", "description": "Official Sentry SDK for react-native", "typings": "dist/js/index.d.ts", "types": "dist/js/index.d.ts", diff --git a/samples/expo/app.json b/samples/expo/app.json index 2a78d85622..7486e307e0 100644 --- a/samples/expo/app.json +++ b/samples/expo/app.json @@ -4,7 +4,7 @@ "slug": "sentry-react-native-expo-sample", "jsEngine": "hermes", "scheme": "sentry-expo-sample", - "version": "5.24.0", + "version": "5.24.1", "orientation": "portrait", "icon": "./assets/icon.png", "userInterfaceStyle": "light", @@ -19,7 +19,7 @@ "ios": { "supportsTablet": true, "bundleIdentifier": "io.sentry.expo.sample", - "buildNumber": "10" + "buildNumber": "11" }, "android": { "adaptiveIcon": { @@ -27,7 +27,7 @@ "backgroundColor": "#ffffff" }, "package": "io.sentry.expo.sample", - "versionCode": 10 + "versionCode": 11 }, "web": { "bundler": "metro", diff --git a/samples/expo/package.json b/samples/expo/package.json index 33ddac8db8..c5a3506800 100644 --- a/samples/expo/package.json +++ b/samples/expo/package.json @@ -1,6 +1,6 @@ { "name": "sentry-react-native-expo-sample", - "version": "5.24.0", + "version": "5.24.1", "main": "expo-router/entry", "scripts": { "start": "expo start", diff --git a/samples/react-native/android/app/build.gradle b/samples/react-native/android/app/build.gradle index 34d4746754..3f8097f0a5 100644 --- a/samples/react-native/android/app/build.gradle +++ b/samples/react-native/android/app/build.gradle @@ -134,8 +134,8 @@ android { applicationId "io.sentry.reactnative.sample" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 17 - versionName "5.24.0" + versionCode 18 + versionName "5.24.1" } signingConfigs { diff --git a/samples/react-native/ios/sentryreactnativesample/Info.plist b/samples/react-native/ios/sentryreactnativesample/Info.plist index aff21d5781..7e2aa7d9d2 100644 --- a/samples/react-native/ios/sentryreactnativesample/Info.plist +++ b/samples/react-native/ios/sentryreactnativesample/Info.plist @@ -17,11 +17,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 5.24.0 + 5.24.1 CFBundleSignature ???? CFBundleVersion - 17 + 18 LSRequiresIPhoneOS NSAppTransportSecurity diff --git a/samples/react-native/ios/sentryreactnativesampleTests/Info.plist b/samples/react-native/ios/sentryreactnativesampleTests/Info.plist index 2e556bc4be..795471a3bc 100644 --- a/samples/react-native/ios/sentryreactnativesampleTests/Info.plist +++ b/samples/react-native/ios/sentryreactnativesampleTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 5.24.0 + 5.24.1 CFBundleSignature ???? CFBundleVersion - 17 + 18 diff --git a/samples/react-native/package.json b/samples/react-native/package.json index c90a691c46..1f58d11bc0 100644 --- a/samples/react-native/package.json +++ b/samples/react-native/package.json @@ -1,6 +1,6 @@ { "name": "sentry-react-native-sample", - "version": "5.24.0", + "version": "5.24.1", "private": true, "scripts": { "postinstall": "patch-package", diff --git a/src/js/version.ts b/src/js/version.ts index f5f3daa25e..0a6b53b2ab 100644 --- a/src/js/version.ts +++ b/src/js/version.ts @@ -1,3 +1,3 @@ export const SDK_PACKAGE_NAME = 'npm:@sentry/react-native'; export const SDK_NAME = 'sentry.javascript.react-native'; -export const SDK_VERSION = '5.24.0'; +export const SDK_VERSION = '5.24.1';