新增模块:XuqmBugCollectSDK - BugCollectSDK: 主入口,错误捕获 API - CrashCapture: 崩溃捕获(NSException + POSIX 信号) - IssueEvent/LogEvent: 数据模型 - Fingerprint: 错误指纹计算(SHA-256) - LogQueue: 内存队列 + 定时上传 - LogStorage: 崩溃文件持久化 - LogUploader: HTTP 上传到服务端 - FunnelTracker: 漏斗追踪 功能: - captureError/captureCrash 捕获错误 - addBreadcrumb 添加面包屑 - event 记录自定义事件 - warn/info 日志级别记录 - 自动初始化(onInitialize hook) Co-Authored-By: Claude <noreply@anthropic.com>
101 行
2.5 KiB
Swift
101 行
2.5 KiB
Swift
import Foundation
|
|
|
|
/// 日志队列 - 内存队列 + 定时上传
|
|
final class LogQueue {
|
|
|
|
private let appKey: String
|
|
private let sdkName: String
|
|
private let sdkVersion: String
|
|
private let uploader: LogUploader
|
|
private let storage: LogStorage
|
|
|
|
private var queue: [Any] = []
|
|
private let queueLock = NSLock()
|
|
private var timer: Timer?
|
|
private let flushInterval: TimeInterval = 30
|
|
private let maxQueueSize = 50
|
|
|
|
init(appKey: String, sdkName: String, sdkVersion: String) {
|
|
self.appKey = appKey
|
|
self.sdkName = sdkName
|
|
self.sdkVersion = sdkVersion
|
|
self.uploader = LogUploader(appKey: appKey)
|
|
self.storage = LogStorage(appKey: appKey)
|
|
}
|
|
|
|
/// 启动定时上传
|
|
func start() {
|
|
// 上传待处理的崩溃
|
|
uploadPendingCrashes()
|
|
|
|
// 启动定时器
|
|
timer = Timer.scheduledTimer(withTimeInterval: flushInterval, repeats: true) { [weak self] _ in
|
|
self?.flush()
|
|
}
|
|
}
|
|
|
|
/// 停止队列
|
|
func stop() {
|
|
timer?.invalidate()
|
|
timer = nil
|
|
flush()
|
|
}
|
|
|
|
/// 推送事件
|
|
func push(_ event: Any) {
|
|
queueLock.lock()
|
|
queue.append(event)
|
|
let count = queue.count
|
|
queueLock.unlock()
|
|
|
|
// 达到阈值时自动上传
|
|
if count >= maxQueueSize {
|
|
flush()
|
|
}
|
|
}
|
|
|
|
/// 刷新队列
|
|
private func flush() {
|
|
queueLock.lock()
|
|
let events = queue
|
|
queue = []
|
|
queueLock.unlock()
|
|
|
|
guard !events.isEmpty else { return }
|
|
|
|
// 分离 issues 和 events
|
|
var issues: [IssueEvent] = []
|
|
var logEvents: [LogEvent] = []
|
|
|
|
for event in events {
|
|
if let issue = event as? IssueEvent {
|
|
issues.append(issue)
|
|
} else if let logEvent = event as? LogEvent {
|
|
logEvents.append(logEvent)
|
|
}
|
|
}
|
|
|
|
// 上传 issues
|
|
if !issues.isEmpty {
|
|
uploader.uploadIssues(issues)
|
|
}
|
|
|
|
// 上传 events
|
|
if !logEvents.isEmpty {
|
|
uploader.uploadEvents(logEvents)
|
|
}
|
|
}
|
|
|
|
/// 上传待处理的崩溃
|
|
private func uploadPendingCrashes() {
|
|
let crashes = storage.loadPendingCrashes()
|
|
guard !crashes.isEmpty else { return }
|
|
|
|
uploader.uploadIssues(crashes) { [weak self] success in
|
|
if success {
|
|
self?.storage.clearPendingCrashes()
|
|
}
|
|
}
|
|
}
|
|
}
|