Previous Entry Share Next Entry
Disable assertions and logging in your Release build
latest
chanson
Typically, when you create a build of your software to release, you'll apply a whole bunch of additional optimizations to that version that you won't apply to the debugging builds. You'll strip debugging symbols — or, nowadays, build them to a separate DWARF with dSYM file — and crank up the compiler optimization and instruction scheduling settings that would normally make debugging hard.

One optimization that's often overlooked, though, is to turn off assertions. A lot of developers will use assertion macros as sort of a "continuous unit testing" technique within their code during development. They'll assert that methods' preconditions hold, that the postconditions of various operations continue to hold, that changes within methods produce expected results, and so on.

Standard C provides the assert(3) macro to perform a simple form of verification. By default, it just writes the failure information — including the failing file and line — and then calls abort(3); most environments also provide a way to extend its functionality by using assert as a wrapper for a sub-macro or other function.

Similarly, Cocoa's Foundation framework provides a number of NSAssert and NSParameterAssert macros that you can use in your code. (The primary difference is in the message of the exception they generate.) These normally throw an NSInternalInconsistencyException, but their behavior is extensible by subclassing NSAssertionHandler.

The thing is, you probably don't want the released versions of your applications terminating immediately or throwing exception in unexpected places — even though you probably do want them to do so during development. (After all, that's part of how you ensure they won't happen in production, right?) So you need to disable them in your release build.

Fortunately, Xcode makes this really easy. You just need to add two entries to the Preprocessor Macros build setting in your Xcode project, typically at the project level (since you'll want it to apply to all targets in your project). To turn off Standard C assertions, you just need to specify NDEBUG while for turning off Foundation assertions, just specify NS_BLOCK_ASSERTIONS. If you do this, you can put assertions literally everywhere in your code but be confident you'll only ever hit them during development.

Logging is in a similar boat. The release build of an application should, in general, never log in normal use. However, it can be extremely useful when things do go wrong to allow your users to enable logging by changing a hidden (or not-so-hidden) preference within your application. Ideally, you could even control the logging for different aspects of your application and different levels of severity, so enabling logging for one piece of functionality doesn't affect others, and so you can avoid spewing more log information than necessary.

Unfortunately, there's no built-in facility in Foundation for this sort of fine-grained logging. There's really just NSLog which, though useful during development, is both unconditional and doesn't have either aspects or levels. However, there's the Open Source (BSD licensed) Log4Cocoa project which aims to provide most of this functionality. It's currently based on the same design as Log4J, and it hasn't had a lot of work since its introduction, but it's a good starting point for working sophisticated logging into your own applications and it would be great to see developers pick it up again.

Bob Frank and Wolf Rentzsch presented on both of them for Uniforum a few years back, and made a PDF of their presentation available. Just be sure to tune the logging that actually gets compiled into your release builds by leveraging the Preprocessor Macros build setting...

Update (April 30, 2007): I've followed this up with another post on the importance of distinguishing between assertions and checks in your code. One of the main reasons I find that people don't want to turn off assertions before shipping is that they're using assertions as checks; if you distinguish between them, then this won't be a problem.

Thanks for the Log4Cocoa link -- I actually forgot I even gave that preso! The story doesn't end with Log4Cocoa, though -- you can take a sneaky peek at JRLog in my redshed SourceForge project to see what's next. I already did a preso on it for PSIG, and it's being used in some apps, but I need to do a good intro to it for its public debut.

--rentzsch

Sweet! But - JRLog? WolfLog has a pretty good ring to it... ;)

Getting involved

(Anonymous)

2007-05-02 01:59 am (UTC)

I'm a newbie, who has been playing with the idea of getting serious with obj-c for years. Now, my plan is to get involved in documenting and testing. I would like to know more about Log4Cocoa, but I don't know if it's a dead project. Especially when one of its presenters forgot about it and is working on another (JRLog) where do I begin?
-aher02late gmail

Getting involved

(Anonymous)

2007-05-02 02:39 pm (UTC)

I'm a newbie, who has been playing with the idea of getting serious with obj-c for years. Now, my plan is to get involved in documenting and testing. I would like to know more about Log4Cocoa, but I don't know if it's a dead project. Especially when one of its presenters forgot about it and is working on another (JRLog) where do I begin?
gmail ahero2late

Would also like more info on Log4Cocoa/JRLog

eric_trepanier

2007-05-03 05:21 pm (UTC)

I have also been reading several Cocoa-related blogs, the famous Aaron Hillegass Cocoa Programming book, listening to podcasts and just being generally interested in the subject but I have never actively participated in any open source Cocoa project.

This one seems to be like a good place to start. I tried looking up Jonathan's JRLog reference but came up mostly empty. More info would be appreciated. Thanks!

Re: JRLog

(Anonymous)

2007-11-21 09:43 pm (UTC)

Corrent URL for SVN is
http://redshed.svn.sourceforge.net/viewvc/redshed/trunk/cocoa/JRLog/