When writing Cocoa the common function to write simple text messages in a non-GUI manner is NSLog(), rather than something like fprintf(). Mainly this is because NSLog adds the "%@" format specifier that (usually) works nicely when printing Cocoa objects. This is especially useful with caveman-style debugging, where instead of using a debugger you just add a ton of print statements and then pore over the results to see what went wrong. That can be ugly but most developers have resorted to it at some point.
Sometimes, though, you don't want those messages to just go to console and (eventually) disappear. It can be useful to make them go somewhere for later reference. The trick here is realizing that NSLog sends its messages to Unix's standard error for the process, which in a GUI app gets sent to the system console. Standard error is malleable, though, and can point wherever you want it to point. So:
// Set permissions for our NSLog file
umask(022);
// Send stderr to our file
FILE *newStderr = freopen("/tmp/redirect.log", "a", stderr);
NSLog(@"This goes to the file");
The effect of the call to freopen() is to open the file at the specified path, and make the already-existing stderr stream use it. Voila! In this case I'm using a mode of "a" so that I'll append to the file if it exists; if you'd prefer to overwrite it, change that to "w". Note that since we're redirecting standard error, anything else that uses stderr will also be redirected.
Even better, you can temporarily redirect NSLog, yet later restore normal NSLog/stderr operation if desired. This involves saving a reference to stderr before redirecting it, and then later restoring stderr to its original state.
#include <unistd.h>
// Set permissions for our NSLog file
umask(022);
// Save stderr so it can be restored.
int stderrSave = dup(STDERR_FILENO);
// Send stderr to our file
FILE *newStderr = freopen("/tmp/redirect.log", "a", stderr);
NSLog(@"This goes to the file");
// Flush before restoring stderr
fflush(stderr);
// Now restore stderr, so new output goes to console.
dup2(stderrSave, STDERR_FILENO);
close(stderrSave);
// This NSLog will go to the console.
NSLog(@"This goes to the console");






Sat, 07/05/2008 - 00:44
Thanks for the suggestion but there something still not completely clear to me.
I'm using your second example to temporary redirect stderr to a file and it works. After this I would like to read back (programmatically) the content of the temp file, and to do so I reopen it in read only mode, and start outputting all the lines. The point is that as soon as I reopen the redirect file, the stderr becomes vacant once again.
Here below a short example
// Save stderr so it can be restored.
int stderrSave = dup(STDERR_FILENO);
// Send stderr to our file
FILE * newStderr = freopen("/tmp/redirect.log", "w", stderr);
cerr << "to the file " << endl;
fflush(stderr);
// Now restore stderr, so new output goes to console.
dup2(stderrSave, STDERR_FILENO);
close(stderrSave);
cerr << "to the console " << endl;
fclose(newStderr);
cerr << "again to console but lost" << endl;
FILE * altro = fopen("/tmp/redirect.log", "r");
char buf[2048];
while ( fgets( buf, sizeof(buf), newStderr ) ) {
string stringa = buf;
cout << "error : " << stringa ;
}
cerr << " console but lost " << endl;
fclose(altro);
unlink("/tmp/redirect.log");
cerr << " lost of course " << endl;
Thanks for helping
Post new comment