设计日志系统
问题
如何设计一个高性能的 iOS 日志系统?
答案
架构
核心实现
enum LogLevel: Int, Comparable {
case debug = 0, info, warning, error, fatal
static func < (lhs: LogLevel, rhs: LogLevel) -> Bool {
lhs.rawValue < rhs.rawValue
}
}
class Logger {
static let shared = Logger()
private let queue = DispatchQueue(label: "com.app.logger")
private var buffer: [LogEntry] = []
private let batchSize = 50
func log(_ level: LogLevel, _ message: String, file: String = #file, line: Int = #line) {
let entry = LogEntry(
level: level,
message: message,
file: (file as NSString).lastPathComponent,
line: line,
timestamp: Date()
)
queue.async {
self.buffer.append(entry)
if self.buffer.count >= self.batchSize {
self.flush()
}
}
}
private func flush() {
let entries = buffer
buffer.removeAll()
// 写入磁盘 / 上报
DiskWriter.write(entries)
}
}
关键设计点
| 设计点 | 方案 |
|---|---|
| 高性能写入 | mmap 内存映射,进程崩溃不丢失 |
| 日志压缩 | zlib 压缩后上报 |
| 隐私保护 | 敏感字段脱敏 |
| 分级 | Debug 不上报,Error 立即上报 |
| 上报触发 | 定时 + App 启动 + 错误触发 |
常见面试问题
Q1: 为什么用 mmap?
答案:mmap 将文件映射到内存,写日志就是写内存,由 OS 定时刷盘。即使 App 崩溃,已写入的数据不会丢失(不像内存 buffer 崩溃时丢失)。微信的 MMKV 和 Mars 的 xlog 都使用了 mmap。