From 59151757e289229b262d3546dd7e87355b4415b0 Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Sat, 6 Jul 2024 14:32:38 +0200 Subject: [PATCH] Add connection tester failure pixels (#2948) Task/Issue URL: https://app.asana.com/0/1206580121312550/1207743877093953/f iOS PR: https://github.com/duckduckgo/iOS/pull/3049 BSK PR: https://github.com/duckduckgo/BrowserServicesKit/pull/881 ## Description Adds pixels to track connection tester failures and recovery. These should give us a better idea about how users are faring. --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 4 +-- .../NetworkProtectionPixelEvent.swift | 30 +++++++++++++++++ .../MacPacketTunnelProvider.swift | 33 +++++++++++++++++++ .../NetworkExtensionTargets/VPNLogger.swift | 12 +++++++ .../DataBrokerProtection/Package.swift | 2 +- .../NetworkProtectionMac/Package.swift | 2 +- LocalPackages/SubscriptionUI/Package.swift | 2 +- 8 files changed, 81 insertions(+), 6 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 6c08561270..83abea48a8 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -13228,7 +13228,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 167.0.0; + version = 167.0.1; }; }; 9FF521422BAA8FF300B9819B /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index ab46671030..6fa07025f8 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "5954412504b0cf294f5c0d90d7a0c8dfcd009558", - "version" : "167.0.0" + "revision" : "0746af01b77d39a1e037bea93b46591534a13b5c", + "version" : "167.0.1" } }, { diff --git a/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/NetworkProtectionPixelEvent.swift b/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/NetworkProtectionPixelEvent.swift index a294db849a..6b0a86cfec 100644 --- a/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/NetworkProtectionPixelEvent.swift +++ b/DuckDuckGo/NetworkProtection/AppAndExtensionAndAgentTargets/NetworkProtectionPixelEvent.swift @@ -56,6 +56,11 @@ enum NetworkProtectionPixelEvent: PixelKitEventV2 { case networkProtectionEnableAttemptSuccess case networkProtectionEnableAttemptFailure + case networkProtectionConnectionTesterFailureDetected(server: String) + case networkProtectionConnectionTesterFailureRecovered(server: String, failureCount: Int) + case networkProtectionConnectionTesterExtendedFailureDetected(server: String) + case networkProtectionConnectionTesterExtendedFailureRecovered(server: String, failureCount: Int) + case networkProtectionTunnelFailureDetected case networkProtectionTunnelFailureRecovered @@ -180,6 +185,18 @@ enum NetworkProtectionPixelEvent: PixelKitEventV2 { case .networkProtectionEnableAttemptFailure: return "netp_ev_enable_attempt_failure" + case .networkProtectionConnectionTesterFailureDetected: + return "netp_connection_tester_failure" + + case .networkProtectionConnectionTesterFailureRecovered: + return "netp_connection_tester_failure_recovered" + + case .networkProtectionConnectionTesterExtendedFailureDetected: + return "netp_connection_tester_extended_failure" + + case .networkProtectionConnectionTesterExtendedFailureRecovered: + return "netp_connection_tester_extended_failure_recovered" + case .networkProtectionTunnelFailureDetected: return "netp_ev_tunnel_failure" @@ -316,6 +333,15 @@ enum NetworkProtectionPixelEvent: PixelKitEventV2 { var parameters: [String: String]? { switch self { + case .networkProtectionConnectionTesterFailureDetected(let server), + .networkProtectionConnectionTesterExtendedFailureDetected(let server): + return [PixelKit.Parameters.server: server] + case .networkProtectionConnectionTesterFailureRecovered(let server, let failureCount), + .networkProtectionConnectionTesterExtendedFailureRecovered(let server, let failureCount): + return [ + PixelKit.Parameters.server: server, + PixelKit.Parameters.count: String(failureCount) + ] case .networkProtectionKeychainErrorFailedToCastKeychainValueToData(let field): return [PixelKit.Parameters.keychainFieldName: field] case .networkProtectionKeychainReadError(let field, let status): @@ -454,6 +480,10 @@ enum NetworkProtectionPixelEvent: PixelKitEventV2 { .networkProtectionEnableAttemptConnecting, .networkProtectionEnableAttemptSuccess, .networkProtectionEnableAttemptFailure, + .networkProtectionConnectionTesterFailureDetected, + .networkProtectionConnectionTesterFailureRecovered, + .networkProtectionConnectionTesterExtendedFailureDetected, + .networkProtectionConnectionTesterExtendedFailureRecovered, .networkProtectionTunnelFailureDetected, .networkProtectionTunnelFailureRecovered, .networkProtectionLatency, diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift index 9d9cd567ea..ac2fa676b9 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift @@ -154,6 +154,39 @@ final class MacPacketTunnelProvider: PacketTunnelProvider { frequency: .legacyDaily, withAdditionalParameters: [PixelKit.Parameters.vpnCohort: PixelKit.cohort(from: defaults.vpnFirstEnabled)], includeAppVersionParameter: true) + case .connectionTesterStatusChange(let status, let server): + vpnLogger.log(status, server: server) + + switch status { + case .failed(let duration): + let pixel: NetworkProtectionPixelEvent = { + switch duration { + case .immediate: + return .networkProtectionConnectionTesterFailureDetected(server: server) + case .extended: + return .networkProtectionConnectionTesterExtendedFailureDetected(server: server) + } + }() + + PixelKit.fire( + pixel, + frequency: .dailyAndCount, + includeAppVersionParameter: true) + case .recovered(let duration, let failureCount): + let pixel: NetworkProtectionPixelEvent = { + switch duration { + case .immediate: + return .networkProtectionConnectionTesterFailureRecovered(server: server, failureCount: failureCount) + case .extended: + return .networkProtectionConnectionTesterExtendedFailureRecovered(server: server, failureCount: failureCount) + } + }() + + PixelKit.fire( + pixel, + frequency: .dailyAndCount, + includeAppVersionParameter: true) + } case .reportConnectionAttempt(attempt: let attempt): vpnLogger.log(attempt) diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/VPNLogger.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/VPNLogger.swift index d01f4519ca..f230701509 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/VPNLogger.swift +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/VPNLogger.swift @@ -29,6 +29,7 @@ import OSLog public final class VPNLogger { public typealias AttemptStep = PacketTunnelProvider.AttemptStep public typealias ConnectionAttempt = PacketTunnelProvider.ConnectionAttempt + public typealias ConnectionTesterStatus = PacketTunnelProvider.ConnectionTesterStatus public typealias LogCallback = (OSLogType, OSLogMessage) -> Void public init() {} @@ -63,6 +64,17 @@ public final class VPNLogger { } } + public func log(_ status: ConnectionTesterStatus, server: String) { + let log = OSLog.networkProtectionConnectionTesterLog + + switch status { + case .failed(let duration): + os_log("🔴 Connection tester (%{public}@ - %{public}@) failure", log: log, type: .error, duration.rawValue, server) + case .recovered(let duration, let failureCount): + os_log("🟢 Connection tester (%{public}@ - %{public}@) recovery (after %{public}@ failures)", log: log, duration.rawValue, server, String(failureCount)) + } + } + public func log(_ step: FailureRecoveryStep) { let log = OSLog.networkProtectionTunnelFailureMonitorLog diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index 3f7e0d261c..5b28efc60e 100644 --- a/LocalPackages/DataBrokerProtection/Package.swift +++ b/LocalPackages/DataBrokerProtection/Package.swift @@ -29,7 +29,7 @@ let package = Package( targets: ["DataBrokerProtection"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "167.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "167.0.1"), .package(path: "../SwiftUIExtensions"), .package(path: "../XPCHelper"), ], diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index 9a170c3af4..71b9507ae1 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -32,7 +32,7 @@ let package = Package( .library(name: "VPNAppLauncher", targets: ["VPNAppLauncher"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "167.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "167.0.1"), .package(url: "https://github.com/airbnb/lottie-spm", exact: "4.4.3"), .package(path: "../AppLauncher"), .package(path: "../UDSHelper"), diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index 57605548a4..b07b39a1da 100644 --- a/LocalPackages/SubscriptionUI/Package.swift +++ b/LocalPackages/SubscriptionUI/Package.swift @@ -12,7 +12,7 @@ let package = Package( targets: ["SubscriptionUI"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "167.0.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "167.0.1"), .package(path: "../SwiftUIExtensions") ], targets: [