DIY Logger 📝

Debugging can be hard.

Sometimes we set a bunch of breakpoints, with good intentions, but then in the process of diving into the stack of callers for each of those breakpoints we lose track of the state causing the problem; and the deeper the dive, the more likely we are to get lost. 👆🏾 👉🏾 👇🏾 👈🏾 🙃

That piece of state might be a bool flag used somewhere that isn’t being reset, or an array that is being accessed from different threads, or in my case, the continuous detection requests being sent out to detect printers — requests that cannot occur concurrently and must also be rate limited.

The point is, we might know the expected behavior, but can’t seem to pin point where the deviation is occurring. To make matters worse, you may have noticed that in some swift files you can’t just po from the debugger at a breakpoint. So when our breakpoints fail what else is there to do?

Logging ?

Normally, we resort to dropping NSLog or print statements in our code when we can’t get our breakpoints to cooperate. This is usually a fine solution so long as we’re logging events in just a few locations, but as the complexity of the bug grows, so do the number of print statements.

Eventually, you have a ton of logs being printed out and can’t remember exactly where that log came from or what triggered it. And when we deal with asynchronous code, the logs can be hard to track if we don’t log when the task begins and ends.

For more rigorous logging needs let create a logger!

Build A Logger 🛠

Basic Logger in Swift 3

One of the benefits of using this logger is that file, function, and line number are all free. Using #file #function #line compile-time constants as default parameters, the caller of the write(message: ) function will provide that information at the call site, behind the scene. This means we can simply write BasicLogger.write(message: "Hello world!") .

Another thing to note is the use of a serial queue here. File writing is not inherently thread safe and since the callers of write(message: ) may not necessarily be on the same thread, we need to guard against concurrent calls to write to the log file. Our serial queue does just that, ensuring that file writes will occur one at a time, avoiding a race condition.

The error handling here is primitive at best, so you may need to build it out if it helps.

Example

02-09-2017| 11:57:41 +503|: - DeviceDetection.swift apply(strategy:onDetectable:): 101: -- Applying LOOPING strat for PrintManager
02-09-2017| 11:57:41 +504|: - PrintManager.swift detectDevices(): 139: -- Detection REQUESTED
02-09-2017| 11:57:41 +505|: - PrintManager.swift detectDevices(): 204: -- returning FUTURE
02-09-2017| 11:57:41 +507|: - PrintManager.swift detectDevices(): 166: -- Detection will be issued by Printer SDKs

Accessing Your Log File

I use SimPholders to access my simulator document directory, but it’s completely possible to access the folder via terminal — although slightly cumbersome.

  • First you need the file path for the simulator’s home directory. To get this, set a breakpoint and po NSHomeDirectory() .
  • Copy the file path.
  • Then open terminal and cd #PASTE FILE PATH HERE#
  • Go to Documents and the LogFile.txt should be there.

Quick Tips

  • Effective logging relies on placing logs at the beginning, middle, and end of an event and marking it so.
  • Place log statements at any point in the code where a return occurs and the reason for the return.
  • It often helpful to explore every branch of the logic tree that your code traverses, logging events for each branch.
  • Log files are particularly useful in determining baseline behavior. So once a change is made the log should differ showing if the change made a difference.

If you rather not build your own logger, there are CocoaPods that have done this, and more, for you like CocoaLumberjack 👌🏾

Anyways, that’s all I’ve got on this one! Thanks for reading and as always feel free to drop a comment below if you have anything to add! ☮️ & ❤️

Like what you read? Give Varindra Hart a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.