代码之家  ›  专栏  ›  技术社区  ›  timbre timbre

使用os\u log记录函数参数或其他动态数据

  •  1
  • timbre timbre  · 技术社区  · 6 年前

    我正在把函数参数记录到 os_log 这样地:

    func foo(x: String, y: [String:String]) {
        //...
        os_log("foo: \(x) \(y.description)", log: OSLog.default, type: .debug)
    }
    

    但是得到错误:

    无法将“String”类型的值转换为预期的参数类型“StaticString”

    1 回复  |  直到 6 年前
        1
  •  26
  •   Community CDub    4 年前

    看到了吗 Logging

    String Format Specifiers 对于标准格式字符串说明符,例如 %@ %d

    就你而言:

    os_log("foo: %@ %@", log: .default, type: .debug, x, y.description)
    

    格式字符串仅限于静态字符串,以防止 (无意)扩展格式字符串说明符。下面是一个演示 问题,使用 NSLog() 因为这并不限制格式 到常量字符串:

    let s = "50%"
    NSLog("\(s)percent")
    // Output: 500x0ercent
    

    这个 %p 变量参数列表上需要一个指针,即 未提供。这是未定义的行为,可能导致崩溃

        2
  •  8
  •   matt    4 年前

    在Xcode 12/Swift 5.3/ios14中,您不必呼叫 os_log 完全是直接的。相反,将OSLog类替换为新的Logger类(当您需要时可用) import os ). 举个例子:

    let myLog = Logger(subsystem: "testing", category: "exploring")
    

    然后,可以直接在Logger对象上调用方法,以使用该子系统和类别进行日志记录:

    myLog.log("logging at \(#function)")
    

    myLog.debug("logging at \(#function)")
    

    在消息字符串中,如您所见, 快速字符串插入是合法的 . 允许Int、Double、Objective-C对象使用 description ,以及符合CustomStringConvertible的Swift对象。

    这里快速字符串插值的合法性令人惊讶,因为 格式说明符是 推迟 评估参数,将其推出应用程序(以便应用程序不会因日志记录而减慢速度)并放入日志记录机制本身。好吧,惊喜!由于swift5中引入了自定义的Swift字符串插值钩子,插值 推迟。

    myLog.log("logging at \(#function, privacy: .public)")
    

    您还可以使用其他参数来执行各种类型的字符串格式化,否则必须使用这些参数来执行 NSLog 格式说明符,例如指定小数点后的位数以及其他类型的填充和对齐:

    myLog.log("the number is \(i, format: .decimal(minDigits: 5))") // e.g. 00001
    

    所以你再也不用打电话了 操作系统日志 再直接,你就不用用 -不再使用类型格式说明符。


    iOS 13及之前版本的旧答案:

    关于Martin R的回答有两点:

    os_log("foo: %@ %@", log: .default, type: .debug, x, y.description)
    

    你可以省略 type: 参数,但不能忽略 log: 参数;你必须拥有它,包括 日志: 标签,或 操作系统日志 会误解你的意图。

    此外,还有 值不必为 .default . 通常在前面创建一个或多个OSLog对象,用作 日志: 参数。这里的优点是您可以为OSLog对象指定子系统和类别,而这些又允许您在Xcode控制台或控制台应用程序中对结果进行过滤。


    另外,关于pkamb的答案,如果我们知道我们的消息总是一个字符串,我们可以这样编写OSLog扩展(利用新的swift5.2) callAsFunction

    extension OSLog {
        func callAsFunction(_ s: String) {
            os_log("%{public}s", log: self, s)
        }
    }
    

    结果是我们现在可以处理OSLog对象 myLog 自身作为一个函数:

    myLog("The main view's bounds are \(self.view.bounds)")
    

    print 声明。我很感激WWDC 2016对这种预演的警告,但如果这是你在一个新的世界里已经在做的事情

        3
  •  1
  •   Community CDub    4 年前

    我对不能使用 "\(variable)" 快速字符串插值 os_log .

    我写了一个小扩展来解决这个问题:

    import os.log
    
    extension OSLog {
        
        static func log(_ message: String, log: OSLog = .default, type: OSLogType = .default) {
            os_log("%@", log: log, type: type, message)
        }
        
    }
    

    这确实会导致“私有”日志记录,这是意料之中的。

    App Name <private>

    In Console.app, how can I reveal to what <private> tags are actually referring?


    在苹果的WWDC 2016演示中 "Unified Logging and Activity Tracing" 他们说:

    如果你在另一个函数中包装它,那么你就失去了我们为你收集文件和行号的能力。

    因此,如果您关心额外收集的信息,这可能不是最佳的解决方案。尽管即使使用库存也可能无法获得这些信息 操作系统日志 How to find source file and line number from os_log()

    一种“宏”替代方案,允许 “\(变量)” 如果有人想写的话,可以替换。

        4
  •  1
  •   Apoc    4 年前

    import Foundation
    import os.log
    
    struct Log {
        enum LogLevel: String {
            case error = "⛔️"
            case warning = "⚠️"
            case debug = "💬"
        }
    
        static func debug(_ info: String, level: LogLevel = .debug, file: String = #file, function: String = #function, line: Int = #line) {
            os_log("%@ %@:%d %@: %@", type: .default, level.rawValue, (file as NSString).lastPathComponent, line, function, info)
        }
    
        static func warning(_ info: String, level: LogLevel = .warning, file: String = #file, function: String = #function, line: Int = #line) {
            os_log("%@ %@:%d %@: %@", type: .default, level.rawValue, (file as NSString).lastPathComponent, line, function, info)
        }
    
        static func error(_ error: NSError, level: LogLevel = .error, file: String = #file, function: String = #function, line: Int = #line) {
            os_log("%@ %@:%d %@: %@", type: .default, level.rawValue, (file as NSString).lastPathComponent, line, function, "\(error)")
        }
    }
    

    用法:

    Log.debug("MyLog")
    

    输出示例:

    应用程序委派。swift:26 application(\:didFinishLaunchingWithOptions:):MyLog

        5
  •  0
  •   pkamb santoshIOS    4 年前

    os_log 现在可以通过Swift字符串插值:

    https://developer.apple.com/documentation/macos-release-notes/macos-big-sur-11-beta-release-notes

    登录中

    • 新的API可供使用 Swift作为操作系统框架的一部分:

      • ( debug(_:) , error(_:) , fault(_:) )

      • Logger api支持指定legacy支持的大多数格式和隐私选项 操作系统日志

      • 与传统api相比,新api提供了显著的性能改进。

      • 操作系统日志 功能。

    注意:新的api不能重新部署;然而,现有的 操作系统日志