Logging in Swift

NSLog or Print

There are multiple ways to log in Swift. This article will explore them!

Image for post
Image for post
Photo by Mildly Useful on Unsplash

Difficulty: Beginner | Easy | Normal | Challenging

Prerequisites:

  • None, although to follow the code you might like to use Playgrounds. Guide: HERE and String interpolation is used later in the article (guide: HERE)

Terminology

Console: A simple window for programming that can display output and (usually) process input

Debugger: A computer program used to test and debug other programs

Function: A group of statements that together can perform a function

IDE: An application that provides a set of features that are used by software developers to create computer software

NSLog: Logging using an error message to the Apple System Log facility

OSLog: Logging, in a way that can log with categories

print: Write items to the standard output

String: A collection of Characters

Logging: A way to capture log messages to memory and disk

Trace: A use of logging to record information of the program’s execution

Why Logging is important

You have a bug. You don’t know how to fix it, but most likely you know where about the problem might be you might choose the debugger or logging to the console. Both approaches are valid, and let us explore them. Note that the use of the debugger and logging to the console are not mutually exclusive and many programmers use a combination of the two.

The debugger

One way of debugging is to use the debugger, and the one provided in Xcode is actually pretty good (as well as being convenient). The debugger allows you to see what the state of a variable is as you move through time, and the state of the system at a moment in time.

This is excellent, but some people exist who never want to use a debugger at all. This is because another way of tracing the program’s execution.

Logging to the console

One other way of seeing the status of some variables and ultimately the state of the system is to print to the console. The advantage of this is that we can have multiple such statements in a program, while still seeing the same part of the code in our IDE.

If you are logging to the console as a form of debugging, you should remember to delete them after you have completed that problem. Oh, and you should also be careful not to print to the console in production mode so you need to make sure that you have the right logging enabled. That means, we need to start to look at our options.

Logging options in Swift

print

The print function prints messages in the Xcode console.

This is done by using the following function

print(_:separator:terminator:)

This means that you can print one or more values. This enables us to use the #function literal to print which function we are in. For example:

func test(input: String) {
print("The function \(#function) received \(input)")
}

has a single input, but uses String interpolation.

You can put a terminator parameter of your choice as the final parameter in the print function.

print ("Message","")

NSLog

NSLog can not only print out a message, but can also format through a second argument

func NSLog(_ format: String, _ args: CVarArg...)

so a general message can be output:

NSLog ("Message")

And to format:

NSLog ("Present a Float %lf", 1.59)

therefore it outputs

2020-02-24 19:47:44.422964+0800 Logging[2031:103183] Present a Float 1.590000

os_log

os_log requires that you import the module at the top of your file (even the playground)

import os.log

But it is worth it, as logging per category (which is added throughos_log requires )

which brings us onto the parameters for the function

func os_log(_ message: StaticString, dso: UnsafeRawPointer? = #dsohandle, log: OSLog = .default, type: OSLogType = .default, _ args: CVarArg...)

Now, in amongst those options there is an OSLogType which controls the conditions under which a message should be logged. These levels are:

default: The default log level
info: The info log level. Used for information logs.
debug: The debug log level. Used for use in the development environment.
error: The error log level. Used for reporting critical errors.
fault: The fault log level. Used for capturing system-level errors.

This is simple to do as

os_log(.info,"Network unavailable")

or, as before we can use the formatting

os_log(.info,"Present a Float %lf", 1.59)

To filter on the log we need to create a custom log object

let log = OSLog(subsystem: "medium_article", category: "basic")
os_log("Error Message", log: log, type: .info)

But now we can filter the messages. The best way to do this is with the Console.app.

To open the Console.app you can start Spotlight by pressing ⌘ — space and typing Console.app.

On the left-hand side select the device you are using for your App (this could be a simulator)

Image for post
Image for post

You then need to ensure that info and debug messages will show up in the console by going to the Action menu and making sure Include Info Messages and Include Debug Messages are both ticked

Image for post
Image for post

Now when we want to search for the category we use the search option — and using the error above I search for basic.

Image for post
Image for post

an alternative is to search for the subsystem

Image for post
Image for post

The search can also be saved using the friendly save button!

It is even possible to use os_signpost to mark a point of interest as a time interval (documentation HERE). This gives you an introduction to os_log but I’m sure you can see this is quite an in-depth topic in itself!

Logging best practices

Don’t include file line numbers in messages. The system captures this information.

Use formatting to produce user-friendly messages.

Use logging in conjunction with the debugger, picking the correct tools to use at any given time.

So which should I use? Print, os_log or NSLog?

Where are we logging to?

NSLog and os_log output to the device console AND the debugger console. print outputs to the debugger console.

What are we outputting?

NSLog output both a timestamp and identifier to the output as well as the message. os_log allows you to specify the type of logging message you would like to use.print outputs the specified message.

So which should I choose? It’s os_log isn't it?

Yes, yes it is. os_log is generally a good choice. Although you should really choose for yourself and your own needs.

Conclusion:

Logging in Swift isn’t too rough. However, NSLog feels much like it has been replaced by the newer os_log … but, as ever you as the developer need to make the choice. How can you decide what the best thing to do is? I’d say you should use you brain…and make the best choice.

Good luck!

Extend your knowledge

  • Apple have a nice article on Logging (guide HERE)
  • String Format specifiers for use with NSLog are listed by Apple HERE
  • Apple had a whole WWDC session on logging! Link HERE

The Twitter contact:

Any questions? You can get in touch with me here

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store