Loading

Debugging is hell

I come from a world where there are a large number of tools to help you with debugging your programs. When I got to Xcode and Swift, I was presented with LLDB (for which I still know very few commands) and using print statements. Not ideal.

To be fair, noting much has changed from those early debugging days, except I now have a much snazzier form of printing to the console in the form of SwiftyBeaver.

SwiftyBeaver console output

You can get install instructions over at github for SwiftyBeaver. For my part., I prefer using Carthage for my install, but you can pick some other way if you want.

Set-up

There are two phases to using SwiftyBeaver; the set-up of the environment and the logging to the console. To get the set-up done, you need to go over to the AppDelegate.swift file. For the purposes of our logging, we're going to log to the console. You can log to all sorts of pother locations, but the console is the simplest place for debugging purposes.

So, first thing we need to do is reference the library and create a global logging variable:

import SwiftyBeaver

let log = SwiftyBeaver.self

The log variable is a convenience, but a very convenient one, so it's worth the ridicule of having a global variable!

The next bit of set-up, I usually split into a separate method:

    fileprivate func initialiseConsoleLogging() {
        let console = ConsoleDestination()  // log to Xcode Console

        // Set a custom format to get date/time and add some colour
        // indicators to the log to make spotting message level easier.
        console.format = "$DHH:mm:ss$d $L $M"
        console.levelString.verbose = "💜 VERBOSE"
        console.levelString.debug = "💚 DEBUG"
        console.levelString.info = "💙 INFO"
        console.levelString.warning = "💛 WARNING"
        console.levelString.error = "❤️ ERROR"

        // Setting the level here determines how much output we get
        console.minLevel = .verbose

        // add the destinations to SwiftyBeaver
        log.addDestination(console)
        log.info("App started and log initialised.")
    }

What we are doing here is defining the console as a destination and configuring the output. The format determines how the output will look while the levelString is used to add some colour to the console which makes it easier to spot messages.

The midlevel tells SwiftyBeaver what level to report at. While intensively debugging, this is usually set to .verbose as this gives me the maximum number of messages. Once the app settles down, it drops to .debug. For production, you might as well set it to error, since you cannot get the console output anyway. For production, you might want to look at the paid options!

Logging

Logging is the second part of the process. That is simply a case of lobbing calls to the log object throughout your code.

let item = items.filter() {
    $0.ItemName.uppercased() == noun && $0.Location == location
}
log.debug("Auto get for \(noun) returned \(item.count) results.")

log provides methods for outputting a string at various levels. Here I have used the debug level which will show provided the minLevel is debug or higher (verbose). For the harder to debug issues, I might use verbose level debugging:

if tmp != 0 {
    vIndex = VERB_GO
    nIndex = tmp
    log.verbose("Go verb found. Direction is \(verb) which translates to \(tmp)")
}

The level at which you log is entirely up to you. I tend to find I can stabilise my programs at the debug and verbose levels during development. For production running, it might make more sense to log to a file at a higher level.