18

What would be the best way to write log statements to a file or database in an iPhone application?

Ideally, NSLog() output could be redirected to a file using freopen(), but I've seen several reports that it doesn't work. Does anyone have this going already or have any ideas how this might best be done?

Thanks!

Mike McMaster
  • 7,573
  • 8
  • 37
  • 42

5 Answers5

32

If you want to use Cocoa, NSString and NSData have methods for reading/writing to file and NSFileManager gives you file operations. Here's an example (should work on iPhone):

NSData *dataToWrite = [[NSString stringWithString:@"String to write"] dataUsingEncoding:NSUTF8StringEncoding];

NSString *docsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [docsDirectory stringByAppendingPathComponent:@"fileName.txt"];

// Write the file
[dataToWrite writeToFile:path atomically:YES];

// Read the file
NSString *stringFromFile = [[NSString alloc] initWithContentsOfFile:path];  

// Check if file exists
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager fileExistsAtPath:path]; // Returns a BOOL    

// Remove the file
[fileManager removeItemAtPath:path error:NULL];

// Cleanup
[stringFromFile release];
[fileManager release];
Martin Gordon
  • 36,329
  • 7
  • 58
  • 54
18

I've successfully used freopen(...) on the phone to re-direct output to my own file.

Ben Gottlieb
  • 85,404
  • 22
  • 176
  • 172
  • Do you remember which arguments you used? – Mike McMaster Oct 14 '08 at 20:58
  • 3
    I used freopen([newFileName UTF8String], "w+", stderr), which redirected all console output to logFileName. – Ben Gottlieb Oct 15 '08 at 10:58
  • Just to follow up - this worked fine. The only bummer is that NSLog output stops appearing on the console after calling freopen, but it's a pretty minor issue. – Mike McMaster Feb 04 '09 at 21:43
  • 3
    You can use `isatty()` to check if STDERR_FILENO is attached to a tty or not and choose not to redirect to file. It will be when you run the app via Xcode (or when its attached to the debugger, I guess). That's probably the only time you need the console output. – Chaitanya Gupta Feb 09 '12 at 07:11
  • @BenGottlieb Will using freopen in production cause mine app to be rejected? – BRUCE May 18 '23 at 15:51
14

This code works great for me..

#if TARGET_IPHONE_SIMULATOR == 0
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console.log"];
    freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
#endif

You can then get the log file off the iphone using the method outlined here http://blog.coriolis.ch/2009/01/09/redirect-nslog-to-a-file-on-the-iphone/#more-85

Note that using freopen will STOP THE CONSOLE IN XCODE working.. however, for some reason the console you can view in xcode's organiser still works great.

Ben Clayton
  • 80,996
  • 26
  • 120
  • 129
  • 1
    I've been able to work around the Xcode issue but only redirecting if the app is NOT running from Xcode by checking an environment variable of my choosing, set by Xcode. http://lists.apple.com/archives/xcode-users/2009/Aug/msg00507.html For example: `if (getenv("MY_ENV_VAR") == NULL) { /* call freopen() */ }` – Quinn Taylor Mar 12 '12 at 22:39
11

This code works for me:

- (void)applicationDidFinishLaunching:(UIApplication *)application {
#if TARGET_IPHONE_SIMULATOR == 0
    freopen([@"/tmp/my_logs.txt" fileSystemRepresentation], "w", stderr);
#endif
}
nst
  • 3,862
  • 1
  • 31
  • 40
3

Consider using Cocoa Lumberjack. It's a light but flexible utility to replace NSLog functionality. In my opinion it's in the same class as Log4J, allowing for custom appenders and the like. It has an SQLite logger, for example.

Chris Dolan
  • 8,905
  • 2
  • 35
  • 73