How to redirect the nslog output to file instead of console
Asked Answered
U

4

19

I have cocoa application running on OS X. I have used NSLog for debugging purpose. Now I want to redirect the log statements to file instead of console.

I have used this method but it results logging in Console as well as in file.

- (BOOL)redirectNSLog
{
    // Create log file
    [@"" writeToFile:@"/NSLog.txt" atomically:YES encoding:NSUTF8StringEncoding error:nil];
    id fileHandle = [NSFileHandle fileHandleForWritingAtPath:@"/NSLog.txt"];
    if (!fileHandle)    return NSLog(@"Opening log failed"), NO;
    [fileHandle retain];

    // Redirect stderr
    int err = dup2([fileHandle fileDescriptor], STDERR_FILENO);
    if (!err)   return  NSLog(@"Couldn't redirect stderr"), NO;

    return  YES;
}

Is it possible to not have log statement in console but only in file ??

Unit answered 6/7, 2010 at 7:15 Comment(0)
M
-9

NSLog is made to log into the console. You need to define your own function MyLog or whatever, and replace all occurrences of NSLog into MyLog.

Mumford answered 6/7, 2010 at 19:55 Comment(2)
I did define my function and replace NSLog with my defined function. But still I do see logs in Cosole application as well as in log file which I created. I liked the idea of defining own function for logging.Unit
Confirm that the file creation worked. I have tested this code and it works. The linked code writes the file to root which I changed to my local home directory.Oriane
A
72

Step 1: Include following function in AppDelegate:

 - (void) redirectConsoleLogToDocumentFolder
 {
       NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
                                                     NSUserDomainMask, YES);
       NSString *documentsDirectory = [paths objectAtIndex:0];
       NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console.log"];
       freopen([logPath fileSystemRepresentation],"a+",stderr);
 }

Step 2: Call this function at the start of function applicationDidFinishLaunchingWithOptions...

Thats it, Every NSLog() will now get redirected to this console.log file, which you can find in the documents directory.

Appearance answered 9/5, 2011 at 14:7 Comment(6)
Definitely a better answer than mine:) Changed cStringWithEncoding:NSASCII... to fileSystemRepresentation. People can have non-ASCII letters in the path (which is unlikely on ~/Documents/)Mumford
Wonderful! It also works for iOS apps. You will find the console.log inside a directory like this: /Users/Fernando/Library/Application Support/iPhone Simulator/6.1/Applications/18FB521C-A782-44E4-9DFA-B963FD7DC44B/Documents/console.log Thanks! :-)Tbar
To close/stop writing output in console - use fflush(fileP); fclose(fileP); To get file pointer, use FILE *fileP = freopen([logPath.. in above method and keep this pointer around. This way you can wrap around specific flow/nslog calls to this output file.Haldes
Also, if you don't see the whole output (some part is missing) you can add a function void flush_std_err() { fflush(stderr); } and hook on at_exit somewhere in main at_exit(flush_std_err)Neall
Could you explain why the stream is from stderrDib
why using stderr instead of stdout in freopen?Pectoral
L
12

Recently i have faced similar requirement and this is how i have done it.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.

    [self redirectConsoleLogToDocumentFolder];


    return YES;
}

- (void) redirectConsoleLogToDocumentFolder
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
                                                         NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console.txt"];
    freopen([logPath fileSystemRepresentation],"a+",stderr);
} 

And Now if you want to this console to user

-(void)displayLog{

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths firstObject];
    NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console.txt"];

    NSError *err = nil;
    NSString *fileContents = [NSString stringWithContentsOfFile:logPath
                                                       encoding:NSUTF8StringEncoding
                                                          error:&err];
    if (fileContents == nil) {
        NSLog(@"Error reading %@: %@", logPath, err);
    } else {
        self.textView.text = fileContents;
    }

}
Lorineloriner answered 24/12, 2014 at 7:54 Comment(2)
just what i needed for a quick bout of debugging :-)Slaphappy
You can use tail –f console.log runtime see the log, or use tail –f console.log | grep “xxx”Font
S
3

You may be interested in CocoaLumberjack. It is a very flexible logging framework for both Mac OS X and iOS. One logging statement can be sent not only to the console but to a file simultaneously. Plus it is actually faster then NSLog. I use it in a project that has common code for both OS X and iOS.

Stipend answered 21/1, 2012 at 21:56 Comment(3)
Thanks dbainbridge. I am using the same framework for my apps.Unit
Does CocoaLumberjack redirect NSLog? I searched it's code base no sign of freopen.I guess not.Imbue
It would be better to replace your NSLogs with the proper DDLog* statements with CocoaLumberjack. CocoaLumberjack also uses GCD so it is much faster then simply replacing NSLog with a different method.Stipend
M
-9

NSLog is made to log into the console. You need to define your own function MyLog or whatever, and replace all occurrences of NSLog into MyLog.

Mumford answered 6/7, 2010 at 19:55 Comment(2)
I did define my function and replace NSLog with my defined function. But still I do see logs in Cosole application as well as in log file which I created. I liked the idea of defining own function for logging.Unit
Confirm that the file creation worked. I have tested this code and it works. The linked code writes the file to root which I changed to my local home directory.Oriane

© 2022 - 2024 — McMap. All rights reserved.