native macOS codings agent orchestrator
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #236 from onevcat/chore/remove-sentry-app-hang-tracking

chore(sentry): remove App Hang tracking and its filter

authored by

Wei Wang and committed by
GitHub
930ce58c db11a25d

-145
-3
supacode/App/supacodeApp.swift
··· 129 129 options.environment = environment 130 130 if let releaseName { options.releaseName = releaseName } 131 131 options.tracesSampleRate = 0.05 132 - options.enableAppHangTracking = true 133 - options.appHangTimeoutInterval = 3 134 - options.beforeSend = SentryEventFilter.filterSystemHang 135 132 } 136 133 } 137 134 if initialSettings.analyticsEnabled,
-46
supacode/Support/SentryEventFilter.swift
··· 1 - import Foundation 2 - import Sentry 3 - 4 - /// Client-side filter for Sentry events. 5 - /// 6 - /// Wired into `SentrySDK.start { options.beforeSend = SentryEventFilter.filterSystemHang }`. 7 - /// 8 - /// Members are explicitly `nonisolated`: Sentry invokes `beforeSend` synchronously 9 - /// from its own background threads (notably `SentryANRTrackerV1`'s detection thread). 10 - /// Under the project's `SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor` setting, any 11 - /// un-annotated member would implicitly be `@MainActor`, and Swift 6.2's executor 12 - /// check aborts the process via libdispatch when such code runs off the main thread. 13 - enum SentryEventFilter { 14 - /// Known stack frame function-name fragments that indicate a system-induced 15 - /// App Hang (wake-from-sleep, active space change, external display connect, 16 - /// menu bar redraw, etc.). These hangs are observable but have no app-level 17 - /// remedy — filter them out to avoid drowning real hangs in noise. 18 - nonisolated static let systemHangSignatures = [ 19 - "_NSMenuBarDisplayManagerActiveSpaceChanged", 20 - "NSMenuBarLocalDisplayWindow", 21 - "NSMenuBarPresentationInstance", 22 - "NSMenuBarReplicantWindow", 23 - ] 24 - 25 - /// Drop App Hang events whose stack contains zero in-app frames AND matches 26 - /// at least one known system signature. Conservative by design: if the hang 27 - /// involves any app code, keep it; if the stack is all-system but matches no 28 - /// known pattern, keep it too (so we still see novel system-level issues). 29 - nonisolated static func filterSystemHang(_ event: Event) -> Event? { 30 - guard let exception = event.exceptions?.first, 31 - exception.mechanism?.type == "AppHang" 32 - else { 33 - return event 34 - } 35 - let frames = exception.stacktrace?.frames ?? [] 36 - let hasAppFrame = frames.contains { $0.inApp?.boolValue == true } 37 - let hasSystemSignature = frames.contains { frame in 38 - guard let function = frame.function else { return false } 39 - return systemHangSignatures.contains { function.contains($0) } 40 - } 41 - if !hasAppFrame && hasSystemSignature { 42 - return nil 43 - } 44 - return event 45 - } 46 - }
-96
supacodeTests/SentryEventFilterTests.swift
··· 1 - import Foundation 2 - import Sentry 3 - import Testing 4 - 5 - @testable import supacode 6 - 7 - struct SentryEventFilterTests { 8 - @Test func nonHangEventPassesThrough() { 9 - let event = makeEvent(mechanismType: "nsexception", frames: []) 10 - #expect(SentryEventFilter.filterSystemHang(event) === event) 11 - } 12 - 13 - @Test func appHangWithSystemSignatureAndNoAppFrameIsDropped() { 14 - let event = makeEvent( 15 - mechanismType: "AppHang", 16 - frames: [ 17 - makeFrame(function: "mach_msg2_trap", inApp: false), 18 - makeFrame(function: "_NSMenuBarDisplayManagerActiveSpaceChanged", inApp: false), 19 - ] 20 - ) 21 - #expect(SentryEventFilter.filterSystemHang(event) == nil) 22 - } 23 - 24 - @Test func appHangWithAnyAppFrameIsKept() { 25 - let event = makeEvent( 26 - mechanismType: "AppHang", 27 - frames: [ 28 - makeFrame(function: "_NSMenuBarDisplayManagerActiveSpaceChanged", inApp: false), 29 - makeFrame(function: "WorktreeTerminalManager.didReceiveNotification", inApp: true), 30 - ] 31 - ) 32 - #expect(SentryEventFilter.filterSystemHang(event) === event) 33 - } 34 - 35 - @Test func appHangWithNoKnownSystemSignatureIsKept() { 36 - let event = makeEvent( 37 - mechanismType: "AppHang", 38 - frames: [ 39 - makeFrame(function: "mach_msg2_trap", inApp: false), 40 - makeFrame(function: "__CFRunLoopRun", inApp: false), 41 - ] 42 - ) 43 - #expect(SentryEventFilter.filterSystemHang(event) === event) 44 - } 45 - 46 - @Test func eventWithoutExceptionsPassesThrough() { 47 - let event = Event() 48 - #expect(SentryEventFilter.filterSystemHang(event) === event) 49 - } 50 - 51 - /// Regression guard for PROWL-MACOS-5 / Sentry issue 7424130201. 52 - /// 53 - /// Sentry's `SentryANRTrackerV1` invokes `beforeSend` synchronously from a 54 - /// background thread. Because the project sets 55 - /// `SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor`, un-annotated members of 56 - /// `SentryEventFilter` are implicitly `@MainActor` and Swift 6.2's executor 57 - /// check aborts the process via libdispatch when called off-main. 58 - /// 59 - /// This test exercises the exact off-main invocation path. If 60 - /// `filterSystemHang` ever loses `nonisolated`, the `@Sendable` closure below 61 - /// will fail to compile — turning the runtime crash into a build-time error. 62 - @Test func filterIsInvokableFromBackgroundThread() async { 63 - await withCheckedContinuation { (continuation: CheckedContinuation<Void, Never>) in 64 - DispatchQueue.global(qos: .userInitiated).async { 65 - let event = Event() 66 - let exception = Exception(value: "test", type: "test") 67 - exception.mechanism = Mechanism(type: "AppHang") 68 - let frame = Frame() 69 - frame.function = "_NSMenuBarDisplayManagerActiveSpaceChanged" 70 - frame.inApp = NSNumber(value: false) 71 - exception.stacktrace = SentryStacktrace(frames: [frame], registers: [:]) 72 - event.exceptions = [exception] 73 - 74 - #expect(!Thread.isMainThread) 75 - #expect(SentryEventFilter.filterSystemHang(event) == nil) 76 - continuation.resume() 77 - } 78 - } 79 - } 80 - 81 - private func makeEvent(mechanismType: String, frames: [Frame]) -> Event { 82 - let event = Event() 83 - let exception = Exception(value: "test", type: "test") 84 - exception.mechanism = Mechanism(type: mechanismType) 85 - exception.stacktrace = SentryStacktrace(frames: frames, registers: [:]) 86 - event.exceptions = [exception] 87 - return event 88 - } 89 - 90 - private func makeFrame(function: String, inApp: Bool) -> Frame { 91 - let frame = Frame() 92 - frame.function = function 93 - frame.inApp = NSNumber(value: inApp) 94 - return frame 95 - } 96 - }