看完这篇文章的讨论后,我想做一个简单的原型,看看是否可以从手机远程获取日志。为此,我稍微修改了 Steipete 的代码:我删除了一些我不需要的代码,并添加了一个按钮来触发日志的发送,名为“将日志发送给开发人员”。
然后,我创建了一个名为SendableLog
转换的可编码结构OSLogEntryLog
,从而可以将其转换为 JSON。在使用日志getEntries()
并将它们映射到这种新类型之后,我将日志转换为 JSON,并向我在 MacBook 上运行的简单 Python 服务器上的端点(如 @DanielKaplan 建议的那样)发送 HTTP POST 请求。
Swift 代码(iOS 15 应用程序):
//
// ContentView.swift
// OSLogStoreTesting
//
// Created by bbruns on 23/12/2021.
// Based on Peter Steinberger (23.08.20): https://github.com/steipete/OSLogTest/blob/master/LoggingTest/ContentView.swift.
//
import SwiftUI
import OSLog
import Combine
let subsystem = "com.bbruns.OSLogStoreTesting"
func getLogEntries() throws -> [OSLogEntryLog] {
let logStore = try OSLogStore(scope: .currentProcessIdentifier)
let oneHourAgo = logStore.position(date: Date().addingTimeInterval(-3600))
let allEntries = try logStore.getEntries(at: oneHourAgo)
return allEntries
.compactMap { $0 as? OSLogEntryLog }
.filter { $0.subsystem == subsystem }
}
struct SendableLog: Codable {
let level: Int
let date, subsystem, category, composedMessage: String
}
func sendLogs() {
let logs = try! getLogEntries()
let sendLogs: [SendableLog] = logs.map({ SendableLog(level: $0.level.rawValue,
date: "\($0.date)",
subsystem: $0.subsystem,
category: $0.category,
composedMessage: $0.composedMessage) })
// Convert object to JSON
let jsonData = try? JSONEncoder().encode(sendLogs)
// Send to my API
let url = URL(string: "http://x.x.x.x:8000")! // IP address and port of Python server
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = jsonData
let session = URLSession.shared
let task = session.dataTask(with: request) { (data, response, error) in
if let httpResponse = response as? HTTPURLResponse {
print(httpResponse.statusCode)
}
}
task.resume()
}
struct ContentView: View {
let logger = Logger(subsystem: subsystem, category: "main")
var logLevels = ["Default", "Info", "Debug", "Error", "Fault"]
@State private var selectedLogLevel = 0
init() {
logger.log("SwiftUI is initializing the main ContentView")
}
var body: some View {
return VStack {
Text("This is a sample project to test the new logging features of iOS 15.")
.padding()
Picker(selection: $selectedLogLevel, label: Text("Choose Log Level")) {
ForEach(0 ..< logLevels.count) {
Text(self.logLevels[$0])
}
}.frame(width: 400, height: 150, alignment: .center)
Button(action: {
switch(selectedLogLevel) {
case 0:
logger.log("Default log message")
case 1:
logger.info("Info log message")
case 2:
logger.debug("Debug log message")
case 3:
logger.error("Error log message")
default: // 4
logger.fault("Fault log message")
}
}) {
Text("Log with Log Level \(logLevels[selectedLogLevel])")
}.padding()
Button(action: sendLogs) {
Text("Send logs to developers")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
我有这个简单的 Python HTTP 服务器来监听传入的 POST 请求,IP 地址设置为我 MacBook 的本地 IP 地址。这与上面 Swift 代码中的 IP 地址相匹配。
from http.server import BaseHTTPRequestHandler, HTTPServer
import json
hostName = "x.x.x.x" # IP address of server
serverPort = 8000
class MyServer(BaseHTTPRequestHandler):
def _set_headers(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
def do_HEAD(self):
self._set_headers()
def do_POST(self):
self._set_headers()
print("Received POST")
self.data_string = self.rfile.read(int(self.headers['Content-Length']))
self.send_response(200)
self.end_headers()
data = json.loads(self.data_string)
print(f"JSON received: \n\n {data}")
if __name__ == "__main__":
webServer = HTTPServer((hostName, serverPort), MyServer)
print("Server started http://%s:%s" % (hostName, serverPort))
try:
webServer.serve_forever()
except KeyboardInterrupt:
pass
webServer.server_close()
print("Server stopped.")
当我运行应用程序并点击向开发人员发送日志按钮时,我在终端中看到以下消息:
x.x.x.x - - [23/Dec/2021 13:56:47] "POST / HTTP/1.1" 200 -
JSON received:
[{'subsystem': 'com.bbruns.OSLogStoreTesting', 'level': 3, 'composedMessage': 'SwiftUI is initializing the main ContentView', 'category': 'main', 'date': '2021-12-23 12:56:43 +0000'}]
日志从手机成功检索,然后发送到服务器。
警告
当我(完全)关闭应用程序并重新打开它时,以前的日志就消失了!
创建日志存储 ( let logStore = try OSLogStore(scope: .currentProcessIdentifier)
) 时,范围设置为.currentProcessIdentifier
,这是 iOS 上唯一可用的范围。这个线程让我相信.system
范围也将包括以前的日志,但系统范围在 iOS 上不可用。