Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using os_log to log function arguments, or other dynamic data

Tags:

swift

oslog

I'm trying to log function arguments into os_log like this:

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

But getting error:

Cannot convert value of type 'String' to expected argument type 'StaticString'

So how can I log function arguments, or any other dynamic data?

like image 930
ytrewq Avatar asked Oct 27 '18 19:10

ytrewq


People also ask

Why use OSLog?

OSLog has a low-performance overhead and is archived on the device for later retrieval. These are two of the advantages of using OSLog instead of print statements.

What is Os_log?

Sends a default-level message to the logging system.


2 Answers

See Logging:

Formatting Log Messages

To format a log message, use a standard NSString or printf format string, ...

and String Format Specifiers for the standard format string specifiers, such as %@ and %d.

In your case:

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

The format string is restricted to static strings to prevent (unintentional) expansion of format string specifiers. Here is an example demonstrating the problem, using NSLog() because that does not restrict the format to constant strings:

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

The %p expects a pointer on the variable argument list, which is not provided. This is undefined behavior, it can lead to crashes or unexpected output.

like image 183
Martin R Avatar answered Oct 29 '22 22:10

Martin R


This is my approach:

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)")
    }
}

Usage:

Log.debug("MyLog")

Output example:

💬 AppDelegate.swift:26 application(_:didFinishLaunchingWithOptions:): MyLog

like image 27
Apoc Avatar answered Oct 30 '22 00:10

Apoc