Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Sentry & Remove Firebase{Crashlytics, Analytics} #854

Merged
merged 1 commit into from
Aug 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
130 changes: 6 additions & 124 deletions HomeAssistant.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@
B6CC5D982159D10E00833E5D /* ComplicationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6CC5D972159D10E00833E5D /* ComplicationController.swift */; };
B6CC5D9A2159D10F00833E5D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B6CC5D992159D10F00833E5D /* Assets.xcassets */; };
B6CC5D9E2159D10F00833E5D /* WatchApp.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = B6CC5D822159D10D00833E5D /* WatchApp.app */; };
B6CC96D624B0097500CE53ED /* CrashlyticsLogDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6CC96D524B0097500CE53ED /* CrashlyticsLogDestination.swift */; };
B6CC96D624B0097500CE53ED /* SentryLogDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6CC96D524B0097500CE53ED /* SentryLogDestination.swift */; };
B6CDC096228CF5C2009355DD /* RemoteMediaPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6CDC095228CF5C2009355DD /* RemoteMediaPlayer.swift */; };
B6D3B4ED225B26900082BB4F /* SensorContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6D3B4EB225B26300082BB4F /* SensorContainer.swift */; };
B6D3B4EE225B26910082BB4F /* SensorContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6D3B4EB225B26300082BB4F /* SensorContainer.swift */; };
Expand Down Expand Up @@ -1266,7 +1266,7 @@
B6CC5D9B2159D10F00833E5D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
B6CC5DA72159D14B00833E5D /* WatchApp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WatchApp.entitlements; sourceTree = "<group>"; };
B6CC5DA82159D15700833E5D /* WatchAppExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WatchAppExtension.entitlements; sourceTree = "<group>"; };
B6CC96D524B0097500CE53ED /* CrashlyticsLogDestination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashlyticsLogDestination.swift; sourceTree = "<group>"; };
B6CC96D524B0097500CE53ED /* SentryLogDestination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryLogDestination.swift; sourceTree = "<group>"; };
B6CDC095228CF5C2009355DD /* RemoteMediaPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteMediaPlayer.swift; sourceTree = "<group>"; };
B6D35C632169905400D1F86B /* HomeAssistant Development.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = "HomeAssistant Development.entitlements"; sourceTree = "<group>"; };
B6D35C652169906A00D1F86B /* APNSAttachmentService Development.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = "APNSAttachmentService Development.entitlements"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2138,7 +2138,7 @@
1100D51C2496AECE00B1073C /* PermissionStatusRow.swift */,
B6DD5E6924940F6F003A0154 /* OpenInFirefoxControllerSwift.swift */,
117D8A0724A9347F00580913 /* UIColor+CSSRGB.swift */,
B6CC96D524B0097500CE53ED /* CrashlyticsLogDestination.swift */,
B6CC96D524B0097500CE53ED /* SentryLogDestination.swift */,
);
path = Utilities;
sourceTree = "<group>";
Expand Down Expand Up @@ -2567,7 +2567,6 @@
B627CB031D83C87B0057173E /* Sources */,
B627CB041D83C87B0057173E /* Frameworks */,
B627CB051D83C87B0057173E /* Resources */,
B6624E4622584CEF00354CDF /* Crashlytics */,
);
buildRules = (
);
Expand Down Expand Up @@ -2595,7 +2594,6 @@
B6CC5DA62159D10F00833E5D /* Embed Watch Content */,
9C08D123229F187E001B4F73 /* Enable Critical Alerts */,
8A763BD9E9F25F0704269545 /* [CP] Embed Pods Frameworks */,
B6624E4122584AD500354CDF /* Crashlytics */,
);
buildRules = (
);
Expand Down Expand Up @@ -2658,7 +2656,6 @@
B66C58A1215086F0004AB261 /* Sources */,
B66C58A2215086F0004AB261 /* Frameworks */,
B66C58A3215086F0004AB261 /* Resources */,
B6624E4722584CFF00354CDF /* Crashlytics */,
);
buildRules = (
);
Expand All @@ -2677,7 +2674,6 @@
B66F9F1E216B1E61000CAA0F /* Sources */,
B66F9F1F216B1E61000CAA0F /* Frameworks */,
B66F9F20216B1E61000CAA0F /* Resources */,
B6624E4822584D1B00354CDF /* Crashlytics */,
);
buildRules = (
);
Expand Down Expand Up @@ -2715,7 +2711,6 @@
B6AAD79D1D827DD40090B220 /* Sources */,
B6AAD79E1D827DD40090B220 /* Frameworks */,
B6AAD79F1D827DD40090B220 /* Resources */,
B6624E4522584CCE00354CDF /* Crashlytics */,
);
buildRules = (
);
Expand Down Expand Up @@ -2774,7 +2769,6 @@
D03D891320E0A85200D4F28D /* Frameworks */,
D03D891420E0A85200D4F28D /* Headers */,
D03D891520E0A85200D4F28D /* Resources */,
B6624E56225852CD00354CDF /* Crashlytics */,
);
buildRules = (
);
Expand Down Expand Up @@ -3497,6 +3491,7 @@
"${BUILT_PRODUCTS_DIR}/ReachabilitySwift/Reachability.framework",
"${BUILT_PRODUCTS_DIR}/Realm-iOS/Realm.framework",
"${BUILT_PRODUCTS_DIR}/RealmSwift-iOS/RealmSwift.framework",
"${BUILT_PRODUCTS_DIR}/Sentry/Sentry.framework",
"${BUILT_PRODUCTS_DIR}/SimulatorStatusMagic/SimulatorStatusMagic.framework",
"${BUILT_PRODUCTS_DIR}/Sodium-iOS/Sodium.framework",
"${BUILT_PRODUCTS_DIR}/SwiftMessages/SwiftMessages.framework",
Expand Down Expand Up @@ -3536,6 +3531,7 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Realm.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RealmSwift.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sentry.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SimulatorStatusMagic.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sodium.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftMessages.framework",
Expand Down Expand Up @@ -3644,120 +3640,6 @@
shellPath = /bin/sh;
shellScript = "\"$PODS_ROOT/SwiftGen/bin/swiftgen\"\n";
};
B6624E4122584AD500354CDF /* Crashlytics */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)",
);
name = Crashlytics;
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "VALID_CONFIGS=(\"Debug\" \"Beta\" \"Release\")\nif [[ ! \" ${VALID_CONFIGS[@]} \" =~ \" ${CONFIGURATION} \" ]]; then\n echo \"warning: Unknown configuration ${CONFIGURATION}, refusing to upload dSYM to Crashlytics\"\n return\nfi\n\n\"${PODS_ROOT}/FirebaseCrashlytics/run\" -d -gsp \"${PROJECT_DIR}/HomeAssistant/Resources/GoogleService-Info-${CONFIGURATION}.plist\"\n";
};
B6624E4522584CCE00354CDF /* Crashlytics */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)",
);
name = Crashlytics;
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "VALID_CONFIGS=(\"Debug\" \"Beta\" \"Release\")\nif [[ ! \" ${VALID_CONFIGS[@]} \" =~ \" ${CONFIGURATION} \" ]]; then\n echo \"warning: Unknown configuration ${CONFIGURATION}, refusing to upload dSYM to Crashlytics\"\n return\nfi\n\n\"${PODS_ROOT}/FirebaseCrashlytics/run\" -d -gsp \"${PROJECT_DIR}/HomeAssistant/Resources/GoogleService-Info-${CONFIGURATION}.plist\"\n";
};
B6624E4622584CEF00354CDF /* Crashlytics */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)",
);
name = Crashlytics;
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "VALID_CONFIGS=(\"Debug\" \"Beta\" \"Release\")\nif [[ ! \" ${VALID_CONFIGS[@]} \" =~ \" ${CONFIGURATION} \" ]]; then\n echo \"warning: Unknown configuration ${CONFIGURATION}, refusing to upload dSYM to Crashlytics\"\n return\nfi\n\n\"${PODS_ROOT}/FirebaseCrashlytics/run\" -d -gsp \"${PROJECT_DIR}/HomeAssistant/Resources/GoogleService-Info-${CONFIGURATION}.plist\"\n";
};
B6624E4722584CFF00354CDF /* Crashlytics */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)",
);
name = Crashlytics;
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "VALID_CONFIGS=(\"Debug\" \"Beta\" \"Release\")\nif [[ ! \" ${VALID_CONFIGS[@]} \" =~ \" ${CONFIGURATION} \" ]]; then\n echo \"warning: Unknown configuration ${CONFIGURATION}, refusing to upload dSYM to Crashlytics\"\n return\nfi\n\n\"${PODS_ROOT}/FirebaseCrashlytics/run\" -d -gsp \"${PROJECT_DIR}/HomeAssistant/Resources/GoogleService-Info-${CONFIGURATION}.plist\"\n";
};
B6624E4822584D1B00354CDF /* Crashlytics */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)",
);
name = Crashlytics;
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "VALID_CONFIGS=(\"Debug\" \"Beta\" \"Release\")\nif [[ ! \" ${VALID_CONFIGS[@]} \" =~ \" ${CONFIGURATION} \" ]]; then\n echo \"warning: Unknown configuration ${CONFIGURATION}, refusing to upload dSYM to Crashlytics\"\n return\nfi\n\n\"${PODS_ROOT}/FirebaseCrashlytics/run\" -d -gsp \"${PROJECT_DIR}/HomeAssistant/Resources/GoogleService-Info-${CONFIGURATION}.plist\"\n";
};
B6624E56225852CD00354CDF /* Crashlytics */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)",
);
name = Crashlytics;
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "VALID_CONFIGS=(\"Debug\" \"Beta\" \"Release\")\nif [[ ! \" ${VALID_CONFIGS[@]} \" =~ \" ${CONFIGURATION} \" ]]; then\n echo \"warning: Unknown configuration ${CONFIGURATION}, refusing to upload dSYM to Crashlytics\"\n return\nfi\n\n\"${PODS_ROOT}/FirebaseCrashlytics/run\" -d -gsp \"${PROJECT_DIR}/HomeAssistant/Resources/GoogleService-Info-${CONFIGURATION}.plist\"\n";
};
B6E47E861CB9FD350027F6CA /* [CP] Copy Acknowledgements */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
Expand Down Expand Up @@ -3988,7 +3870,7 @@
B661FC8D226D5A0700E541DD /* ConnectInstanceViewController.swift in Sources */,
B648AE262275918F006972AF /* Scenes.swift in Sources */,
1100D51F2496F63400B1073C /* ThemeColors.swift in Sources */,
B6CC96D624B0097500CE53ED /* CrashlyticsLogDestination.swift in Sources */,
B6CC96D624B0097500CE53ED /* SentryLogDestination.swift in Sources */,
11F3B85C24C4295200642676 /* EurekaLocationRow.swift in Sources */,
B6DA3C7322691A5000DE811C /* AKConverter.swift in Sources */,
B68EDD05215F12C900DD6B28 /* NotificationActionConfigurator.swift in Sources */,
Expand Down
87 changes: 65 additions & 22 deletions HomeAssistant/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ import Shared
import XCGLogger
import UIKit
import UserNotifications
import FirebaseCrashlytics
import FirebaseMessaging
import FirebaseCore
import Sentry
#if DEBUG
import SimulatorStatusMagic
#endif
Expand Down Expand Up @@ -73,6 +73,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {

UNUserNotificationCenter.current().delegate = self

self.setupSentry()
self.setupFirebase()

self.configureLokalise()
Expand Down Expand Up @@ -272,6 +273,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let apnsToken = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
Current.Log.verbose("Successfully registered for push notifications! APNS token: \(apnsToken)")
Current.setUserProperty?(apnsToken, "APNS Token")

var tokenType: MessagingAPNSTokenType = .prod

Expand Down Expand Up @@ -826,40 +828,82 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
Lokalise.shared.localizationType = Current.appConfiguration.lokaliseEnv
}

func setupFirebase() {
LogDestination = CrashlyticsLogDestination()
func setupSentry() {
Current.Log.add(destination: SentryLogDestination())

FirebaseApp.configure()
SentrySDK.start { options in
options.dsn = "https://762c198b86594fa2b6bedf87028db34d@o427061.ingest.sentry.io/5372775"
options.debug = NSNumber(value: Current.appConfiguration == .Debug)
options.enableAutoSessionTracking = NSNumber(value: Current.settingsStore.privacy.analytics)
options.enabled = NSNumber(value: Current.settingsStore.privacy.crashes)
options.maxBreadcrumbs = 1000

Messaging.messaging().delegate = self
var integrations = type(of: options).defaultIntegrations()

Current.Log.verbose("Calling UIApplication.shared.registerForRemoteNotifications()")
UIApplication.shared.registerForRemoteNotifications()
let analyticsIntegrations = Set([
NSStringFromClass(SentryAutoBreadcrumbTrackingIntegration.self),
NSStringFromClass(SentryAutoSessionTrackingIntegration.self)
])

let crashesIntegrations = Set([
NSStringFromClass(SentryCrashIntegration.self)
])

if !Current.settingsStore.privacy.crashes {
integrations.removeAll(where: { crashesIntegrations.contains($0) })
}

Messaging.messaging().isAutoInitEnabled = prefs.bool(forKey: "messagingEnabled")
Analytics.setAnalyticsCollectionEnabled(prefs.bool(forKey: "analyticsEnabled"))
if !Current.settingsStore.privacy.analytics {
integrations.removeAll(where: { analyticsIntegrations.contains($0) })
}

Current.logEvent = { (eventName: String, params: [String: Any]?) -> Void in
Current.Log.verbose("Logging event \(eventName) to analytics")
Analytics.logEvent(eventName, parameters: params)
Current.Log.info("enabled integrations: \(integrations)")
options.integrations = integrations
}

Current.logError = { error in
// crashlytics itself controlled by the crashlytics key, but this is more like analytics
guard prefs.bool(forKey: "analyticsEnabled") else { return }
// crash reporting is controlled by the crashes key, but this is more like analytics
guard Current.settingsStore.privacy.analytics else { return}

Current.Log.error("logging error: \(error.debugDescription)")
Crashlytics.crashlytics().record(error: error)
Current.Log.error("error: \(error.debugDescription)")
SentrySDK.capture(error: error)
}

Current.logEvent = { (eventName: String, params: [String: Any]) -> Void in
guard Current.settingsStore.privacy.analytics else { return}

Current.Log.verbose("event \(eventName): \(params)")
SentrySDK.capture(message: eventName) { scope in
scope.setTags(params.mapValues { String(describing: $0)})
}
}

Current.setUserProperty = { (value: String?, name: String) -> Void in
Current.Log.verbose("Setting user property \(name) to \(String(describing: value))")
Analytics.setUserProperty(value, forName: name)
guard let value = value else { return }
Crashlytics.crashlytics().setCustomValue(value, forKey: name)
SentrySDK.configureScope { scope in
scope.setEnvironment(Current.appConfiguration.description)

if let value = value {
Current.Log.verbose("setting tag \(name) to '\(value)'")
scope.setTag(value: value, key: name)
} else {
Current.Log.verbose("removing tag \(name)")
scope.removeTag(key: name)
}
}
}
}

func setupFirebase() {
FirebaseApp.configure()

Messaging.messaging().delegate = self

Current.Log.verbose("Calling UIApplication.shared.registerForRemoteNotifications()")
UIApplication.shared.registerForRemoteNotifications()

Messaging.messaging().isAutoInitEnabled = Current.settingsStore.privacy.messaging
}

func setupModels() {
Current.modelManager.cleanup().cauterize()
Action.setupObserver()
Expand Down Expand Up @@ -1086,8 +1130,7 @@ extension AppDelegate: MessagingDelegate {
Current.Log.warning("FCM token has changed from \(existingToken) to \(fcmToken)")
}

Crashlytics.crashlytics().setCustomValue(fcmToken, forKey: "pushToken")

Current.setUserProperty?(fcmToken, "FCM Token")
Current.settingsStore.pushID = fcmToken

guard let api = HomeAssistantAPI.authenticatedAPI() else {
Expand Down
9 changes: 5 additions & 4 deletions HomeAssistant/Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -517,12 +517,13 @@
"watch.labels.no_action" = "No actions configured. Configure actions on your phone to dismiss this message.";
"settings.status_section.mobile_app_component_loaded_row.title" = "Mobile App Component Loaded";
"settings_details.privacy.title" = "Privacy";
"settings_details.privacy.analytics.title" = "Google Analytics";
"settings_details.privacy.analytics.description" = "Allows collection of basic information about your device and interactions with the app. No user identifiable data is shared with Google, including your Home Assistant URLs and tokens. You must restart the app for changes to this setting to take effect.";
"settings_details.privacy.analytics.generic_title" = "Analytics";
"settings_details.privacy.analytics.generic_description" = "Allows collection of basic information about your device and interactions with the app. No user identifiable data is shared, including your Home Assistant URLs and tokens. You must restart the app for changes to this setting to take effect.";
"settings_details.privacy.messaging.title" = "Firebase Cloud Messaging";
"settings_details.privacy.messaging.description" = "Firebase Cloud Messaging must be enabled for push notifications to function.";
"settings_details.privacy.crashlytics.title" = "Firebase Crashlytics";
"settings_details.privacy.crashlytics.description" = "Crashlytics allows for deeper tracking of crashes and other errors in the app, leading to faster fixes being published. No user identifiable information is sent, other than basic device information. You must restart the app for changes to this setting to take effect.";
"settings_details.privacy.crash_reporting.title" = "Crash Reporting";
"settings_details.privacy.crash_reporting.description" = "Allows for deeper tracking of crashes and other errors in the app, leading to faster fixes being published. No user identifiable information is sent, other than basic device information. You must restart the app for changes to this setting to take effect.";
"settings_details.privacy.crash_reporting.sentry" = "This feature currently uses Sentry as the report destination.";
"settings_details.privacy.performance_monitoring.title" = "Firebase Performance Monitoring";
"settings_details.privacy.performance_monitoring.description" = "Firebase Performance Monitoring allows for remote monitoring of overall application performance, allowing for speed improvements to be made more easily. You must restart the app for changes to this setting to take effect.";
"settings.developer.sync_watch_context.title" = "Sync Watch Context";
Expand Down