Redirecting NSLog to a log file
Using NSLog is all well and good for debugging iPhone OS applications when the device is connected to your Mac, but what about when it is not. Often you want to give builds of your application to people that don’t have Xcode installed (or can’t get the silly certificates to work !!!), or just as commonly, to test if the application works outside of your lovely office which has a perfect WiFi connection.
When I first thought about this problem, I was thinking along the lines of build a custom log function lets say MagicLog() and this calls a function that saves the string to a file. The problem with this is that I would have to go through all of my code and add MagicLog() to everywhere that I have NSLog(), that seemed a bit to verbose for my liking.
After searching on the internet I found out that (rather obvious) NSLog runs over standard error. This means that you are able to simply redirect standard error to a file using the ANSI function freopen().
FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *restrict stream);
http://www.opengroup.org/onlinepubs/000095399/functions/freopen.html
Before we can save NSLog() to a file, we first have to find a place to save it. The best place to do this is the application’s documents folder. To get this you can use the following code snippet:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
Once we have the documents folder, we need to give a name to the file. To make it easy for me I just name it “the date”.log :
NSString *fileName = [NSString stringWithFormat:@"%@.log",[NSDate date]];
To make this into a valid path, use the NSString method stringByAppendingPathComponent
NSString *logFilePath = [documentsDirectory stringByAppendingPathComponent:fileName];
The last step is to redirect stderr to this file
freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
To keep my code maintainable I keep all of this as a function, and I call it in my AppDelegate if I want to turn this functionality on.
- (void)redirectNSLogToDocumentFolder {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fileName = [NSString stringWithFormat:@"%@.log",[NSDate date]];
NSString *logFilePath = [documentsDirectory stringByAppendingPathComponent:fileName];
freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
}
Getting the file.
Now that you have logged all the information you need, you will want to get this off of the device. Thankfully this is easy as well. Simply open the organiser in Xcode and select the device that is currently connected to your Mac.
A the bottom of the main pain there is an application section. Open the detail disclosure on the application you want to get the data from, and hit the little download button to the right of the Application Data package. You will be prompted to save this folder to your mac.
Warning: Writing to the file system on the iPhone is slow, so this will effect the performance of your application. Therefore DO NOT ship an application with this in, or give it to people that can’t stand poor performance.