提问人:Ortwin Gentz 提问时间:9/25/2023 更新时间:10/14/2023 访问量:100
Swift 宏中的 OSLog 不保留原始文件/行号
OSLog in Swift macro doesn't persist original file/line number
问:
我需要并行登录到一个文件(由于无法提供旧日志)。OSLog
OSLogStore
在 Objective-C 中,我可以使用宏来实现这一点,并且在宏实现中仍然引用原始代码中的位置。
我试图创建一个 Swift 宏来从 Swift 完成这项工作。但是,采用宏定义文件的文件和行号,而不是调用代码中的位置。因此,当我单击元数据链接时,我被带到宏而不是调用位置。__FILE__
__LINE__
log()
有什么解决办法吗? 并在宏中正确设置,但无法为函数指定文件和行号。#file
#line
log()
答:
-1赞
killobatt
9/30/2023
#1
我遇到了类似的问题,通过偶尔将内容转储到文件中来解决它。OSLogStore
评论
1赞
Ortwin Gentz
9/30/2023
我很想使用 OSLogStore 而不是普通文件。遗憾的是,OSLogStore(在 iOS 下)仅提供当前正在运行的进程的日志,而不提供以前运行或扩展的日志。
1赞
Claus Jørgensen
10/14/2023
#2
很遗憾,您没有办法这样做*。苹果在他们的无限智慧中不认为有人会做这样的事情。
苹果论坛上常驻的内部爱斯基摩人的建议是,你写一个 Swift 宏来包装它,基本上为每个日志语句写两行日志记录。
* 严格来说不是真的。您可以自己包装 C API,但通常不建议这样做
1赞
iUrii
11/26/2023
#3
Xcode 的编译器会查看代码中 OSLog 记录器调用的位置,并将此信息指向元数据,因此您需要对不同的代码行进行不同的调用。
您可以使用带有闭包的方法,该闭包包含对传递给日志函数的记录器的调用:
func writeToFile(_ message: String, file: String, line: Int) {
let fileName = NSString(string: file).lastPathComponent
print("<\(fileName):\(line)> \(message)")
}
func log(_ message: String, file: String = #file, line: Int = #line, writeToLog: (String) -> Void) {
writeToLog(message)
writeToFile(message, file: file, line: line)
}
现在,您可以按以下方式调用日志函数:
let logger = Logger(subsystem: "com.logger.Test", category: "Test")
log("a") { logger.log("\($0)") }
log("b") { logger.log("\($0)") }
Xcode 的调试控制台输出:
<AppDelegate.swift:35> a
<AppDelegate.swift:36> b
a
Timestamp: 2023-11-26 15:55:08.177017+02:00 | .../AppDelegate.swift 35:23
b
Timestamp: 2023-11-26 15:55:08.177078+02:00 | .../AppDelegate.swift 36:23
为了消除不必要的重复代码,你可以制作 swift 宏:#log
@freestanding(expression)
public macro log(_ message: String) = #externalMacro(module: "MyMacroMacros", type: "LogMacro")
public struct LogMacro: ExpressionMacro {
public static func expansion(of node: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext) throws -> ExprSyntax {
guard let message = node.argumentList.first?.expression.description else {
fatalError("No message")
}
return "log(\(raw: message)) { logger.log(\"\\($0)\") }"
}
}
您的代码将转换为:
import MyMacro
...
#log("a")
#log("b")
评论
0赞
Ortwin Gentz
11/27/2023
我已经尝试过了,它工作正常,但前提是我不使用宏。使用宏时,单击元数据链接将打开宏定义,而不是宏调用位置。这对你有用吗?
评论