Skip to content

Commit

Permalink
Add more meta data to crash beacon (#33)
Browse files Browse the repository at this point in the history
Add more meta data, exceptionType exceptionCode and signal display processing to crash beacon
  • Loading branch information
Hongyan Jiang authored and GitHub Enterprise committed Dec 15, 2023
1 parent d76cdd5 commit 13f68fb
Show file tree
Hide file tree
Showing 12 changed files with 194 additions and 143 deletions.
5 changes: 5 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 1.6.8
- Add more meta data to crash beacon
- Add more exceptionType processing to crash beacon
- Display crash terminationReason as meta data rather than error message

## 1.6.7
- Add more raw crash payload info to stackTrace

Expand Down
2 changes: 1 addition & 1 deletion InstanaAgent.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Pod::Spec.new do |s|
#

s.name = "InstanaAgent"
s.version = "1.6.7"
s.version = "1.6.8"
s.summary = "Instana iOS agent."

# This description is used to generate tags and improve search results.
Expand Down
1 change: 1 addition & 0 deletions Sources/InstanaAgent/.swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ identifier_name:
excluded: # excluded via string array
- id
large_tuple: 3
cyclomatic_complexity: 20

2 changes: 1 addition & 1 deletion Sources/InstanaAgent/Configuration/Defines.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ let crashMetaKeyUserID = "ui"
let crashMetaKeyUserName = "un"
let crashMetaKeyUserEmail = "ue"

let currentInstanaCrashPayloadVersion = "0.93"
let currentInstanaCrashPayloadVersion = "0.94"
let defaultCrashViewName = "CrashView"

let maxSecondsToKeepCrashLog = (maxDaysToKeepCrashLog * 60 * 60 * 24)
2 changes: 1 addition & 1 deletion Sources/InstanaAgent/Configuration/VersionConfig.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
struct VersionConfig {
static let agentVersion = "1.6.7"
static let agentVersion = "1.6.8"
}
150 changes: 83 additions & 67 deletions Sources/InstanaAgent/Monitors/Metric/DiagnosticPayload.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class DiagnosticPayload: Codable {
let appVersion: String?
let osVersion: String?
let deviceType: String?
let platformArchitecture: String?
// crash
let exceptionType: Int?
let exceptionCode: Int?
Expand Down Expand Up @@ -69,6 +70,7 @@ class DiagnosticPayload: Codable {
case appVersion
case osVersion
case deviceType
case platformArchitecture
case exceptionType // crash
case exceptionCode
case signal
Expand Down Expand Up @@ -96,6 +98,7 @@ class DiagnosticPayload: Codable {
appVersion: String?,
osVersion: String?,
deviceType: String?,
platformArchitecture: String?,
exceptionType: Int?,
exceptionCode: Int?,
signal: Int?,
Expand All @@ -122,6 +125,7 @@ class DiagnosticPayload: Codable {
self.appVersion = appVersion
self.osVersion = osVersion
self.deviceType = deviceType
self.platformArchitecture = platformArchitecture
self.exceptionType = exceptionType
self.exceptionCode = exceptionCode
self.signal = signal
Expand Down Expand Up @@ -218,6 +222,7 @@ class DiagnosticPayload: Codable {
var appVersion: String?
let osVersion = oneDiag.metaData.osVersion
var deviceType: String?
var platformArchitecture: String?
var exceptionType: Int? // crash
var exceptionCode: Int?
var signal: Int?
Expand All @@ -244,6 +249,7 @@ class DiagnosticPayload: Codable {
appVersion = metaDict["appVersion"] as? String
bundleIdentifier = metaDict["bundleIdentifier"] as? String
deviceType = metaDict["deviceType"] as? String
platformArchitecture = metaDict["platformArchitecture"] as? String
exceptionType = metaDict["exceptionType"] as? Int // crash
exceptionCode = metaDict["exceptionCode"] as? Int
signal = metaDict["signal"] as? Int
Expand All @@ -257,6 +263,7 @@ class DiagnosticPayload: Codable {
}

let (errorType, errorMessage) = Self.parseErrorTypeAndMessage(crashType: crashType!, diagnostic: oneDiag)
guard errorMessage != nil else { continue }
let rawMXPayload = Self.getMXPayloadStr(diagnostic: oneDiag)
guard rawMXPayload != nil else { continue }

Expand All @@ -275,6 +282,7 @@ class DiagnosticPayload: Codable {
appVersion: appVersion,
osVersion: osVersion,
deviceType: deviceType,
platformArchitecture: platformArchitecture,
exceptionType: exceptionType,
exceptionCode: exceptionCode,
signal: signal,
Expand Down Expand Up @@ -363,95 +371,103 @@ class DiagnosticPayload: Codable {
let signal = crashDiag.signal

var errorCode: Int?
var errorMsg: String?
let machExceptionName = Self.getMachExceptionName(exceptionType: exceptionType,
exceptionCode: exceptionCode)
if machExceptionName != nil {
errorCode = Int(truncating: exceptionType!)
errorMsg = machExceptionName
} else {
let (sigName, sigCodeName) = Self.getSignalName(signal: signal)
if sigName != nil {
errorCode = Int(truncating: signal!)
if sigCodeName != nil {
errorMsg = sigName! + " - " + sigCodeName!
} else {
errorMsg = sigName
}
}
var errorMsg: String = ""
let machExceptionType = Self.getMachExceptionTypeDisplayName(exceptionType: exceptionType)
let machExceptionCode = Self.getMachExceptionCodeDisplayName(exceptionType: exceptionType,
exceptionCode: exceptionCode)
let sigName = Self.getSignalName(signal: signal)

if machExceptionType != nil {
errorMsg = machExceptionType!
}
if sigName != nil {
errorMsg += " (\(sigName!))"
}
if crashDiag.terminationReason != nil {
errorMsg = crashDiag.terminationReason!
if machExceptionCode != nil {
errorMsg += " - \(machExceptionCode!)"
}

if errorMsg.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
errorMsg = "unkown error"
}

if exceptionType != nil {
errorCode = Int(truncating: exceptionType!)
} else if signal != nil {
errorCode = Int(truncating: signal!)
}

return (errorCode, errorMsg)
}

static func getMachExceptionName(exceptionType: NSNumber?, exceptionCode: NSNumber?) -> String? {
static func getMachExceptionTypeDisplayName(exceptionType: NSNumber?) -> String? {
guard let exceptionType = exceptionType else {
return nil
}

var name: String?
var codeName: String?
switch Int32(truncating: exceptionType) {
case EXC_BAD_ACCESS:
name = "EXC_BAD_ACCESS"
codeName = Self.getMachExceptionBadAccessCodeName(exceptionType: exceptionType, exceptionCode: exceptionCode)
case EXC_BAD_INSTRUCTION:
name = "EXC_BAD_INSTRUCTION"
case EXC_ARITHMETIC:
name = "EXC_ARITHMETIC"
case EXC_BREAKPOINT:
name = "EXC_BREAKPOINT"
case EXC_GUARD:
name = "EXC_GUARD"
case EXC_BAD_ACCESS: // 1
return "EXC_BAD_ACCESS"
case EXC_BAD_INSTRUCTION: // 2
return "EXC_BAD_INSTRUCTION"
case EXC_ARITHMETIC: // 3
return "EXC_ARITHMETIC"
case EXC_BREAKPOINT: // 6
return "EXC_BREAKPOINT"
case EXC_CRASH: // 10
return "EXC_CRASH"
case EXC_RESOURCE: // 11
return "EXC_RESOURCE"
case EXC_GUARD: // 12
return "EXC_GUARD"
default:
name = exceptionType.stringValue
}
if name != nil {
if codeName != nil {
name = name! + " - " + codeName!
}
return name
return exceptionType.stringValue
}
return nil
}

static func getMachExceptionBadAccessCodeName(exceptionType: NSNumber, exceptionCode: NSNumber?) -> String? {
guard Int32(truncating: exceptionType) == EXC_BAD_ACCESS,
let exceptionCode = exceptionCode else { return nil }
static func getMachExceptionCodeDisplayName(exceptionType: NSNumber?, exceptionCode: NSNumber?) -> String? {
guard let exceptionCode = exceptionCode else {
return nil
}

switch Int32(truncating: exceptionCode) {
case KERN_INVALID_ADDRESS:
return "KERN_INVALID_ADDRESS"
case KERN_PROTECTION_FAILURE:
return "KERN_PROTECTION_FAILURE"
default:
return exceptionCode.stringValue
if exceptionType != nil, Int32(truncating: exceptionType!) == EXC_BAD_ACCESS {
switch Int32(truncating: exceptionCode) {
case KERN_INVALID_ADDRESS: // 1
return "KERN_INVALID_ADDRESS"
case KERN_PROTECTION_FAILURE: // 2
return "KERN_PROTECTION_FAILURE"
default:
return exceptionCode.stringValue
}
}
return exceptionCode.stringValue
}

static func getSignalName(signal: NSNumber?) -> (String?, String?) {
static func getSignalName(signal: NSNumber?) -> String? {
guard let signal = signal else {
return (nil, nil)
return nil
}
switch Int32(truncating: signal) {
case SIGABRT:
return ("SIGABRT", "ABORT")
case SIGBUS:
return ("SIGBUS", nil)
case SIGFPE:
return ("SIGFPE", nil)
case SIGILL:
return ("SIGILL", nil)
case SIGSEGV:
return ("SIGSEGV", nil)
case SIGSYS:
return ("SIGSYS", nil)
case SIGTRAP:
return ("SIGTRAP", nil)
case SIGQUIT: // 3
return ("SIGQUIT")
case SIGILL: // 4
return ("SIGILL")
case SIGTRAP: // 5
return ("SIGTRAP")
case SIGABRT: // 6
return ("SIGABRT - ABORT")
case SIGFPE: // 8
return ("SIGFPE")
case SIGKILL: // 9
return ("SIGKILL")
case SIGBUS: // 10
return ("SIGBUS")
case SIGSEGV: // 11
return ("SIGSEGV")
case SIGSYS: // 12
return ("SIGSYS")
default:
return (signal.stringValue, nil)
return (signal.stringValue)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,23 @@ struct DiagnosticSymbolicator {
let headers = outputHeaderSection(operation: operation, diagPayload: diagPayload)
stackTrace.setHeader(stHeaders: headers)

// Binary Images section
// process before Threads section so as to build indices of binary images for frames to reference
var dictUUIDs: [String: Int] = [:]
dictUUIDs.reserveCapacity(binaryImages.count)
binaryImages.forEach { bii in
let mAddr = (bii.maxAddress == 0 ? (needToSymbolicate ? "<unknown> " : "")
: String(format: "0x%llx", bii.maxAddress))

stackTrace.appendBinaryImage(startAddr: String(bii.loadAddress),
endAddr: needToSymbolicate ? mAddr : nil,
name: bii.binaryName,
arch: needToSymbolicate ? bii.arch : nil,
uuid: bii.binaryUUID,
path: needToSymbolicate ? bii.fullPath : nil)
dictUUIDs[bii.binaryUUID] = stackTrace.binaryImages.count - 1
}

// Threads section
for idx in 0 ..< threads.count {
if operation.isCancelled { return nil }
Expand Down Expand Up @@ -117,27 +134,21 @@ struct DiagnosticSymbolicator {
stOffset = String(symFrame!.symbol!.offset!)
}
}
stThread.appendFrame(name: frame.binaryName!,
var sampleCount: Int?
if frame.sampleCount != nil, frame.sampleCount! != 1 {
sampleCount = frame.sampleCount!
}
let filteredUUID = frame.binaryUUID!.uuidString.lowercased().filter { $0 != "-" }
stThread.appendFrame(index: dictUUIDs[filteredUUID] ?? -1,
name: frame.binaryName!,
address: String(format: "0x%llx", frame.address!),
offsetIntoBinaryTextSegment: String(frame.offsetIntoBinaryTextSegment!),
sampleCount: sampleCount,
symbol: stSymbol,
symbolOffset: stOffset)
}
stackTrace.appendThread(stThread: stThread)
}

// Binary Images section
binaryImages.forEach { bii in
let mAddr = (bii.maxAddress == 0 ? (needToSymbolicate ? "<unknown> " : "")
: String(format: "0x%llx", bii.maxAddress))

stackTrace.appendBinaryImage(startAddr: String(bii.loadAddress),
endAddr: needToSymbolicate ? mAddr : nil,
name: bii.binaryName,
arch: needToSymbolicate ? bii.arch : nil,
uuid: bii.binaryUUID,
path: needToSymbolicate ? bii.fullPath : nil)
}
return stackTrace.serialize()
}

Expand Down Expand Up @@ -167,6 +178,10 @@ struct DiagnosticSymbolicator {
stHeaders.append(StHeader(key: "OS Version", value: diagPayload.osVersion!))
}

if diagPayload.platformArchitecture != nil {
stHeaders.append(StHeader(key: "Platform Architecture", value: diagPayload.platformArchitecture!))
}

// crash
stHeaders.append(contentsOf: getCrashHeader(operation: operation, diagPayload: diagPayload))
// cpu
Expand Down Expand Up @@ -199,27 +214,27 @@ struct DiagnosticSymbolicator {
func getCrashHeader(operation: SymbolicationOperation, diagPayload: DiagnosticPayload) -> [StHeader] {
var crashHeaders = [StHeader]()

let exceptionType = DiagnosticPayload.getMachExceptionName(exceptionType: diagPayload.exceptionType as? NSNumber,
exceptionCode: diagPayload.exceptionCode as? NSNumber)
let (sigType, sigSubType) = DiagnosticPayload.getSignalName(signal: diagPayload.signal as? NSNumber)
let signal = (sigSubType == nil) ? sigType : sigType! + " - " + sigSubType!

var str: String?
if exceptionType != nil, signal != nil {
str = exceptionType! + " (" + signal! + ")"
} else if exceptionType != nil {
str = exceptionType!
} else {
str = signal
let exceptionTypeDisplay = DiagnosticPayload.getMachExceptionTypeDisplayName(
exceptionType: diagPayload.exceptionType as? NSNumber)
if exceptionTypeDisplay != nil {
crashHeaders.append(StHeader(key: "Exception Type", value: exceptionTypeDisplay!))
}

if str != nil {
crashHeaders.append(StHeader(key: "Exception Type", value: str!))
var exceptionCodeDisplay = DiagnosticPayload.getMachExceptionCodeDisplayName(
exceptionType: diagPayload.exceptionType as? NSNumber,
exceptionCode: diagPayload.exceptionCode as? NSNumber)
if exceptionCodeDisplay != nil {
if exceptionCodeDisplay != String(diagPayload.exceptionCode!) {
exceptionCodeDisplay! += " (diagPayload.exceptionCode!)"
}
crashHeaders.append(StHeader(key: "Exception Code", value: exceptionCodeDisplay!))
}

if diagPayload.exceptionCode != nil {
crashHeaders.append(StHeader(key: "Exception Code", value: String(diagPayload.exceptionCode!)))
let signal = DiagnosticPayload.getSignalName(signal: diagPayload.signal as? NSNumber)
if signal != nil {
crashHeaders.append(StHeader(key: "signal", value: signal!))
}

if diagPayload.terminationReason != nil {
crashHeaders.append(StHeader(key: "Termination Reason", value: diagPayload.terminationReason!))
}
Expand Down
Loading

0 comments on commit 13f68fb

Please sign in to comment.