17 Aug

Log iOS Errors to File

Normally, attaching to the console log through the debugger in Xcode shows everything we need to see, but what happens when you need to understand what happened when the device wasn’t hooked up to the debugger?

I recently had an issue that manifested itself only sporadically, and therefore needed to capture the output from NSLog and other console errors to better understand what was happening at the time of the bug.

After a little searching I found the ability to redirect the standard error output stderr to a file.

Adding the following to the application didFinishLaunchingWithOptions

NSArray *allPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
NSString *documentsDirectory = [allPaths objectAtIndex:0]; 
NSString *pathForLog = [documentsDirectory stringByAppendingPathComponent:@"yourlogfile.log"]; 
freopen([pathForLog cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);

 

I then decided it would be useful to add in a date stamp to the log, that would be reset upon app launch, so added:-

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd"];
NSString *stringFromDate = [formatter stringFromDate:[NSDate date]];
NSString *fileName = [NSString stringWithFormat:@"log-%@.log",stringFromDate];

 

Once this was added, replacing the @”yourfilename.txt” with the fileName variable I had a dated output that would open in the log viewer, as I used the .log extension.

There was an issue though. This meant that I could no longer see the content from the console even when hooked up to Xcode. So wrapped the code to check if the debugger was attached, and only write to the file when it wasn’t.

if (!isatty(STDERR_FILENO)) { 
}

 

Finally, it struck me that I could add a test for whether the app is running in Debug, and thus add this code for all development, but know that it will not compile into the final build as that will not be configured as DEBUG. Simply by wrapping the above with:-

#ifdef DEBUG 
#endif

 

So to pull it all together, we have the following code:-

#ifdef DEBUG 
if (!isatty(STDERR_FILENO)) {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd"]; 
NSString *stringFromDate = [formatter stringFromDate:[NSDate date]]; 
NSString *fileName = [NSString stringWithFormat:@"log-%@.log",stringFromDate];
NSArray *allPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [allPaths objectAtIndex:0];
NSString *pathForLog = [documentsDirectory stringByAppendingPathComponent:fileName];
freopen([pathForLog cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
} 
#endif

 

Any questions or comments, feel free to reach out to me via the contact options above.

Also, why not subscribe for updates?