diff --git a/Podfile b/Podfile index 0a00d24693..17a98de3bb 100644 --- a/Podfile +++ b/Podfile @@ -72,6 +72,7 @@ abstract_target 'RiotPods' do # PostHog for analytics pod 'PostHog', '~> 1.4.4' + pod 'Sentry', '~> 7.15.0' pod 'AnalyticsEvents', :git => 'https://github.com/matrix-org/matrix-analytics-events.git', :branch => 'release/swift', :inhibit_warnings => false # pod 'AnalyticsEvents', :path => '../matrix-analytics-events/AnalyticsEvents.podspec' diff --git a/Podfile.lock b/Podfile.lock index 7e05e4ccd3..33e81e3477 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -87,6 +87,9 @@ PODS: - Reusable/View (= 4.1.2) - Reusable/Storyboard (4.1.2) - Reusable/View (4.1.2) + - Sentry (7.15.0): + - Sentry/Core (= 7.15.0) + - Sentry/Core (7.15.0) - SideMenu (6.5.0) - SwiftBase32 (0.9.0) - SwiftGen (6.5.1) @@ -126,6 +129,7 @@ DEPENDENCIES: - PostHog (~> 1.4.4) - ReadMoreTextView (~> 3.0.1) - Reusable (~> 4.1) + - Sentry (~> 7.15.0) - SideMenu (~> 6.5) - SwiftBase32 (~> 0.9.0) - SwiftGen (~> 6.3) @@ -169,6 +173,7 @@ SPEC REPOS: - ReadMoreTextView - Realm - Reusable + - Sentry - SideMenu - SwiftBase32 - SwiftGen @@ -223,6 +228,7 @@ SPEC CHECKSUMS: ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d Realm: 9ca328bd7e700cc19703799785e37f77d1a130f2 Reusable: 6bae6a5e8aa793c9c441db0213c863a64bce9136 + Sentry: 63ca44f5e0c8cea0ee5a07686b02e56104f41ef7 SideMenu: f583187d21c5b1dd04c72002be544b555a2627a2 SwiftBase32: 9399c25a80666dc66b51e10076bf591e3bbb8f17 SwiftGen: a6d22010845f08fe18fbdf3a07a8e380fd22e0ea @@ -235,6 +241,6 @@ SPEC CHECKSUMS: zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: fdddeaf3f403004b1cc6200add1b6b9e00d40906 +PODFILE CHECKSUM: b3c7c064fc2b74dc937762364faab403fc3fd041 COCOAPODS: 1.11.2 diff --git a/Riot/Modules/Analytics/Analytics.swift b/Riot/Modules/Analytics/Analytics.swift index 9505b56206..030b4463c3 100644 --- a/Riot/Modules/Analytics/Analytics.swift +++ b/Riot/Modules/Analytics/Analytics.swift @@ -17,8 +17,12 @@ import PostHog import AnalyticsEvents -/// A class responsible for managing an analytics client -/// and sending events through this client. +/// A class responsible for managing a variety of analytics clients +/// and sending events through these clients. +/// +/// Events may include user activity, or app health data such as crashes, +/// non-fatal issues and performance. `Analytics` class serves as a façade +/// to all these use cases. /// /// ## Creating Analytics Events /// @@ -42,6 +46,9 @@ import AnalyticsEvents /// The analytics client to send events with. private var client: AnalyticsClientProtocol = PostHogAnalyticsClient() + /// The monitoring client to track crashes, issues and performance + private var monitoringClient = SentryMonitoringClient() + /// The service used to interact with account data settings. private var service: AnalyticsService? @@ -106,6 +113,7 @@ import AnalyticsEvents // The order is important here. PostHog ignores the reset if stopped. reset() client.stop() + monitoringClient.stop() MXLog.debug("[Analytics] Stopped.") } @@ -115,6 +123,7 @@ import AnalyticsEvents guard RiotSettings.shared.enableAnalytics, !isRunning else { return } client.start() + monitoringClient.start() // Sanity check in case something went wrong. guard client.isRunning else { return } @@ -163,6 +172,7 @@ import AnalyticsEvents /// Note: **MUST** be called before stopping PostHog or the reset is ignored. func reset() { client.reset() + monitoringClient.reset() MXLog.debug("[Analytics] Reset.") RiotSettings.shared.isIdentifiedForAnalytics = false @@ -374,4 +384,7 @@ extension Analytics: MXAnalyticsDelegate { capture(event: event) } + func trackNonFatalIssue(_ issue: String, details: [String : Any]?) { + monitoringClient.trackNonFatalIssue(issue, details: details) + } } diff --git a/Riot/Modules/Analytics/SentryMonitoringClient.swift b/Riot/Modules/Analytics/SentryMonitoringClient.swift new file mode 100644 index 0000000000..286c0fb43f --- /dev/null +++ b/Riot/Modules/Analytics/SentryMonitoringClient.swift @@ -0,0 +1,67 @@ +// +// Copyright 2022 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import Sentry +import MatrixSDK + +/// Sentry client used as part of the Analytics set of tools to track health metrics +/// of the application, such as crashes, non-fatal issues and performance. +/// +/// All analytics tracking, incl. health metrics, is subject to user consent, +/// configurable in user settings. +struct SentryMonitoringClient { + private static let sentryDSN = "https://a5e37731f9b94642a1b93093cacbee4c@sentry.tools.element.io/47" + + func start() { + guard !SentrySDK.isEnabled else { return } + + MXLog.debug("[SentryMonitoringClient] Started") + SentrySDK.start { options in + options.dsn = Self.sentryDSN + options.tracesSampleRate = 1.0 + + options.beforeSend = { event in + MXLog.error("[SentryMonitoringClient] Issue detected: \(event)") + return event + } + + options.onCrashedLastRun = { event in + MXLog.debug("[SentryMonitoringClient] Last run crashed: \(event)") + } + } + } + + func stop() { + MXLog.debug("[SentryMonitoringClient] Stopped") + SentrySDK.close() + } + + func reset() { + MXLog.debug("[SentryMonitoringClient] Reset") + SentrySDK.startSession() + } + + func trackNonFatalIssue(_ issue: String, details: [String: Any]?) { + guard SentrySDK.isEnabled else { return } + + let event = Event() + event.level = .error + event.message = .init(formatted: issue) + event.extra = details + SentrySDK.capture(event: event) + } +} diff --git a/changelog.d/pr-6308.feature b/changelog.d/pr-6308.feature new file mode 100644 index 0000000000..d288d13bf7 --- /dev/null +++ b/changelog.d/pr-6308.feature @@ -0,0 +1 @@ +Analytics: Track non-fatal issues if consent provided