Skip to content

Commit b7c25ab

Browse files
zhu-xiaoweixiaoweii
andauthored
feat: add app exception event (#18)
Co-authored-by: xiaoweii <xiaoweii@amazom.com>
1 parent fe411fe commit b7c25ab

File tree

5 files changed

+44
-2
lines changed

5 files changed

+44
-2
lines changed

Sources/Clickstream/Dependency/Clickstream/AutoRecord/AutoRecordEventClient.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ class AutoRecordEventClient {
2828
UIViewController.swizzle(viewDidAppear: onViewDidAppear)
2929
#endif
3030
}
31+
if clickstream.configuration.isTrackAppExceptionEvents {
32+
setupExceptionHandler()
33+
}
3134
}
3235

3336
func checkAppVersionUpdate(clickstream: ClickstreamContext) {
@@ -130,6 +133,26 @@ class AutoRecordEventClient {
130133
lastScreenStartTime = currentTimestamp
131134
}
132135

136+
func setupExceptionHandler() {
137+
NSSetUncaughtExceptionHandler { exception in
138+
AutoRecordEventClient.handleException(exception)
139+
}
140+
}
141+
142+
static func handleException(_ exception: NSException) {
143+
let name = exception.name.rawValue
144+
let reason = exception.reason ?? ""
145+
let stackTrace = exception.callStackSymbols.joined(separator: "\n")
146+
let attribute: ClickstreamAttribute = [
147+
Event.ReservedAttribute.EXCEPTION_NAME: name,
148+
Event.ReservedAttribute.EXCEPTION_REASON: reason,
149+
Event.ReservedAttribute.EXCEPTION_STACK: stackTrace
150+
]
151+
ClickstreamAnalytics.recordEvent(Event.PresetEvent.APP_EXCEPTION, attribute)
152+
Thread.sleep(forTimeInterval: 0.2)
153+
log.info("Recorded an app exception event, error name:\(name)")
154+
}
155+
133156
func recordEvent(_ event: ClickstreamEvent) {
134157
Task {
135158
try await clickstream.analyticsClient.record(event)
@@ -142,3 +165,5 @@ extension AutoRecordEventClient {
142165
static let minEngagementTime = 1_000
143166
}
144167
}
168+
169+
extension AutoRecordEventClient: ClickstreamLogger {}

Sources/Clickstream/Dependency/Clickstream/ClickstreamContext.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ extension UserDefaults: UserDefaultsBehaviour {
4242
/// Time interval after which the events are automatically submitted to server
4343
private let sendEventsInterval: Int
4444
/// Whether to track app exception events automatically
45-
public var isTrackAppExceptionEvents: Bool
45+
var isTrackAppExceptionEvents: Bool
4646
/// Whether to track app scren view events automatically
4747
public var isTrackScreenViewEvents: Bool
4848
/// Whether to compress events when send to server

Sources/Clickstream/Dependency/Clickstream/Event/ClickstreamEvent.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class ClickstreamEvent: AnalyticsPropertiesModel, Hashable {
4545

4646
func addAttribute(_ attribute: AttributeValue, forKey key: String) {
4747
let eventError = Event.checkAttribute(currentNumber: attributes.count, key: key, value: attribute)
48-
if eventError != nil {
48+
if eventError != nil, key != Event.ReservedAttribute.EXCEPTION_STACK {
4949
attributes[eventError!.errorType] = eventError!.errorMessage
5050
} else {
5151
attributes[key] = attribute

Sources/Clickstream/Dependency/Clickstream/Event/Event.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ enum Event {
167167
static let SCREEN_ID = "_screen_id"
168168
static let SCREEN_NAME = "_screen_name"
169169
static let IS_FIRST_TIME = "_is_first_time"
170+
static let EXCEPTION_NAME = "_exception_name"
171+
static let EXCEPTION_REASON = "_exception_reason"
172+
static let EXCEPTION_STACK = "_excepiton_stack"
170173
}
171174

172175
enum User {
@@ -209,6 +212,7 @@ enum Event {
209212
static let USER_ENGAGEMENT = "_user_engagement"
210213
static let SCREEN_VIEW = "_screen_view"
211214
static let APP_START = "_app_start"
215+
static let APP_EXCEPTION = "_app_exception"
212216
}
213217

214218
enum ErrorType {

Tests/ClickstreamTests/IntegrationTest.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,19 @@ class IntegrationTest: XCTestCase {
308308
XCTAssertEqual(1, eventCount)
309309
}
310310

311+
func testAppException() throws {
312+
let exception = NSException(name: NSExceptionName("TestException"), reason: "Testing", userInfo: nil)
313+
AutoRecordEventClient.handleException(exception)
314+
Thread.sleep(forTimeInterval: 0.5)
315+
let event = try eventRecorder.getBatchEvent().eventsJson.jsonArray()[0]
316+
XCTAssertTrue(event["event_type"] as! String == Event.PresetEvent.APP_EXCEPTION)
317+
let attributes = event["attributes"] as! [String: Any]
318+
XCTAssertTrue(attributes[Event.ReservedAttribute.EXCEPTION_NAME] as! String == exception.name.rawValue)
319+
XCTAssertTrue(attributes[Event.ReservedAttribute.EXCEPTION_REASON] as? String == exception.reason)
320+
XCTAssertTrue(attributes[Event.ReservedAttribute.EXCEPTION_STACK] as! String
321+
== exception.callStackSymbols.joined(separator: "\n"))
322+
}
323+
311324
private func getTestEvent() throws -> [String: Any] {
312325
var testEvent: [String: Any] = JsonObject()
313326
let eventArray = try eventRecorder.getBatchEvent().eventsJson.jsonArray()

0 commit comments

Comments
 (0)