From 0d51b513b1926998a36de1c4d3b68929f200a56e Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Sun, 8 Dec 2024 17:57:30 -0800 Subject: [PATCH 1/7] Additional Crash Report Data - Added additional fields to suppor Crash Symbolication. - Added debugger detection support, disabling crash detection --- .../contents.xcworkspacedata | 7 + .../CrashReporting.swift | 171 +++++++++++++++++- 2 files changed, 169 insertions(+), 9 deletions(-) create mode 100644 .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift b/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift index d2f70fa..771dde1 100644 --- a/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift +++ b/SplunkRumCrashReporting/SplunkRumCrashReporting/CrashReporting.swift @@ -24,6 +24,7 @@ let CrashReportingVersionString = "0.6.0" var TheCrashReporter: PLCrashReporter? private var customDataDictionary: [String: String] = [String: String]() +private var allUsedImageNames: Array = [] func initializeCrashReporting() { let startupSpan = buildTracer().spanBuilder(spanName: "SplunkRumCrashReporting").startSpan() @@ -39,11 +40,20 @@ func initializeCrashReporting() { return } let crashReporter = crashReporter_! - let success = crashReporter.enable() - SplunkRum.debugLog("PLCrashReporter enabled: "+success.description) - if !success { - startupSpan.setAttribute(key: "error.message", value: "Cannot enable PLCrashReporter") - return + + // Stop enable if debugger attached + var inDebugger = false + if isDebuggerAttached() { + startupSpan.setAttribute(key: "error.message", value: "Debugger present. Will not construct PLCrashReporter") + SplunkRum.debugLog("Debugger present. Will not enable PLCrashReporter") + inDebugger = true; + } + if inDebugger == false { + let success = crashReporter.enable() + SplunkRum.debugLog("PLCrashReporter enabled: "+success.description) + if !success { + startupSpan.setAttribute(key: "error.message", value: "Cannot enable PLCrashReporter") + } } TheCrashReporter = crashReporter updateCrashReportSessionId() @@ -58,6 +68,9 @@ func initializeCrashReporting() { } SplunkRum.debugLog("Had a pending crash report") do { + allUsedImageNames.removeAll() + let path = crashReporter.crashReportPath() + print(path as Any) let data = crashReporter.loadPendingCrashReportData() try loadPendingCrashReport(data) } catch { @@ -66,8 +79,8 @@ func initializeCrashReporting() { // yes, fall through to purge } crashReporter.purgePendingCrashReport() - } + private func buildTracer() -> Tracer { return OpenTelemetry.instance.tracerProvider.get(instrumentationName: "splunk-ios-crashreporting", instrumentationVersion: CrashReportingVersionString) @@ -138,10 +151,25 @@ 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) - for case let thread as PLCrashReportThreadInfo in report.threads where thread.crashed { - span.setAttribute(key: "exception.stacktrace", value: crashedThreadToStack(report: report, thread: thread)) - break + + var allThreads: Array = [] + for case let thread as PLCrashReportThreadInfo in report.threads { + + // Original crashed thread handler + if (thread.crashed) { + span.setAttribute(key: "exception.stacktrace", value: crashedThreadToStack(report: report, thread: thread)) + } + + // Detailed thread handler + allThreads.append(detailedThreadToStackFrames(report: report, thread: thread)) } + let threadPayload = convertArrayToJSONString(allThreads) ?? "Unable to create stack frames" + span.setAttribute(key: "exception.stackFrames", value: threadPayload) + var images: Array = [] + images = imageList(images: report.images) + let imagesPayload = convertArrayToJSONString(images) ?? "Unable to create images" + span.setAttribute(key: "exception.images", value: imagesPayload) + if report.hasExceptionInfo { span.setAttribute(key: "exception.type", value: report.exceptionInfo.exceptionName) span.setAttribute(key: "exception.message", value: report.exceptionInfo.exceptionReason) @@ -200,3 +228,128 @@ func formatStackFrame(frame: PLCrashReportStackFrameInfo, frameNum: Int, report: initializeCrashReporting() } } + +// Symbolication Support Code + +// Extracts detail for one thread +func detailedThreadToStackFrames(report: PLCrashReport, thread: PLCrashReportThreadInfo) -> Dictionary { + + var oneThread: [String:Any] = [:] + var allStackFrames: Array = [] + + let threadNum = thread.threadNumber as NSNumber + oneThread["threadNumber"] = threadNum.stringValue + oneThread["crashed"] = thread.crashed + + var frameNum = 0 + while frameNum < thread.stackFrames.count { + var oneFrame: [String:Any] = [:] + + let frame = thread.stackFrames[frameNum] as! PLCrashReportStackFrameInfo + let instructionPointer = frame.instructionPointer + oneFrame["instructionPointer"] = instructionPointer + + var baseAddress: UInt64 = 0 + var offset: UInt64 = 0 + var imageName = "???" + + let imageInfo = report.image(forAddress: instructionPointer) + if imageInfo != nil { + imageName = imageInfo?.imageName ?? "???" + baseAddress = imageInfo!.imageBaseAddress + offset = instructionPointer - baseAddress + } + oneFrame["imageName"] = imageName + allUsedImageNames.append(imageName) + + if frame.symbolInfo != nil { + let symbolName = frame.symbolInfo.symbolName + let symOffset = instructionPointer - frame.symbolInfo.startAddress + oneFrame["symbolName"] = symbolName + oneFrame["offset"] = symOffset + } else { + oneFrame["baseAddress"] = baseAddress + oneFrame["offset"] = offset + } + allStackFrames.append(oneFrame) + frameNum += 1 + } + oneThread["stackFrames"] = allStackFrames + return oneThread +} + +// Returns true if debugger is attached +private func isDebuggerAttached() -> Bool { + var debuggerIsAttached = false + + var name: [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()] + var info = kinfo_proc() + var infoSize = MemoryLayout.size + + _ = name.withUnsafeMutableBytes { (nameBytePtr: UnsafeMutableRawBufferPointer) -> Bool in + guard let nameBytesBlindMemory = nameBytePtr.bindMemory(to: Int32.self).baseAddress else { + return false + } + return sysctl(nameBytesBlindMemory, 4, &info, &infoSize, nil, 0) != -1 + } + if !debuggerIsAttached && (info.kp_proc.p_flag & P_TRACED) != 0 { + debuggerIsAttached = true + } + return debuggerIsAttached +} + +// Returns array of code images used by app +func imageList(images: Array) -> Array { + var outputImages: Array = [] + for image in images { + var imageDictionary: [String:Any] = [:] + guard let image = image as? PLCrashReportBinaryImageInfo else { + continue + } + + // Only add the image to the list if it was noted in the stack traces + if(allUsedImageNames.contains(image.imageName)) { + imageDictionary["codeType"] = cpuTypeDictionary(cpuType: image.codeType) + imageDictionary["baseAddress"] = image.imageBaseAddress + imageDictionary["imageSize"] = image.imageSize + imageDictionary["imagePath"] = image.imageName + imageDictionary["imageUUID"] = image.imageUUID + + outputImages.append(imageDictionary) + } + } + return outputImages +} + +// Returns formatted cpu data +func cpuTypeDictionary(cpuType: PLCrashReportProcessorInfo) -> Dictionary { + var dictionary: [String:String] = [:] + dictionary.updateValue(String(cpuType.type), forKey: "cType") + dictionary.updateValue(String(cpuType.subtype), forKey: "cSubType") + return dictionary +} + +// JSON support code +func convertDictionaryToJSONString(_ dictionary: [String: Any]) -> String? { + guard let jsonData = try? JSONSerialization.data(withJSONObject: dictionary, options: .prettyPrinted) else { + + return nil + } + guard let jsonString = String(data: jsonData, encoding: .utf8) else { + + return nil + } + return jsonString +} + +func convertArrayToJSONString(_ array: [Any]) -> String? { + guard let jsonData = try? JSONSerialization.data(withJSONObject: array, options: .prettyPrinted) else { + + return nil + } + guard let jsonString = String(data: jsonData, encoding: .utf8) else { + + return nil + } + return jsonString +} From baeb4431466f9578689679612534d7c60fe22b3e Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Mon, 9 Dec 2024 16:24:56 -0800 Subject: [PATCH 2/7] Update Crash Report Unit Tests - Added current binary plcrash file. - Added unit test against new crash report. --- .../CrashTests.swift | 55 ++++++++++++++++++ .../sample_v3.plcrash | Bin 0 -> 122673 bytes 2 files changed, 55 insertions(+) create mode 100644 SplunkRumCrashReporting/SplunkRumCrashReportingTests/sample_v3.plcrash diff --git a/SplunkRumCrashReporting/SplunkRumCrashReportingTests/CrashTests.swift b/SplunkRumCrashReporting/SplunkRumCrashReportingTests/CrashTests.swift index 97654d1..952db81 100644 --- a/SplunkRumCrashReporting/SplunkRumCrashReportingTests/CrashTests.swift +++ b/SplunkRumCrashReporting/SplunkRumCrashReportingTests/CrashTests.swift @@ -120,4 +120,59 @@ class CrashTests: XCTestCase { XCTAssertEqual(startup!.attributes["component"]?.description, "appstart") } + func testBasics_v3() throws { + let crashPath = Bundle(for: CrashTests.self).url(forResource: "sample_v3", withExtension: "plcrash")! + let crashData = try Data(contentsOf: crashPath) + + SplunkRumBuilder(beaconUrl: "http://127.0.0.1:8989/v1/traces", rumAuth: "FAKE") + .allowInsecureBeacon(enabled: true) + .debug(enabled: true) + .build() + let tracerProvider = TracerProviderBuilder() + .add(spanProcessor: SimpleSpanProcessor(spanExporter: TestSpanExporter())) + .build() + OpenTelemetry.registerTracerProvider(tracerProvider: tracerProvider) + localSpans.removeAll() + + SplunkRumCrashReporting.start() + try loadPendingCrashReport(crashData) + + XCTAssertEqual(localSpans.count, 2) + let crashReport = localSpans.first(where: { (span) -> Bool in + return span.name == "SIGTRAP" + }) + let startup = localSpans.first(where: { (span) -> Bool in + return span.name == "SplunkRumCrashReporting" + }) + + XCTAssertNotNil(crashReport) + XCTAssertNotEqual(crashReport!.attributes["splunk.rumSessionId"], crashReport!.attributes["crash.rumSessionId"]) + XCTAssertEqual(crashReport!.attributes["crash.rumSessionId"]?.description, "a9ef9e0a7683eaf973ec8fa4b31df3f9") + XCTAssertEqual(crashReport!.attributes["crash.address"]?.description, "6786470812") + XCTAssertEqual(crashReport!.attributes["component"]?.description, "crash") + XCTAssertEqual(crashReport!.attributes["error"]?.description, "true") + XCTAssertEqual(crashReport!.attributes["exception.type"]?.description, "SIGTRAP") + XCTAssertTrue(crashReport!.attributes["exception.stacktrace"]?.description.contains("UIKitCore") ?? false) + XCTAssertEqual(crashReport!.attributes["crash.batteryLevel"]?.description, "100.0%") + XCTAssertEqual(crashReport!.attributes["crash.freeDiskSpace"]?.description, "628.03 GB") + XCTAssertEqual(crashReport!.attributes["crash.freeMemory"]?.description, "31.88 GB") + XCTAssertEqual(crashReport!.attributes["crash.app.version"]?.description, "1.0") + XCTAssertNotNil(crashReport!.attributes["exception.stackFrames"]) + XCTAssertTrue(crashReport!.attributes["exception.stackFrames"]?.description.contains("threadNumber") ?? false) + XCTAssertTrue(crashReport!.attributes["exception.stackFrames"]?.description.contains("crashed") ?? false) + XCTAssertTrue(crashReport!.attributes["exception.stackFrames"]?.description.contains("instructionPointer") ?? false) + XCTAssertTrue(crashReport!.attributes["exception.stackFrames"]?.description.contains("baseAddress") ?? false) + XCTAssertTrue(crashReport!.attributes["exception.stackFrames"]?.description.contains("imageName") ?? false) + XCTAssertTrue(crashReport!.attributes["exception.stackFrames"]?.description.contains("offset") ?? false) + XCTAssertNotNil(crashReport!.attributes["exception.images"]) + XCTAssertTrue(crashReport!.attributes["exception.images"]?.description.contains("imageUUID") ?? false) + XCTAssertTrue(crashReport!.attributes["exception.images"]?.description.contains("imageSize") ?? false) + XCTAssertTrue(crashReport!.attributes["exception.images"]?.description.contains("imagePath") ?? false) + XCTAssertTrue(crashReport!.attributes["exception.images"]?.description.contains("codeType") ?? false) + XCTAssertTrue(crashReport!.attributes["exception.images"]?.description.contains("baseAddress") ?? false) + + XCTAssertNotNil(startup) + XCTAssertEqual(startup!.attributes["component"]?.description, "appstart") + + } } diff --git a/SplunkRumCrashReporting/SplunkRumCrashReportingTests/sample_v3.plcrash b/SplunkRumCrashReporting/SplunkRumCrashReportingTests/sample_v3.plcrash new file mode 100644 index 0000000000000000000000000000000000000000..8dfba9ae382e36604db1838d649fac8b5150b726 GIT binary patch literal 122673 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 O2%#CYpfr?X^aB9uL-Ozd literal 0 HcmV?d00001 From a4ea975eb07a88b7bb2c7df6005eada806c327ea Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Wed, 11 Dec 2024 15:33:08 -0800 Subject: [PATCH 3/7] Update ci.yml Change to macOS-14 from macOS-latest --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1e18a31..dc43987 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,7 @@ on: jobs: full-build: - runs-on: macOS-latest + runs-on: macOS-14 steps: - name: Checkout uses: actions/checkout@v1 From 3ba99405d5c0161cbf740cd27a3176e32e1a9b00 Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:08:25 -0800 Subject: [PATCH 4/7] CI Build Updates - Switch to MacOS 13 - Temporarily remove strict swiftlint --- .github/workflows/ci.yml | 2 +- fullbuild.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc43987..6375ab8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,7 @@ on: jobs: full-build: - runs-on: macOS-14 + runs-on: macOS-13 steps: - name: Checkout uses: actions/checkout@v1 diff --git a/fullbuild.sh b/fullbuild.sh index 47445b9..4398186 100755 --- a/fullbuild.sh +++ b/fullbuild.sh @@ -1,6 +1,6 @@ #!/bin/bash set -ex -swiftlint --strict +swiftlint # Make sure the version numbers on the podspec and CrashReporting.swift match echo "Checking that version numbers match" From 076484d308c91d51beca6b4b798225217a10201d Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:45:37 -0800 Subject: [PATCH 5/7] Update Tests Added sample_v3.plcrash file --- .../SplunkRumCrashReporting.xcodeproj/project.pbxproj | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/SplunkRumCrashReporting/SplunkRumCrashReporting.xcodeproj/project.pbxproj b/SplunkRumCrashReporting/SplunkRumCrashReporting.xcodeproj/project.pbxproj index 07d9a9b..2732b81 100644 --- a/SplunkRumCrashReporting/SplunkRumCrashReporting.xcodeproj/project.pbxproj +++ b/SplunkRumCrashReporting/SplunkRumCrashReporting.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -14,6 +14,7 @@ 86461EFC269729C0007C6DC0 /* CrashReporter in Frameworks */ = {isa = PBXBuildFile; productRef = 86461EFB269729C0007C6DC0 /* CrashReporter */; }; 86461F0526972A11007C6DC0 /* sample_v1.plcrash in Resources */ = {isa = PBXBuildFile; fileRef = 86461F0426972A11007C6DC0 /* sample_v1.plcrash */; }; 86D3180A271655B300B43379 /* SplunkOtel in Frameworks */ = {isa = PBXBuildFile; productRef = 86D31809271655B300B43379 /* SplunkOtel */; }; + BA93ED7B2D0BACF400330FAB /* sample_v3.plcrash in Resources */ = {isa = PBXBuildFile; fileRef = BA93ED7A2D0BACF400330FAB /* sample_v3.plcrash */; }; D774545D28E38CF40056159F /* DeviceStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = D774545C28E38CF40056159F /* DeviceStats.swift */; }; D7C64D1228E494C50086368D /* DeviceStatsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7C64D1128E494C50086368D /* DeviceStatsTests.swift */; }; D7D14290293804A200CAD87E /* sample_v2.plcrash in Resources */ = {isa = PBXBuildFile; fileRef = D7D1428F293804A200CAD87E /* sample_v2.plcrash */; }; @@ -38,6 +39,7 @@ 86461EEA26972906007C6DC0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 86461EF626972964007C6DC0 /* CrashReporting.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CrashReporting.swift; sourceTree = ""; }; 86461F0426972A11007C6DC0 /* sample_v1.plcrash */ = {isa = PBXFileReference; lastKnownFileType = file.plcrash; path = sample_v1.plcrash; sourceTree = ""; }; + BA93ED7A2D0BACF400330FAB /* sample_v3.plcrash */ = {isa = PBXFileReference; lastKnownFileType = file; path = sample_v3.plcrash; sourceTree = ""; }; D774545C28E38CF40056159F /* DeviceStats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceStats.swift; sourceTree = ""; }; D7C64D1128E494C50086368D /* DeviceStatsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceStatsTests.swift; sourceTree = ""; }; D7D1428F293804A200CAD87E /* sample_v2.plcrash */ = {isa = PBXFileReference; lastKnownFileType = file; path = sample_v2.plcrash; sourceTree = ""; }; @@ -96,6 +98,7 @@ 86461EE726972906007C6DC0 /* SplunkRumCrashReportingTests */ = { isa = PBXGroup; children = ( + BA93ED7A2D0BACF400330FAB /* sample_v3.plcrash */, D7D1428F293804A200CAD87E /* sample_v2.plcrash */, 86461F0426972A11007C6DC0 /* sample_v1.plcrash */, 86461EE826972906007C6DC0 /* CrashTests.swift */, @@ -213,6 +216,7 @@ buildActionMask = 2147483647; files = ( 86461F0526972A11007C6DC0 /* sample_v1.plcrash in Resources */, + BA93ED7B2D0BACF400330FAB /* sample_v3.plcrash in Resources */, D7D14290293804A200CAD87E /* sample_v2.plcrash in Resources */, ); runOnlyForDeploymentPostprocessing = 0; From fef857cf95c801f5fbb955a1b3f24dca38613ef0 Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Fri, 13 Dec 2024 09:58:07 -0800 Subject: [PATCH 6/7] Revert "Update Tests" This reverts commit 076484d308c91d51beca6b4b798225217a10201d. --- .../SplunkRumCrashReporting.xcodeproj/project.pbxproj | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/SplunkRumCrashReporting/SplunkRumCrashReporting.xcodeproj/project.pbxproj b/SplunkRumCrashReporting/SplunkRumCrashReporting.xcodeproj/project.pbxproj index 2732b81..07d9a9b 100644 --- a/SplunkRumCrashReporting/SplunkRumCrashReporting.xcodeproj/project.pbxproj +++ b/SplunkRumCrashReporting/SplunkRumCrashReporting.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ @@ -14,7 +14,6 @@ 86461EFC269729C0007C6DC0 /* CrashReporter in Frameworks */ = {isa = PBXBuildFile; productRef = 86461EFB269729C0007C6DC0 /* CrashReporter */; }; 86461F0526972A11007C6DC0 /* sample_v1.plcrash in Resources */ = {isa = PBXBuildFile; fileRef = 86461F0426972A11007C6DC0 /* sample_v1.plcrash */; }; 86D3180A271655B300B43379 /* SplunkOtel in Frameworks */ = {isa = PBXBuildFile; productRef = 86D31809271655B300B43379 /* SplunkOtel */; }; - BA93ED7B2D0BACF400330FAB /* sample_v3.plcrash in Resources */ = {isa = PBXBuildFile; fileRef = BA93ED7A2D0BACF400330FAB /* sample_v3.plcrash */; }; D774545D28E38CF40056159F /* DeviceStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = D774545C28E38CF40056159F /* DeviceStats.swift */; }; D7C64D1228E494C50086368D /* DeviceStatsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7C64D1128E494C50086368D /* DeviceStatsTests.swift */; }; D7D14290293804A200CAD87E /* sample_v2.plcrash in Resources */ = {isa = PBXBuildFile; fileRef = D7D1428F293804A200CAD87E /* sample_v2.plcrash */; }; @@ -39,7 +38,6 @@ 86461EEA26972906007C6DC0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 86461EF626972964007C6DC0 /* CrashReporting.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CrashReporting.swift; sourceTree = ""; }; 86461F0426972A11007C6DC0 /* sample_v1.plcrash */ = {isa = PBXFileReference; lastKnownFileType = file.plcrash; path = sample_v1.plcrash; sourceTree = ""; }; - BA93ED7A2D0BACF400330FAB /* sample_v3.plcrash */ = {isa = PBXFileReference; lastKnownFileType = file; path = sample_v3.plcrash; sourceTree = ""; }; D774545C28E38CF40056159F /* DeviceStats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceStats.swift; sourceTree = ""; }; D7C64D1128E494C50086368D /* DeviceStatsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceStatsTests.swift; sourceTree = ""; }; D7D1428F293804A200CAD87E /* sample_v2.plcrash */ = {isa = PBXFileReference; lastKnownFileType = file; path = sample_v2.plcrash; sourceTree = ""; }; @@ -98,7 +96,6 @@ 86461EE726972906007C6DC0 /* SplunkRumCrashReportingTests */ = { isa = PBXGroup; children = ( - BA93ED7A2D0BACF400330FAB /* sample_v3.plcrash */, D7D1428F293804A200CAD87E /* sample_v2.plcrash */, 86461F0426972A11007C6DC0 /* sample_v1.plcrash */, 86461EE826972906007C6DC0 /* CrashTests.swift */, @@ -216,7 +213,6 @@ buildActionMask = 2147483647; files = ( 86461F0526972A11007C6DC0 /* sample_v1.plcrash in Resources */, - BA93ED7B2D0BACF400330FAB /* sample_v3.plcrash in Resources */, D7D14290293804A200CAD87E /* sample_v2.plcrash in Resources */, ); runOnlyForDeploymentPostprocessing = 0; From c0a9b2c273ac74486f49ea75722550f08b0f25ff Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:33:07 -0800 Subject: [PATCH 7/7] Roll back tests --- .../CrashTests.swift | 55 ------------------ .../sample_v3.plcrash | Bin 122673 -> 0 bytes 2 files changed, 55 deletions(-) delete mode 100644 SplunkRumCrashReporting/SplunkRumCrashReportingTests/sample_v3.plcrash diff --git a/SplunkRumCrashReporting/SplunkRumCrashReportingTests/CrashTests.swift b/SplunkRumCrashReporting/SplunkRumCrashReportingTests/CrashTests.swift index 952db81..97654d1 100644 --- a/SplunkRumCrashReporting/SplunkRumCrashReportingTests/CrashTests.swift +++ b/SplunkRumCrashReporting/SplunkRumCrashReportingTests/CrashTests.swift @@ -120,59 +120,4 @@ class CrashTests: XCTestCase { XCTAssertEqual(startup!.attributes["component"]?.description, "appstart") } - func testBasics_v3() throws { - let crashPath = Bundle(for: CrashTests.self).url(forResource: "sample_v3", withExtension: "plcrash")! - let crashData = try Data(contentsOf: crashPath) - - SplunkRumBuilder(beaconUrl: "http://127.0.0.1:8989/v1/traces", rumAuth: "FAKE") - .allowInsecureBeacon(enabled: true) - .debug(enabled: true) - .build() - let tracerProvider = TracerProviderBuilder() - .add(spanProcessor: SimpleSpanProcessor(spanExporter: TestSpanExporter())) - .build() - OpenTelemetry.registerTracerProvider(tracerProvider: tracerProvider) - localSpans.removeAll() - - SplunkRumCrashReporting.start() - try loadPendingCrashReport(crashData) - - XCTAssertEqual(localSpans.count, 2) - let crashReport = localSpans.first(where: { (span) -> Bool in - return span.name == "SIGTRAP" - }) - let startup = localSpans.first(where: { (span) -> Bool in - return span.name == "SplunkRumCrashReporting" - }) - - XCTAssertNotNil(crashReport) - XCTAssertNotEqual(crashReport!.attributes["splunk.rumSessionId"], crashReport!.attributes["crash.rumSessionId"]) - XCTAssertEqual(crashReport!.attributes["crash.rumSessionId"]?.description, "a9ef9e0a7683eaf973ec8fa4b31df3f9") - XCTAssertEqual(crashReport!.attributes["crash.address"]?.description, "6786470812") - XCTAssertEqual(crashReport!.attributes["component"]?.description, "crash") - XCTAssertEqual(crashReport!.attributes["error"]?.description, "true") - XCTAssertEqual(crashReport!.attributes["exception.type"]?.description, "SIGTRAP") - XCTAssertTrue(crashReport!.attributes["exception.stacktrace"]?.description.contains("UIKitCore") ?? false) - XCTAssertEqual(crashReport!.attributes["crash.batteryLevel"]?.description, "100.0%") - XCTAssertEqual(crashReport!.attributes["crash.freeDiskSpace"]?.description, "628.03 GB") - XCTAssertEqual(crashReport!.attributes["crash.freeMemory"]?.description, "31.88 GB") - XCTAssertEqual(crashReport!.attributes["crash.app.version"]?.description, "1.0") - XCTAssertNotNil(crashReport!.attributes["exception.stackFrames"]) - XCTAssertTrue(crashReport!.attributes["exception.stackFrames"]?.description.contains("threadNumber") ?? false) - XCTAssertTrue(crashReport!.attributes["exception.stackFrames"]?.description.contains("crashed") ?? false) - XCTAssertTrue(crashReport!.attributes["exception.stackFrames"]?.description.contains("instructionPointer") ?? false) - XCTAssertTrue(crashReport!.attributes["exception.stackFrames"]?.description.contains("baseAddress") ?? false) - XCTAssertTrue(crashReport!.attributes["exception.stackFrames"]?.description.contains("imageName") ?? false) - XCTAssertTrue(crashReport!.attributes["exception.stackFrames"]?.description.contains("offset") ?? false) - XCTAssertNotNil(crashReport!.attributes["exception.images"]) - XCTAssertTrue(crashReport!.attributes["exception.images"]?.description.contains("imageUUID") ?? false) - XCTAssertTrue(crashReport!.attributes["exception.images"]?.description.contains("imageSize") ?? false) - XCTAssertTrue(crashReport!.attributes["exception.images"]?.description.contains("imagePath") ?? false) - XCTAssertTrue(crashReport!.attributes["exception.images"]?.description.contains("codeType") ?? false) - XCTAssertTrue(crashReport!.attributes["exception.images"]?.description.contains("baseAddress") ?? false) - - XCTAssertNotNil(startup) - XCTAssertEqual(startup!.attributes["component"]?.description, "appstart") - - } } diff --git a/SplunkRumCrashReporting/SplunkRumCrashReportingTests/sample_v3.plcrash b/SplunkRumCrashReporting/SplunkRumCrashReportingTests/sample_v3.plcrash deleted file mode 100644 index 8dfba9ae382e36604db1838d649fac8b5150b726..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 122673 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 O2%#CYpfr?X^aB9uL-Ozd