如何在Crashlytics非致命错误报告中覆盖库与文件名?
Crashlytics适配依赖注入式日志封装的解决方案
针对封装Logger接口后,Crashlytics上报错误时仅显示LoggerImpl栈帧的问题,有以下几种可行方案:
方案一:手动包装Error并注入原始调用栈
利用NSError的NSStackTraceKey字段,在Logger实现中捕获并清理掉自身的栈帧,将原始错误的调用栈传递给Crashlytics:
final class LoggerImpl: Logger { func log(error: Error) { // 获取当前调用栈,移除LoggerImpl相关的栈帧 var stackTrace = Thread.callStackSymbols while let topFrame = stackTrace.first, topFrame.contains("LoggerImpl.log(error:)") { stackTrace.removeFirst() } // 包装原始错误,注入清理后的调用栈 let wrappedUserInfo: [String: Any] = [ NSUnderlyingErrorKey: error, NSStackTraceKey: stackTrace ] let wrappedError = NSError( domain: error._domain, code: error._code, userInfo: wrappedUserInfo ) Crashlytics.crashlytics().record(error: wrappedError) } }
Crashlytics会识别NSStackTraceKey字段,自动展示原始错误的调用栈,而非LoggerImpl的位置。
方案二:使用自定义异常上报API
直接调用Crashlytics的recordCustomExceptionName方法,传入自定义的堆栈帧数组,完全绕过默认的栈帧捕获逻辑:
import Crashlytics final class LoggerImpl: Logger { func log(error: Error) { // 获取调用栈地址,移除LoggerImpl及当前方法的栈帧(根据实际调用深度调整移除数量) var stackAddresses = Thread.callStackReturnAddresses stackAddresses.removeFirst(2) // 转换为Crashlytics要求的CLSStackFrame数组 let crashFrames = stackAddresses.map { CLSStackFrame(address: $0) } // 上报自定义异常 Crashlytics.crashlytics().recordCustomExceptionName( error._domain, reason: error.localizedDescription, frameArray: crashFrames ) } }
这种方式能直接控制上报的堆栈内容,确保错误来源的准确性。
方案三:扩展Error自动捕获堆栈
通过扩展Error类型,让业务模块可以便捷地传递带原始栈帧的错误(需业务侧配合调用):
extension Error { func withOriginalStackTrace() -> NSError { var userInfo = self._userInfo ?? [:] userInfo[NSStackTraceKey] = Thread.callStackSymbols return NSError( domain: self._domain, code: self._code, userInfo: userInfo ) } }
业务侧调用示例:
do { try someRiskyOperation() } catch { logger.log(error: error.withOriginalStackTrace()) }
内容的提问来源于stack exchange,提问作者Jacob Bartlett
相关产品推荐
相关产品推荐

