A variation on NSLog()
Using NSLog() is probably the easiest and most used [first line] debuggingtool. However, the output of NSLog() was not really to my liking and I thought it could be made more useful. The output of:
NSLog(@"%s : generated = %d", _cmd, generated);
looks typically like this:
It shows the date and time (with milliseconds precision) and the name of the project before it shows the text I want to print out. In this case the called method and the value of an int.
My preferred output would be capable of doing this:
1) Show on which thread CCLog() was called from.
2) Show from which sourcecode file CCLog() was called from.
3) Show the linenumber in the sourcecode file CCLog was called from.
My first preference might seem a bit weird but as a beginning developer I found it useful to have the possibility to quickly check if my code was running in the thread I intended to. CoCoa has the capability of giving a NSThread a name [on top of its threadnumber]. This can very easily be done like this:
A bit of searching brought me to a blog-entry of agentM which describes his own implementation of a better NSLog(). In short, his implementation is a very nice example on the usage of variadic macros and the C preprocessor. Using the C preprocessor, It’s possible to write the CCLog() class method like this:
The above CCLog macro expands to a class method call:
;
At compile-time, the __FILE__ and __LINE__ arguments would be expanded to the filename and linenumber where CCLog() was called from just like I wanted. For those classes that have a methodname like ‘init’ which appear quite often, having the filename in the log makes it easy to follow which ‘init’ method from which implementation was called. The last argument is the string with our own text. Using the variadic macro (__VA_ARGS__) we can still format strings as we are used to for formating a NSString. E.g. the following is perfectly possible:
@"%s : generated = %d", _cmd, generated);
As you can see, we can specify any number of parameters to format our textstring like we want. The processing of the variadic macro then happens like this:
listOfArguments, format);
formattedString = ;
listOfArguments);
The only other remaining problem is printing out the threadname. If the threadname is not set, then the threadnumber should be logged. Getting the threadname is pretty simple and can be done like this:
Getting to show the threadnumber was less easy. NSThread provides a method to get its name but not its number. This can be bit problematic in those cases a thread doesn’t have a name. Asking the threadname of a thread which is not named simply returns nil. In that case I simply send the output of the currentThread class message of NSThread to a NSString. That output contains the threadnumber and can be extracted with a bit of string manipulation.
The output of CCLog() now looks like this with a threadnumber:
The output of CCLog() now looks like this with a named thread:
The full implementation of CCLog() can be found below and a small Xcode project can be downloaded at the end of this blogentry.
As a last remark, when you define the USE_NSLOG preprocessor macro, then the familiar NSLog() will be used instead of printf() to print out the message. This means that the date, time and project name will be added in front of the threadname, filename, linenumber and the content of the logstring. The output of the same CCLog() calls as above becomes:
The header file:
//
// CCLog.h
// gitVersions
//
// Created by Koenraad Van Nieuwenhove on 26/08/08.
// Copyright 2008 CoCoa Crumbs. All rights reserved.
//
// idea from http://www.borkware.com/rants/agentm/mlog/
/* interface CCLog */
The implementation:
//
// CCLog.m
// gitVersions
//
// Created by Koenraad Van Nieuwenhove on 26/08/08.
// Copyright 2008 CoCoa Crumbs. All rights reserved.
//
/* implementation CCLog */
A sample project can be downloaded here: CCLog sample project
Posted: November 13th, 2008 under CoCoa.
Comment from RYErnest
Time December 1, 2008 at 9:17 am
Nice post u have here
Added to my RSS reader