Monday, May 31, 2010

Introducing Cocoa Lumberjack

Today we are introducing a new open source project: Cocoa Lumberjack

This is a revolutionary new logging framework for iPhone and Mac. Now you might be thinking "logging is boring".

But what if I told you that by using the framework you can actually make your application faster because it is an order of magnitude faster than NSLog?

What if I told you that the framework could allow you to debug your iPhone application remotely, by viewing its log statements in real time, via your web browser?

What if I told you it supports Grand Central Dispatch (if available).

I'm getting ahead of myself...

Let's start from the beginning.

Logging is one of those boring subjects for many developers. We all know we should be doing it. At a minimum we should be logging things like errors and warnings. Of course, when we're debugging we log all kinds of stuff. But what happens once the debugging is done?

Some languages have a plethora of powerful and mature logging frameworks. Take Java for example. But what about Cocoa? You don't often hear Mac/iPhone developers talk much about logging. Why is this?

Is it because Java and C# programmers are boring, and Cocoa developers are exciting?

No (but I'm sure many Cocoa programmers would like to think so). Every programmer wants to write good and stable code. Logging is one of the tools to help accomplish this task. So regardless of what the application does, a good logging framework can help.

So what do Cocoa programmers have available to them?

Log4Cocoa is one possible option. But it never really took hold for a number of reasons. It lacks obvious preprocessor options (many developers would like their log statements to be compiled out of their release builds). It appears to be slow (some say twice as slow as NSLog, and every log statement requires a dictionary lookup, even if the statement won't be executed). Development seems to have all but completely stopped several years ago. And the latest version doesn't contain a logger that can output to the Console application.

So most end up writing their own macros (kinda like this) that allows them to easily toggle log statements from their build. The good part is that it's really easy to use. The bad part is it still uses NSLog...

What's wrong with NSLog?

iPhone developers may be the most aware of NSLog's shortcomings. The iPhone keeps a very short history of log statements. This means that if your iPhone app misbehaves, you need to plug it into Xcode quickly, or any possible log statements may disappear.

And Mac developers know that their log statements are visible to any user via the Console application. If your application is too verbose, you'll hear about it from annoyed IT users.

It would be useful if you could send your log statements to a dedicated file. And while we're at it, how about we customize the format. Instead of just a prepended timestamp, what if we also included the file and method name and line number where the log statement came from. This is where a logging framework comes in...

Cocoa Lumberjack

The Lumberjack framework was designed to be fast, simple, powerful and flexible. As I mentioned earlier, it is faster than NSLog. In addition, the framework is simple to use, especially for those who are converting from NSLog. In fact, the default configuration behaves just like NSLog, so it's like a drop-in replacement.

We've taken considerable effort to document the project on the Cocoa Lumberjack Google Code project site.

There is a quick getting started page for those wondering what it would take to start using the framework in their application.

For those curious individuals, there is a performance page that provides benchmarks of the framework and details the underlying performance optimizations.

There is a page called Xcode Tricks that discusses how you can use different log levels for your debug and release builds. (There are even screenshots to guide you through the process.)

For advanced users who are already accustomed to logging frameworks, there is a page that shows how to customize the number and/or names of the various log levels. (So if you want 13 log levels, you can have them.) And there is also a page that shows how you can add fine grained logging.


Jeremy said...

Having just integrated Lumberjack into my simple application it appears to be working nicely so far, though I am only using it as an NSLog replacement at the moment. One small request, though:

I see that the library is New-BSD licensed but the source currently has no license file with the right bits and pieces filled in so that I can include it alongside your source files in my application's repo. Would you be so kind as to update your SVN repo to include a license file?

Anonymous said...


Jason said...

I have to say the documentation is wonderful! I am really accustomed to hunting around and trying to decipher what some developer has done with some piece of code or whatever... But your documentation level is really wonderful and quite unusual in the wilds of open source code. (IMHO). Thank you so much!

Jason Harris (author of MacHg)

Rob said...

I'm loving lumberjack - but I can't see the support for this bold claim:

'allow you to debug your iPhone application remotely, by viewing its log statements in real time, via your web browser?'

can you elaborate?

thank you.

Robbie Hanson said...


Take a look at the Xcode/WebServerIPhone sample project. It does what I mentioned. It comes with a ReadMe file.

David said...

Great stuff. Looking at using this for an iOS/Mac OS X project. I used KTLog in a commercial product which is a step above the #define route but nowhere near as elegant as what you have provided.

Steve said...

I'm pretty new to Mac OS and to Cocoa so I don't know how to use the browser to view the log statements that the sample iPhone web server sample is generating. Can you please point me in the right direction?

Anonymous said...

The "getting started" link appears to be broken.

Robbie Hanson said...

@anonymous - Links fixed (project was moved to GitHub)

Brian Simmons said...

Robbie, my device is EST, and the CLJ log (each starting line) prints out the timestamp in EST. I see there's a variable _timestamp, which grabs a NSDate in GMT. But when the log is printed it seems to convert it to EST (or whatever the device's locale is). Is there a (an easy) way to get the timestamp printed at each starting line to be in GMT?