From 6d1cffc6c018eeb7eb3bc6ba8fa255595169a72d Mon Sep 17 00:00:00 2001 From: Shraddha Hattimare Date: Wed, 16 Mar 2022 17:39:01 +0530 Subject: [PATCH 1/6] feature/APMI-2820 changes in crashreporting.swift --- .../CrashReporting.swift | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift b/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift index 3803695..88afd9d 100644 --- a/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift +++ b/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift @@ -49,6 +49,10 @@ func initializeCrashReporting() { SplunkRum.addSessionIdChangeCallback { updateCrashReportSessionId() } + updateCrashReportScreenName() + SplunkRum.addScreenNameChangeCallback { + updateCrashReportScreenName() + } // Now for the pending report if there is one if !crashReporter.hasPendingCrashReport() { return @@ -72,10 +76,16 @@ private func buildTracer() -> Tracer { func updateCrashReportSessionId() { DispatchQueue.main.async { - TheCrashReporter?.customData = SplunkRum.getSessionId().data(using: .utf8) + let str = SplunkRum.getSessionId() + "|" + SplunkRum.getCurrentScreenName() + TheCrashReporter?.customData = str.data(using: .utf8) + } +} +func updateCrashReportScreenName() { + DispatchQueue.main.async { + let str = SplunkRum.getSessionId() + "|" + SplunkRum.getCurrentScreenName() + TheCrashReporter?.customData = str.data(using: .utf8) } } - func loadPendingCrashReport(_ data: Data!) throws { SplunkRum.debugLog("Loading crash report of size \(data?.count as Any)") let report = try PLCrashReport(data: data) @@ -84,7 +94,9 @@ func loadPendingCrashReport(_ data: Data!) throws { exceptionType = report.exceptionInfo.exceptionName } - let oldSessionId = String(decoding: report.customData, as: UTF8.self) + let strArr = String(decoding: report.customData, as: UTF8.self).components(separatedBy: "|") + let oldSessionId = strArr[0] + let screenName = strArr[1] // Turn the report into a span let now = Date() let span = buildTracer().spanBuilder(spanName: exceptionType ?? "unknown").setStartTime(time: now).setNoParent().startSpan() @@ -96,6 +108,7 @@ func loadPendingCrashReport(_ data: Data!) throws { span.addEvent(name: "crash.timestamp", timestamp: report.systemInfo.timestamp) span.setAttribute(key: "exception.type", value: exceptionType ?? "unknown") span.setAttribute(key: "crash.address", value: report.signalInfo.address.description) + span.setAttribute(key: "screen.name", value: screenName) for case let thread as PLCrashReportThreadInfo in report.threads where thread.crashed { span.setAttribute(key: "exception.stacktrace", value: crashedThreadToStack(report: report, thread: thread)) break From 3eade7cc2a4fc7e8c73c61a6df34188cc29be938 Mon Sep 17 00:00:00 2001 From: Shraddha Hattimare Date: Wed, 30 Mar 2022 11:30:31 +0530 Subject: [PATCH 2/6] feature/APMI-2820 Changed logic of saving sessionid and screen name as custom data. --- .../CrashReporting.swift | 60 +++++++++++++++---- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift b/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift index 88afd9d..15e9bda 100644 --- a/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift +++ b/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift @@ -24,6 +24,9 @@ let CrashReportingVersionString = "0.2.0" var TheCrashReporter: PLCrashReporter? +let keyID = "SessionID" +let keyName = "ScreenName" + func initializeCrashReporting() { let startupSpan = buildTracer().spanBuilder(spanName: "SplunkRumCrashReporting").startSpan() startupSpan.setAttribute(key: "component", value: "appstart") @@ -49,9 +52,8 @@ func initializeCrashReporting() { SplunkRum.addSessionIdChangeCallback { updateCrashReportSessionId() } - updateCrashReportScreenName() - SplunkRum.addScreenNameChangeCallback { - updateCrashReportScreenName() + SplunkRum.addScreenNameChangeCallback { name in + updateCrashReportScreenName(screenname: name) } // Now for the pending report if there is one if !crashReporter.hasPendingCrashReport() { @@ -74,16 +76,52 @@ private func buildTracer() -> Tracer { } +func dataToDictionary(data: Data) ->[String:String]? { + let dicFromData = try? PropertyListSerialization.propertyList(from: data, options: PropertyListSerialization.ReadOptions.mutableContainers, format: nil) + return dicFromData as? [String: String] +} + +func dictionaryToData(dict: [String:String]) -> Data? { + let data = try? PropertyListSerialization.data(fromPropertyList: dict, format: PropertyListSerialization.PropertyListFormat.binary, options: 0) + return data +} + func updateCrashReportSessionId() { DispatchQueue.main.async { - let str = SplunkRum.getSessionId() + "|" + SplunkRum.getCurrentScreenName() - TheCrashReporter?.customData = str.data(using: .utf8) + saveSessionIDInToCustomData() + } +} + +func saveSessionIDInToCustomData() { + if let dict = fetchFromCustomData() { + let screenName = dict[keyName] ?? "" + saveIntoCustomData(dict: [keyID:SplunkRum.getSessionId(),keyName:screenName]) + }else { + saveIntoCustomData(dict: [keyID:SplunkRum.getSessionId()]) } } -func updateCrashReportScreenName() { + +func saveScreenNameInToCustomData(screenname:String) { + if let dict = fetchFromCustomData(){ + let oldsessionid = dict[keyID] ?? "" + saveIntoCustomData(dict: [keyID:oldsessionid,keyName:screenname]) + }else { + saveIntoCustomData(dict: [keyName:screenname]) + } +} + +func saveIntoCustomData(dict: [String:String]) { + TheCrashReporter?.customData = dictionaryToData(dict: dict) +} + +func fetchFromCustomData() -> [String:String]? { + guard let data = TheCrashReporter?.customData else { return nil} + let dicFromData = dataToDictionary(data: data) + return dicFromData +} +func updateCrashReportScreenName(screenname:String) { DispatchQueue.main.async { - let str = SplunkRum.getSessionId() + "|" + SplunkRum.getCurrentScreenName() - TheCrashReporter?.customData = str.data(using: .utf8) + saveScreenNameInToCustomData(screenname: screenname) } } func loadPendingCrashReport(_ data: Data!) throws { @@ -94,9 +132,9 @@ func loadPendingCrashReport(_ data: Data!) throws { exceptionType = report.exceptionInfo.exceptionName } - let strArr = String(decoding: report.customData, as: UTF8.self).components(separatedBy: "|") - let oldSessionId = strArr[0] - let screenName = strArr[1] + guard let dict = dataToDictionary(data: report.customData) else {return} + let oldSessionId = dict[keyID] ?? "" + let screenName = dict[keyName] ?? "" // Turn the report into a span let now = Date() let span = buildTracer().spanBuilder(spanName: exceptionType ?? "unknown").setStartTime(time: now).setNoParent().startSpan() From 1abe1e75ea78728acb0452d38d34678c6fedf1dd Mon Sep 17 00:00:00 2001 From: Shraddha Hattimare Date: Wed, 30 Mar 2022 11:42:20 +0530 Subject: [PATCH 3/6] feature/APMI-2820 linting issue solved --- .../CrashReporting.swift | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift b/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift index 15e9bda..d7583c8 100644 --- a/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift +++ b/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift @@ -76,12 +76,12 @@ private func buildTracer() -> Tracer { } -func dataToDictionary(data: Data) ->[String:String]? { +func dataToDictionary(data: Data) -> [String: String]? { let dicFromData = try? PropertyListSerialization.propertyList(from: data, options: PropertyListSerialization.ReadOptions.mutableContainers, format: nil) return dicFromData as? [String: String] } -func dictionaryToData(dict: [String:String]) -> Data? { +func dictionaryToData(dict: [String: String]) -> Data? { let data = try? PropertyListSerialization.data(fromPropertyList: dict, format: PropertyListSerialization.PropertyListFormat.binary, options: 0) return data } @@ -95,31 +95,31 @@ func updateCrashReportSessionId() { func saveSessionIDInToCustomData() { if let dict = fetchFromCustomData() { let screenName = dict[keyName] ?? "" - saveIntoCustomData(dict: [keyID:SplunkRum.getSessionId(),keyName:screenName]) - }else { - saveIntoCustomData(dict: [keyID:SplunkRum.getSessionId()]) + saveIntoCustomData(dict: [keyID: SplunkRum.getSessionId(), keyName: screenName]) + } else { + saveIntoCustomData(dict: [keyID: SplunkRum.getSessionId()]) } } -func saveScreenNameInToCustomData(screenname:String) { - if let dict = fetchFromCustomData(){ +func saveScreenNameInToCustomData(screenname: String) { + if let dict = fetchFromCustomData() { let oldsessionid = dict[keyID] ?? "" - saveIntoCustomData(dict: [keyID:oldsessionid,keyName:screenname]) - }else { - saveIntoCustomData(dict: [keyName:screenname]) + saveIntoCustomData(dict: [keyID: oldsessionid, keyName: screenname]) + } else { + saveIntoCustomData(dict: [keyName: screenname]) } } -func saveIntoCustomData(dict: [String:String]) { +func saveIntoCustomData(dict: [String: String]) { TheCrashReporter?.customData = dictionaryToData(dict: dict) } -func fetchFromCustomData() -> [String:String]? { +func fetchFromCustomData() -> [String: String]? { guard let data = TheCrashReporter?.customData else { return nil} let dicFromData = dataToDictionary(data: data) return dicFromData } -func updateCrashReportScreenName(screenname:String) { +func updateCrashReportScreenName(screenname: String) { DispatchQueue.main.async { saveScreenNameInToCustomData(screenname: screenname) } From c7d08bc41d41d2ef87402d41a408a936539baa6e Mon Sep 17 00:00:00 2001 From: Shraddha Hattimare Date: Thu, 31 Mar 2022 19:10:39 +0530 Subject: [PATCH 4/6] feature/APMI-2820 minor changes --- .../CrashReporting.swift | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift b/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift index d7583c8..edfaabc 100644 --- a/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift +++ b/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift @@ -24,8 +24,8 @@ let CrashReportingVersionString = "0.2.0" var TheCrashReporter: PLCrashReporter? -let keyID = "SessionID" -let keyName = "ScreenName" +let sessionIdKey = "SessionID" +let screenNameKey = "ScreenName" func initializeCrashReporting() { let startupSpan = buildTracer().spanBuilder(spanName: "SplunkRumCrashReporting").startSpan() @@ -88,25 +88,25 @@ func dictionaryToData(dict: [String: String]) -> Data? { func updateCrashReportSessionId() { DispatchQueue.main.async { - saveSessionIDInToCustomData() + saveSessionIDIntoCustomData() } } -func saveSessionIDInToCustomData() { +func saveSessionIDIntoCustomData() { if let dict = fetchFromCustomData() { - let screenName = dict[keyName] ?? "" - saveIntoCustomData(dict: [keyID: SplunkRum.getSessionId(), keyName: screenName]) + let screenName = dict[screenNameKey] ?? "" + saveIntoCustomData(dict: [sessionIdKey: SplunkRum.getSessionId(), screenNameKey: screenName]) } else { - saveIntoCustomData(dict: [keyID: SplunkRum.getSessionId()]) + saveIntoCustomData(dict: [sessionIdKey: SplunkRum.getSessionId()]) } } -func saveScreenNameInToCustomData(screenname: String) { +func saveScreenNameIntoCustomData(screenname: String) { if let dict = fetchFromCustomData() { - let oldsessionid = dict[keyID] ?? "" - saveIntoCustomData(dict: [keyID: oldsessionid, keyName: screenname]) + let oldsessionid = dict[sessionIdKey] ?? "" + saveIntoCustomData(dict: [sessionIdKey: oldsessionid, screenNameKey: screenname]) } else { - saveIntoCustomData(dict: [keyName: screenname]) + saveIntoCustomData(dict: [screenNameKey: screenname]) } } @@ -121,7 +121,7 @@ func fetchFromCustomData() -> [String: String]? { } func updateCrashReportScreenName(screenname: String) { DispatchQueue.main.async { - saveScreenNameInToCustomData(screenname: screenname) + saveScreenNameIntoCustomData(screenname: screenname) } } func loadPendingCrashReport(_ data: Data!) throws { @@ -133,8 +133,8 @@ func loadPendingCrashReport(_ data: Data!) throws { } guard let dict = dataToDictionary(data: report.customData) else {return} - let oldSessionId = dict[keyID] ?? "" - let screenName = dict[keyName] ?? "" + let oldSessionId = dict[sessionIdKey] ?? "" + let screenName = dict[screenNameKey] ?? "" // Turn the report into a span let now = Date() let span = buildTracer().spanBuilder(spanName: exceptionType ?? "unknown").setStartTime(time: now).setNoParent().startSpan() From 261507502db9573ddaa5884e37f22238d91a9b11 Mon Sep 17 00:00:00 2001 From: Shraddha Hattimare Date: Mon, 11 Apr 2022 12:18:01 +0530 Subject: [PATCH 5/6] feature/APMI-2820 remove guard let , send crash span if it has not sessionid or screen name data. --- .../CrashReporting.swift | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift b/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift index edfaabc..be9be50 100644 --- a/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift +++ b/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift @@ -131,22 +131,27 @@ func loadPendingCrashReport(_ data: Data!) throws { if report.hasExceptionInfo { exceptionType = report.exceptionInfo.exceptionName } - - guard let dict = dataToDictionary(data: report.customData) else {return} - let oldSessionId = dict[sessionIdKey] ?? "" - let screenName = dict[screenNameKey] ?? "" // Turn the report into a span let now = Date() let span = buildTracer().spanBuilder(spanName: exceptionType ?? "unknown").setStartTime(time: now).setNoParent().startSpan() + if report.customData != nil { + let dict = dataToDictionary(data: report.customData) + if dict?[sessionIdKey] != nil { + let oldSessionId = dict?[sessionIdKey] + span.setAttribute(key: "crash.rumSessionId", value: oldSessionId!) + } + if dict?[screenNameKey] != nil { + let screenName = dict?[screenNameKey] + span.setAttribute(key: "screen.name", value: screenName!) + } + } span.setAttribute(key: "component", value: "crash") - span.setAttribute(key: "crash.rumSessionId", value: oldSessionId) // "marketing version" here matches up to our use of CFBundleShortVersionString span.setAttribute(key: "crash.app.version", value: report.applicationInfo.applicationMarketingVersion) span.setAttribute(key: "error", value: true) span.addEvent(name: "crash.timestamp", timestamp: report.systemInfo.timestamp) span.setAttribute(key: "exception.type", value: exceptionType ?? "unknown") span.setAttribute(key: "crash.address", value: report.signalInfo.address.description) - span.setAttribute(key: "screen.name", value: screenName) for case let thread as PLCrashReportThreadInfo in report.threads where thread.crashed { span.setAttribute(key: "exception.stacktrace", value: crashedThreadToStack(report: report, thread: thread)) break From 4d19f5e9fe5da4826c1c6e0d431daaf60ebfb99c Mon Sep 17 00:00:00 2001 From: Shraddha Hattimare Date: Thu, 14 Apr 2022 11:44:03 +0530 Subject: [PATCH 6/6] feature/APMI-2820 iOS crash does not retain old screen name test case added to check that screen.name is there or not --- .../SplunkRumCrashReportingTests/CrashTests.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SplunkRumCrashReporting/SplunkRumCrashReportingTests/CrashTests.swift b/SplunkRumCrashReporting/SplunkRumCrashReportingTests/CrashTests.swift index f736cd1..9944e7e 100644 --- a/SplunkRumCrashReporting/SplunkRumCrashReportingTests/CrashTests.swift +++ b/SplunkRumCrashReporting/SplunkRumCrashReportingTests/CrashTests.swift @@ -73,6 +73,8 @@ class CrashTests: XCTestCase { XCTAssertNotNil(startup) XCTAssertEqual(startup!.attributes["component"]?.description, "appstart") + + XCTAssertNotNil(crashReport!.attributes["screen.name"]) } }