The typical print statement. Not very informative, is it?

Unable to serialize JSON.

 

I like to include the time, file, function, and thread.

16:22:19 AccountAPI [line 13] <Thread: Main> in login()
16:22:19 AccountAPI [line 13] <Thread: Main> Unable to serialize JSON.

 

And find it easier to scan the console if blocks of related logs are grouped together.

16:22:10 AccountAPI [line 17] <Thread: Main> in register()
16:22:10 AccountAPI [line 17] <Thread: Main> Registration failed.
----------------------------------------
16:26:12 AccountAPI [line 13] <Thread: Main> in login()
16:26:13 AccountAPI [line 13] <Thread: Main> Unable to serialize JSON.

 

The logging function itself.

public func logger(_ message: String = "",
                  file: String = #file, function: String = #function, line: Int = #line) {
    
    // Thread
    let thread = (Thread.isMainThread) ? "Main" : String(Thread.current.number())
    let threadContent = " <Thread: \(thread)>"
    
    // Time
    let now = Date()
    var last: Date!
    
    Logs.queue.sync {
        last = Logs.lastTime
        Logs.lastTime = now
    }
    
    let timeElapsed = now.timeIntervalSince1970 - last.timeIntervalSince1970
    
    // Divider
    let divider = (timeElapsed > 1) ? "----------------------------------------\n" : ""
    
    // File
    let fileName = ((file as NSString).lastPathComponent as NSString).deletingPathExtension
    
    let messageHeader = "\(divider)\(now.logTime()) \(fileName)\(" [line \(line)]")\(threadContent) in \(function)"
    print(messageHeader)
    
    guard message != "" else {
        return
    }
    
    let messageContent = "\(now.logTime()) \(fileName)\(" [line \(line)]")\(threadContent) \(message)"
    print(messageContent)
}


Add to the same file:

fileprivate struct Logs {
    static var lastTime = Date()
    static let queue = DispatchQueue(label: "com.bundle.logs”, qos: .background)
}


And these extensions:

extension Thread {
    func number() -> String {
        let array1 = self.description.components(separatedBy: ">")
        if array1.count > 1 {
            let array2 = array1[1].trimmingCharacters(in: CharacterSet(charactersIn: "{}")).components(separatedBy: ",")
            for pair in array2 {
                let array3 = pair.components(separatedBy: "=")
                if array3.count > 1 {
                    if array3[0].contains("number") {
                        return array3[1].trimmingCharacters(in: CharacterSet.whitespaces)
                    }
                }
            }
        }
        return "(unknown)"
    }
}
extension Date {
    func logTime() -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.locale = Locale.current
        dateFormatter.setLocalizedDateFormatFromTemplate("HH:mm:ss")
        
        return dateFormatter.string(from: self)
    }
}