From 92ca1e3704df8778ae59ca205e058217437045e3 Mon Sep 17 00:00:00 2001 From: Avinash Lingaloo Date: Wed, 21 Dec 2022 21:34:44 +0400 Subject: [PATCH] Sentry fixes (#6830) --- app/init/push_notifications.ts | 4 +- app/screens/sso/sso_with_redirect_url.tsx | 4 +- app/utils/error_handling.ts | 6 ++- app/utils/general/index.ts | 3 ++ app/utils/sentry.ts | 23 ++++++++-- fastlane/Fastfile | 6 ++- ios/ErrorReporting/Sentry.swift | 27 +++++++++++ ios/Mattermost.xcodeproj/project.pbxproj | 45 +++++++++++++++++-- .../xcshareddata/swiftpm/Package.resolved | 9 ++++ ios/MattermostShare/Info.plist | 8 +++- ios/MattermostShare/ShareViewController.swift | 7 ++- ios/NotificationService/Info.plist | 4 ++ .../NotificationService.swift | 6 ++- 13 files changed, 135 insertions(+), 17 deletions(-) create mode 100644 ios/ErrorReporting/Sentry.swift diff --git a/app/init/push_notifications.ts b/app/init/push_notifications.ts index ec78be8f7e..14aac23155 100644 --- a/app/init/push_notifications.ts +++ b/app/init/push_notifications.ts @@ -2,7 +2,6 @@ // See LICENSE.txt for license information. import {AppState, DeviceEventEmitter, Platform} from 'react-native'; -import DeviceInfo from 'react-native-device-info'; import { Notification, NotificationAction, @@ -29,6 +28,7 @@ import {getIsCRTEnabled, getThreadById} from '@queries/servers/thread'; import {dismissOverlay, showOverlay} from '@screens/navigation'; import EphemeralStore from '@store/ephemeral_store'; import NavigationStore from '@store/navigation_store'; +import {isBetaApp} from '@utils/general'; import {isMainActivity, isTablet} from '@utils/helpers'; import {logInfo} from '@utils/log'; import {convertToNotificationData} from '@utils/notification'; @@ -248,7 +248,7 @@ class PushNotifications { if (Platform.OS === 'ios') { prefix = Device.PUSH_NOTIFY_APPLE_REACT_NATIVE; - if (DeviceInfo.getBundleId().includes('rnbeta')) { + if (isBetaApp) { prefix = `${prefix}beta`; } } else { diff --git a/app/screens/sso/sso_with_redirect_url.tsx b/app/screens/sso/sso_with_redirect_url.tsx index 30867c24de..5eb39f7a62 100644 --- a/app/screens/sso/sso_with_redirect_url.tsx +++ b/app/screens/sso/sso_with_redirect_url.tsx @@ -6,13 +6,13 @@ import React, {useEffect, useState} from 'react'; import {useIntl} from 'react-intl'; import {Linking, Platform, Text, View} from 'react-native'; import Button from 'react-native-button'; -import DeviceInfo from 'react-native-device-info'; import urlParse from 'url-parse'; import FormattedText from '@components/formatted_text'; import {Sso} from '@constants'; import NetworkManager from '@managers/network_manager'; import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles'; +import {isBetaApp} from '@utils/general'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; import {tryOpenURL} from '@utils/url'; @@ -62,7 +62,7 @@ const SSOWithRedirectURL = ({doSSOLogin, loginError, loginUrl, serverUrl, setLog const style = getStyleSheet(theme); const intl = useIntl(); let customUrlScheme = Sso.REDIRECT_URL_SCHEME; - if (DeviceInfo.getBundleId && DeviceInfo.getBundleId().includes('rnbeta')) { + if (isBetaApp) { customUrlScheme = Sso.REDIRECT_URL_SCHEME_DEV; } diff --git a/app/utils/error_handling.ts b/app/utils/error_handling.ts index 721a05b68b..2ac1145fda 100644 --- a/app/utils/error_handling.ts +++ b/app/utils/error_handling.ts @@ -11,6 +11,7 @@ import { import {DEFAULT_LOCALE, getTranslations, t} from '@i18n'; import {dismissAllModals} from '@screens/navigation'; import {ClientError} from '@utils/client_error'; +import {isBetaApp} from '@utils/general'; import { captureException, captureJSException, @@ -42,7 +43,10 @@ class JavascriptAndNativeErrorHandler { } logWarning('Handling Javascript error', e, isFatal); - captureJSException(e, isFatal); + + if (isBetaApp || isFatal) { + captureJSException(e, isFatal); + } if (isFatal && e instanceof Error) { const translations = getTranslations(DEFAULT_LOCALE); diff --git a/app/utils/general/index.ts b/app/utils/general/index.ts index 60bc8d2793..1a29fa1ba1 100644 --- a/app/utils/general/index.ts +++ b/app/utils/general/index.ts @@ -1,6 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import DeviceInfo from 'react-native-device-info'; import ReactNativeHapticFeedback, {HapticFeedbackTypes} from 'react-native-haptic-feedback'; type SortByCreatAt = (Session | Channel | Team | Post) & { @@ -51,3 +52,5 @@ export const sortByNewest = (a: SortByCreatAt, b: SortByCreatAt) => { return 1; }; + +export const isBetaApp = DeviceInfo.getBundleId && DeviceInfo.getBundleId().includes('rnbeta'); diff --git a/app/utils/sentry.ts b/app/utils/sentry.ts index cf071c10b3..44b5e7bb99 100644 --- a/app/utils/sentry.ts +++ b/app/utils/sentry.ts @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import {Database} from '@nozbe/watermelondb'; -import {Breadcrumb} from '@sentry/types'; +import {Breadcrumb, Event} from '@sentry/types'; import {Platform} from 'react-native'; import {Navigation} from 'react-native-navigation'; @@ -10,6 +10,7 @@ import Config from '@assets/config.json'; import DatabaseManager from '@database/manager'; import {getConfig} from '@queries/servers/system'; import {getCurrentUser} from '@queries/servers/user'; +import {isBetaApp} from '@utils/general'; import {ClientError} from './client_error'; import {logError, logWarning} from './log'; @@ -39,9 +40,18 @@ export function initializeSentry() { return; } + const mmConfig = { + environment: isBetaApp ? 'beta' : 'production', + tracesSampleRate: isBetaApp ? 1.0 : 0.2, + sampleRate: isBetaApp ? 1.0 : 0.2, + attachStacktrace: isBetaApp, // For Beta, stack traces are automatically attached to all messages logged + }; + Sentry.init({ dsn, - tracesSampleRate: 0.2, + sendDefaultPii: false, + ...mmConfig, + ...Config.SentryOptions, integrations: [ new Sentry.ReactNativeTracing({ @@ -51,8 +61,13 @@ export function initializeSentry() { ), }), ], - sendDefaultPii: false, - ...Config.SentryOptions, + beforeSend: (event: Event) => { + if (isBetaApp || event?.level === 'fatal') { + return event; + } + + return null; + }, }); } diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 3fad4a6b8d..7e281fb267 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -568,6 +568,9 @@ platform :ios do app_name_sub = app_name.gsub(" ", "_") config_mode = ENV['BUILD_FOR_RELEASE'] == 'true' ? 'Release' : 'Debug' method = ENV['IOS_BUILD_EXPORT_METHOD'].nil? || ENV['IOS_BUILD_EXPORT_METHOD'].empty? ? 'ad-hoc' : ENV['IOS_BUILD_EXPORT_METHOD'] + + # Need to add xcargs to only notification and + xcargs = ENV['SENTRY_ENABLED'] == 'true' ? "SENTRY_DSN_IOS='#{ENV['SENTRY_DSN_IOS']}' SENTRY_ENABLED='#{ENV['SENTRY_ENABLED']}'" : '' setup_code_signing @@ -583,7 +586,8 @@ platform :ios do export_options: { signingStyle: 'manual', iCloudContainerEnvironment: 'Production' - } + }, + xcargs:xcargs ) end diff --git a/ios/ErrorReporting/Sentry.swift b/ios/ErrorReporting/Sentry.swift new file mode 100644 index 0000000000..71b8def203 --- /dev/null +++ b/ios/ErrorReporting/Sentry.swift @@ -0,0 +1,27 @@ +// +// Sentry.swift +// Mattermost +// +// Created by Avinash Lingaloo on 20/12/2022. +// Copyright © 2022 Facebook. All rights reserved. +// +import Foundation + +import Sentry + +func initSentryAppExt(){ + if let SENTRY_ENABLED = Bundle.main.infoDictionary?["SENTRY_ENABLED"] as? String, + let SENTRY_DSN = Bundle.main.infoDictionary?["SENTRY_DSN_IOS"] as? String { + if(SENTRY_ENABLED=="true"){ + SentrySDK.start { options in + options.dsn = SENTRY_DSN + options.enableAppHangTracking = true + options.enableCaptureFailedRequests = true + } + } + } +} + +func testSentry(msg: String){ + SentrySDK.capture(message: msg) +} diff --git a/ios/Mattermost.xcodeproj/project.pbxproj b/ios/Mattermost.xcodeproj/project.pbxproj index 02f0ef2c02..11feef5184 100644 --- a/ios/Mattermost.xcodeproj/project.pbxproj +++ b/ios/Mattermost.xcodeproj/project.pbxproj @@ -11,6 +11,10 @@ 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; + 27C667A329523ECA00E590D5 /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 27C667A229523ECA00E590D5 /* Sentry */; }; + 27C667A529523F0A00E590D5 /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 27C667A429523F0A00E590D5 /* Sentry */; }; + 27C667A9295241B600E590D5 /* Sentry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27C667A8295241B600E590D5 /* Sentry.swift */; }; + 27C667AA295241B600E590D5 /* Sentry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27C667A8295241B600E590D5 /* Sentry.swift */; }; 49AE370126D4455D00EF4E52 /* Gekidou in Frameworks */ = {isa = PBXBuildFile; productRef = 49AE370026D4455D00EF4E52 /* Gekidou */; }; 536CC6C323E79287002C478C /* RNNotificationEventHandler+HandleReplyAction.m in Sources */ = {isa = PBXBuildFile; fileRef = 536CC6C123E79287002C478C /* RNNotificationEventHandler+HandleReplyAction.m */; }; 58495E36BF1A4EAB93609E57 /* Metropolis-SemiBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 54956DEFEBB74EF78C3A6AE5 /* Metropolis-SemiBold.ttf */; }; @@ -156,6 +160,7 @@ 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Mattermost/main.m; sourceTree = ""; }; 182D203F539AF68F1647EFAF /* Pods-Mattermost-MattermostTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mattermost-MattermostTests.release.xcconfig"; path = "Target Support Files/Pods-Mattermost-MattermostTests/Pods-Mattermost-MattermostTests.release.xcconfig"; sourceTree = ""; }; 25BF2BACE89201DE6E585B7E /* Pods-Mattermost.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mattermost.release.xcconfig"; path = "Target Support Files/Pods-Mattermost/Pods-Mattermost.release.xcconfig"; sourceTree = ""; }; + 27C667A8295241B600E590D5 /* Sentry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sentry.swift; sourceTree = ""; }; 297AAFCCF0BD99FC109DA2BC /* Pods-MattermostTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MattermostTests.release.xcconfig"; path = "Target Support Files/Pods-MattermostTests/Pods-MattermostTests.release.xcconfig"; sourceTree = ""; }; 32AC3D4EA79E44738A6E9766 /* OpenSans-BoldItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "OpenSans-BoldItalic.ttf"; path = "../assets/fonts/OpenSans-BoldItalic.ttf"; sourceTree = ""; }; 3647DF63D6764CF093375861 /* OpenSans-ExtraBold.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "OpenSans-ExtraBold.ttf"; path = "../assets/fonts/OpenSans-ExtraBold.ttf"; sourceTree = ""; }; @@ -279,6 +284,7 @@ buildActionMask = 2147483647; files = ( 49AE370126D4455D00EF4E52 /* Gekidou in Frameworks */, + 27C667A329523ECA00E590D5 /* Sentry in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -288,6 +294,7 @@ files = ( 7FD4822C2864D73300A5B18B /* OpenGraph in Frameworks */, 7F4288042865D340006B48E1 /* Gekidou in Frameworks */, + 27C667A529523F0A00E590D5 /* Sentry in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -352,6 +359,14 @@ name = Mattermost; sourceTree = ""; }; + 27C667AB2952425700E590D5 /* ErrorReporting */ = { + isa = PBXGroup; + children = ( + 27C667A8295241B600E590D5 /* Sentry.swift */, + ); + path = ErrorReporting; + sourceTree = ""; + }; 33E107B4DC21A5C48B09F800 /* Pods */ = { isa = PBXGroup; children = ( @@ -625,6 +640,7 @@ 83CBB9F61A601CBA00E9B192 = { isa = PBXGroup; children = ( + 27C667AB2952425700E590D5 /* ErrorReporting */, 13B07FAE1A68108700A75B9A /* Mattermost */, 7F581D33221ED5C60099E66B /* NotificationService */, 7F292A701E8AB73400A450A3 /* SplashScreenResource */, @@ -698,6 +714,7 @@ name = NotificationService; packageProductDependencies = ( 49AE370026D4455D00EF4E52 /* Gekidou */, + 27C667A229523ECA00E590D5 /* Sentry */, ); productName = NotificationService; productReference = 7F581D32221ED5C60099E66B /* NotificationService.appex */; @@ -719,6 +736,7 @@ packageProductDependencies = ( 7FD4822B2864D73300A5B18B /* OpenGraph */, 7F4288032865D340006B48E1 /* Gekidou */, + 27C667A429523F0A00E590D5 /* Sentry */, ); productName = MattermostShare; productReference = 7FC5698628563FDB000B0905 /* MattermostShare.appex */; @@ -782,7 +800,8 @@ ); mainGroup = 83CBB9F61A601CBA00E9B192; packageReferences = ( - 7FD4822A2864D73300A5B18B /* XCRemoteSwiftPackageReference "OpenGraph.git" */, + 7FD4822A2864D73300A5B18B /* XCRemoteSwiftPackageReference "OpenGraph" */, + 27C667A129523ECA00E590D5 /* XCRemoteSwiftPackageReference "sentry-cocoa" */, ); productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; projectDirPath = ""; @@ -1005,6 +1024,7 @@ buildActionMask = 2147483647; files = ( 7F581D35221ED5C60099E66B /* NotificationService.swift in Sources */, + 27C667A9295241B600E590D5 /* Sentry.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1021,6 +1041,7 @@ 7F93AAB8287778090047B89F /* Publishers.swift in Sources */, 7F7E9F732864E8060064BFAF /* CompassIcons.swift in Sources */, 7F93AABA28777A390047B89F /* Notification.swift in Sources */, + 27C667AA295241B600E590D5 /* Sentry.swift in Sources */, 7FA9A9902868BD8800AB35A1 /* LocalFileManager.swift in Sources */, 7F93AA9E2875FD310047B89F /* CancelButton.swift in Sources */, 7F42880A286672F6006B48E1 /* ServerService.swift in Sources */, @@ -1502,7 +1523,15 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 7FD4822A2864D73300A5B18B /* XCRemoteSwiftPackageReference "OpenGraph.git" */ = { + 27C667A129523ECA00E590D5 /* XCRemoteSwiftPackageReference "sentry-cocoa" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/getsentry/sentry-cocoa.git"; + requirement = { + branch = 8.0.0; + kind = branch; + }; + }; + 7FD4822A2864D73300A5B18B /* XCRemoteSwiftPackageReference "OpenGraph" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/satoshi-takano/OpenGraph.git"; requirement = { @@ -1513,6 +1542,16 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 27C667A229523ECA00E590D5 /* Sentry */ = { + isa = XCSwiftPackageProductDependency; + package = 27C667A129523ECA00E590D5 /* XCRemoteSwiftPackageReference "sentry-cocoa" */; + productName = Sentry; + }; + 27C667A429523F0A00E590D5 /* Sentry */ = { + isa = XCSwiftPackageProductDependency; + package = 27C667A129523ECA00E590D5 /* XCRemoteSwiftPackageReference "sentry-cocoa" */; + productName = Sentry; + }; 49AE370026D4455D00EF4E52 /* Gekidou */ = { isa = XCSwiftPackageProductDependency; productName = Gekidou; @@ -1527,7 +1566,7 @@ }; 7FD4822B2864D73300A5B18B /* OpenGraph */ = { isa = XCSwiftPackageProductDependency; - package = 7FD4822A2864D73300A5B18B /* XCRemoteSwiftPackageReference "OpenGraph.git" */; + package = 7FD4822A2864D73300A5B18B /* XCRemoteSwiftPackageReference "OpenGraph" */; productName = OpenGraph; }; /* End XCSwiftPackageProductDependency section */ diff --git a/ios/Mattermost.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/Mattermost.xcworkspace/xcshareddata/swiftpm/Package.resolved index 72a8937d2e..edc1406c88 100644 --- a/ios/Mattermost.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ios/Mattermost.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -10,6 +10,15 @@ "version": "1.4.1" } }, + { + "package": "Sentry", + "repositoryURL": "https://github.com/getsentry/sentry-cocoa.git", + "state": { + "branch": "8.0.0", + "revision": "1a18683901844a2970ccfb633e4ebae565361817", + "version": null + } + }, { "package": "SQLite.swift", "repositoryURL": "https://github.com/stephencelis/SQLite.swift.git", diff --git a/ios/MattermostShare/Info.plist b/ios/MattermostShare/Info.plist index d738e7e41d..814d39d4c0 100644 --- a/ios/MattermostShare/Info.plist +++ b/ios/MattermostShare/Info.plist @@ -50,8 +50,8 @@ NSExtensionActivationRule - NSExtensionActivationDictionaryVersion - 2 + NSExtensionActivationDictionaryVersion + 2 NSExtensionActivationSupportsAttachmentsWithMaxCount 10 NSExtensionActivationSupportsFileWithMaxCount @@ -73,5 +73,9 @@ NSExtensionPointIdentifier com.apple.share-services + SENTRY_DSN_IOS + $(SENTRY_DSN_IOS) + SENTRY_ENABLED + $(SENTRY_ENABLED) diff --git a/ios/MattermostShare/ShareViewController.swift b/ios/MattermostShare/ShareViewController.swift index f7e0cc8d58..e70489dd1a 100644 --- a/ios/MattermostShare/ShareViewController.swift +++ b/ios/MattermostShare/ShareViewController.swift @@ -10,6 +10,7 @@ import Gekidou import SwiftUI import UIKit import os.log +import Sentry class ShareViewController: UIViewController { private var fileManager: LocalFileManager? @@ -20,7 +21,6 @@ class ShareViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() self.isModalInPresentation = true - self.addObservers() fileManager = LocalFileManager() if let inputItems = extensionContext?.inputItems { @@ -34,6 +34,9 @@ class ShareViewController: UIViewController { ) }) } + + // Initialize Sentry + initSentryAppExt() } override func viewDidAppear(_ animated: Bool) { @@ -94,6 +97,8 @@ class ShareViewController: UIViewController { let fileCount = attachments.count let files: [String] = attachments.map{ $0.fileUrl.absoluteString } + + var message = text if linkPreviewUrl != nil && !linkPreviewUrl!.isEmpty { if text.isEmpty { diff --git a/ios/NotificationService/Info.plist b/ios/NotificationService/Info.plist index 09ec58b325..9e2224e0aa 100644 --- a/ios/NotificationService/Info.plist +++ b/ios/NotificationService/Info.plist @@ -29,5 +29,9 @@ NSExtensionPrincipalClass $(PRODUCT_MODULE_NAME).NotificationService + SENTRY_DSN_IOS + $(SENTRY_DSN_IOS) + SENTRY_ENABLED + $(SENTRY_ENABLED) diff --git a/ios/NotificationService/NotificationService.swift b/ios/NotificationService/NotificationService.swift index 88d4078316..9f0810ffac 100644 --- a/ios/NotificationService/NotificationService.swift +++ b/ios/NotificationService/NotificationService.swift @@ -9,6 +9,11 @@ class NotificationService: UNNotificationServiceExtension { var retryIndex = 0 + override init() { + super.init() + initSentryAppExt() + } + override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler @@ -24,7 +29,6 @@ class NotificationService: UNNotificationServiceExtension { func processResponse(serverUrl: String, data: Data, bestAttemptContent: UNMutableNotificationContent, contentHandler: ((UNNotificationContent) -> Void)?) { bestAttemptContent.userInfo["server_url"] = serverUrl - let json = try? JSONSerialization.jsonObject(with: data) as! [String: Any] if let json = json { if let message = json["message"] as? String {