Swift 4/Xcode9+环境下如何获取部署设备上的os.log日志?
我在Swift 4 / Xcode 9+环境下,用新的os.log做应用日志记录,代码如下:
import os.log class ViewController: UIViewController { // a bunch of methods } extension OSLog { static let ui = OSLog(subsystem: "io.my.app", category: "ui") } extension ViewController { func upload(locations: [LocationProtocol]) { os_log("Sending locations to server", log: .ui, type: .debug) self.server_api.send(locations) } }
通过Xcode调试时,日志能在Console.app正常显示,但我需要在**现场测试(远离电脑)**时,从设备上的应用实例里提取已记录的字符串并保存成文本文件。想请教:是否需要配置日志器来持久化存储日志?还是部署后的应用只能获取崩溃报告?
核心结论先给你说清楚
默认的os.log不会自动把日志存在你的应用沙盒里,所以现场没电脑的时候,你直接拿不到这些日志——必须做额外配置或者自定义实现才行。崩溃报告和业务日志是两码事,崩溃报告只记录崩溃瞬间的信息,完全替代不了你要的业务日志。
具体拆解与解决办法
1. 为啥默认的os.log拿不到?
默认情况下,os.log的日志是由系统统一管理的,存在系统级的日志数据库里,不是你的应用沙盒目录。这就导致:
- 调试时,Xcode和Console.app能有权限读取这些系统日志,所以你能看到
- 但应用部署到设备后,普通APP没有权限访问系统日志数据库,自然没法提取;而且系统日志会自动清理旧内容,也没法保证你需要的日志一直留存。
2. 实现日志持久化的几个可行方案
方案一:自己封装日志工具,同时写系统日志和本地文件
最简单的办法就是在调用os.log的同时,把日志内容写入到应用沙盒里的文件中。比如写个简单的工具类:
import os.log struct AppLogger { static let uiLog = OSLog(subsystem: "io.my.app", category: "ui") static func log(_ message: String, log: OSLog = .default, type: OSLogType = .debug) { // 先写入系统日志,保留原有的调试功能 os_log("%@", log: log, type: type, message) // 再写入沙盒内的日志文件 let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] let logFileURL = documentsDir.appendingPathComponent("app_business_logs.txt") let logLine = "\(Date()): [\(type.rawValue)] \(message)\n" guard let data = logLine.data(using: .utf8) else { return } do { if FileManager.default.fileExists(atPath: logFileURL.path) { let fileHandle = try FileHandle(forWritingTo: logFileURL) fileHandle.seekToEndOfFile() fileHandle.write(data) fileHandle.closeFile() } else { try data.write(to: logFileURL) } } catch { print("Failed to write log to file: \(error.localizedDescription)") } } } // 调用方式替换成这个 AppLogger.log("Sending locations to server", log: AppLogger.uiLog, type: .debug)
之后你只需要在Info.plist里开启UIFileSharingEnabled(设置为YES),测试人员就能通过“文件”APP找到你的应用,把日志文件导出来;或者你也可以在应用里加个导出按钮,把日志通过邮件、AirDrop等方式发送出来。
方案二:测试阶段用系统工具提取(依赖电脑)
如果只是测试场景偶尔需要,且能短暂连接电脑的话,可以用这两种方式:
- 把设备连到Mac,打开Console.app,筛选你的subsystem(
io.my.app),然后导出日志 - 用Mac终端的
log命令:比如log show --predicate 'subsystem == "io.my.app"' --info --debug --last 2h,把输出重定向到文件里(加> app_logs.txt就行)
但这个方法显然不适合完全脱离电脑的现场测试。
方案三:用第三方日志库
嫌自定义麻烦的话,直接用成熟的第三方库,比如CocoaLumberjack。它支持日志分级、自动持久化、日志轮转(避免文件太大),还能灵活配置导出方式,完全能满足现场测试的日志提取需求。
3. 关于崩溃报告的补充
崩溃报告(比如Xcode Organizer里的那些)只记录应用崩溃时的调用栈、系统状态等信息,不会包含你用os.log记录的业务操作日志,所以二者是完全不同的东西,没法用崩溃报告来替代你要的业务日志提取。
内容的提问来源于stack exchange,提问作者devforfu

