3

how to get the stringWithFormat from NSLog() in Swift?

For example the Console Output is 2016-05-24 18:33:31.543 MyPlayground[15578:143357] This is a test!, so how to get the 2016-05-24 18:33:31.543 or 2016-05-24 18:33:31.543 MyPlayground[15578:143357] and save it to a Variable, without printing to Console?

HelloToYou
  • 335
  • 5
  • 14
  • 1
    You could make your own Format string to mimic the output: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html – Alexander May 24 '16 at 16:48
  • I dont understand the question.Can you explain it with some code? – Alessandro Ornano May 24 '16 at 16:50
  • 1
    `String(format:)` is the Swift rendition of Objective-C's `stringWithFormat`. – Rob May 24 '16 at 17:28
  • Why not hook into the runtime and point the log to a file instead of stdout? Related discussion: [How to disable logging?](http://stackoverflow.com/q/35881034/2415822) – JAL May 24 '16 at 17:32
  • 2
    Do you want to create a string in the same format as NSLog() does (as simpleBob and I thought)? – Or do you want to capture/redirect the NSLog output from your program to a variable? In the latter case, @JAL has pointed to a solution. – Martin R May 24 '16 at 17:40

2 Answers2

4

The numbers in the square brackets are the process id and the current thread id, compare e.g. What are the numbers in the square brackets in NSLog() output?. The details can be found in the implementation of __CFLogCString() in http://opensource.apple.com//source/CF/CF-1153.18/CFUtilities.c.

In Swift this can be done as follows:

func logstring(format: String, _ arguments: CVarArgType...) -> String {
    let fmt = NSDateFormatter()
    fmt.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
    let timestamp = fmt.stringFromDate(NSDate())

    let pinfo = NSProcessInfo()
    let pname = pinfo.processName
    let pid = pinfo.processIdentifier
    var tid = UInt64(0)
    pthread_threadid_np(nil, &tid)

    return "\(timestamp) \(pname)[\(pid):\(tid)] " + String(format: format, arguments: arguments)
}

Example:

NSLog("Hello world, x=%ld", 1234)
// 2016-05-24 19:27:35.282 MyProg[26631:1142252] Hello world, x=1234

print(logstring("Hello world, x=%ld", 1234))
// 2016-05-24 19:27:35.283 MyProg[26631:1142252] Hello world, x=1234
Community
  • 1
  • 1
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • 1
    I just wish `print` did that by default, the same as NSLog does. Knowing the time and the thread is useful information! – matt May 24 '16 at 17:32
  • nailed it, congrats ;) – Daniel May 24 '16 at 17:33
  • Could you explain, which sense have `format` and `arguments` (parameters given to function)? – HelloToYou May 24 '16 at 17:54
  • @HelloToYou: `format` is the format and `arguments` a variable arguments list. That are the same parameters that `NSLog()` takes. Compare https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Strings/Articles/FormatStrings.html and https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html#//apple_ref/doc/uid/TP40004265-SW1. – Martin R May 24 '16 at 17:58
  • @MartinR But it is not required, so it's also "okay", if I'm having only one parameter, with the log Statement? And if would like to print a variable, I will just send the var using `"\(TheVar)"` to the function. – HelloToYou May 24 '16 at 18:14
  • @HelloToYou: `NSLog("some message")` is fine, but string interpolation is dangerous because any percent character is interpreted as a format specifier. See http://stackoverflow.com/questions/33144389/printing-nserror-by-nslog-always-raises-exe-bad-access for an example where this crashes. – Martin R May 24 '16 at 18:59
  • @MartinR What would be, if I'm just having one input argument and replace the return-Statement with `return "\(timestamp) \(pname)[\(pid):\(tid)] \(inputstring)"`? – HelloToYou May 24 '16 at 19:58
  • @HelloToYou: That's fine. – Martin R May 24 '16 at 20:03
  • @MartinR Thanks :) – HelloToYou May 25 '16 at 16:49
1

I think this is pretty close:

func interceptLog(format: String, _ arguments: CVarArgType...) -> String {
  let fileName = (#file as NSString).lastPathComponent
  return String(format: "\(NSDate()) \(fileName) [\(#line):\(#column)] \(format)", arguments: arguments)
}

While NSLog("a: %@", "test") prints:

2016-05-24 19:12:35.962 MyPlayground[13970:180094] a: test

print(interceptLog("a: %@", "test")) would print:

2016-05-24 17:17:12 +0000 playground60.swift [7:64] a: test
Daniel
  • 20,420
  • 10
  • 92
  • 149