Skip to content

Instantly share code, notes, and snippets.

@Abizern
Last active September 22, 2021 14:28
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save Abizern/a81f31a75e1ad98ff80d to your computer and use it in GitHub Desktop.
Save Abizern/a81f31a75e1ad98ff80d to your computer and use it in GitHub Desktop.
Debug logging for Swift
//
// LoggingPrint.swift
//
import Foundation
/**
Prints the filename, function name, line number and textual representation of `object` and a newline character into
the standard output if the build setting for "Active Complilation Conditions" (SWIFT_ACTIVE_COMPILATION_CONDITIONS) defines `DEBUG`.
The current thread is a prefix on the output. <UI> for the main thread, <BG> for anything else.
Only the first parameter needs to be passed to this funtion.
The textual representation is obtained from the `object` using `String(reflecting:)` which works for _any_ type.
To provide a custom format for the output make your object conform to `CustomDebugStringConvertible` and provide your format in
the `debugDescription` parameter.
:param: object The object whose textual representation will be printed. If this is an expression, it is lazily evaluated.
:param: file The name of the file, defaults to the current file without the ".swift" extension.
:param: function The name of the function, defaults to the function within which the call is made.
:param: line The line number, defaults to the line number within the file that the call is made.
*/
func loggingPrint<T>(_ object: @autoclosure () -> T, _ file: String = #file, _ function: String = #function, _ line: Int = #line) {
#if DEBUG
let value = object()
let fileURL = NSURL(string: file)?.lastPathComponent ?? "Unknown file"
let queue = Thread.isMainThread ? "UI" : "BG"
print("<\(queue)> \(fileURL) \(function)[\(line)]: " + String(reflecting: value))
#endif
}
@Abizern
Copy link
Author

Abizern commented Feb 2, 2015

@Esqarrouth
Copy link

Do you have example uses cases or codes for calling this method?

@Abizern
Copy link
Author

Abizern commented Aug 28, 2015

Yep. I use it instead of print() while developing - prints to the console only for debug builds.

@Abizern
Copy link
Author

Abizern commented Oct 8, 2015

Updated for Swift 2.0

@cesar-oyarzun-m
Copy link

@Abizern Do you have example how to use this, I add the custom flag but I don't see the logs, I'm running on Xcode 7.2 IOS 9.2 simulator

@fawkesley
Copy link

Thanks for this @Abizern! XCode 7.3 is suggesting to replace soon-to-be-deprecated __FILE__, __FUNCTION__, and __LINE__ with #file, #function and #line, like so:

func loggingPrint<T>(@autoclosure object: () -> T, _ file: String = #file, _ function: String = #function, _ line: Int = #line) {

@fawkesley
Copy link

@Abizern Also, it would be super if you could clarify the licence - thanks!

@DevAndArtist
Copy link

DevAndArtist commented Aug 26, 2016

Swift 3.0 version will look like this:

func loggingPrint<T>(object: @autoclosure () -> T, _ file: String = #file, _ function: String = #function, _ line: Int = #line) {
    #if DEBUG
        let value = object()
        let stringRepresentation: String

        if let value = value as? CustomDebugStringConvertible {
            stringRepresentation = value.debugDescription
        } else if let value = value as? CustomStringConvertible {
            stringRepresentation = value.description
        } else {
            fatalError("loggingPrint only works for values that conform to CustomDebugStringConvertible or CustomStringConvertible")
        }

        let fileURL = URL(string: file)?.lastPathComponent ?? "Unknown file"
        let queue = Thread.isMainThread ? "UI" : "BG"

        print("<\(queue)> \(fileURL) \(function)[\(line)]: " + stringRepresentation)
    #endif
}

I'm also interested in the license. :)

An enhanced solution might look like this:

func loggingPrint<T>(_ closure: @autoclosure () -> T, _ file: String = #file, _ function: String = #function, _ line: Int = #line) {
    #if DEBUG
        let instance = closure()
        let description: String

        if let debugStringConvertible = instance as? CustomDebugStringConvertible {
            description = debugStringConvertible.debugDescription
        } else {
            // Will use `CustomStringConvertible` representation if possuble, otherwise
            // it will print the type of the returned instance like `T()`
            description = "\(instance)"
        }

        let file = URL(fileURLWithPath: file).lastPathComponent
        let queue = Thread.isMainThread ? "UI" : "BG"

        print("<\(queue)> \(file) `\(function)` [\(line)]: \(description)")
    #endif
}

@Abizern
Copy link
Author

Abizern commented Sep 15, 2016

Sorry @DevAndArtist and @paulfurley, I completely missed your questions. I've updated the gist to Swift 3 and Xcode 8, which allowed me to simplify the code and also provides a different way of specifiying DEBUG.

The License is MIT, and you can see a proper repository (rather than a gist) over at https://github.com/JungleCandy/LoggingPrint.

@mihirpmehta
Copy link

Even if i run the build in release configuration i can see all the Logs in Console ... Any idea ? i am using Xcode 9.2 and iOS 11.x

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment