Reputation: 5666
Suppose you have the code of a Cocoa app which logs its own messages through NSlogs and printfs to the Console output. My goal is to redirect all this output into a separate NSWindow in a NSView.
How can I achieve this in a way that
(the usual software engineering guide lines)?
Upvotes: 1
Views: 1712
Reputation: 382
Soon after your program starts use the dup(2) call to make duplicate File Descriptors for fd 1 (stdout) and 2 (stderr). Save the returned values for later.
Call close(2) on FD 1 and FD 2.
Call openpty(2) twice. The first master returned should be FD 1 (because it is the first avaiable FD), and the second master should be 2. Save the two slave FDs for later. Don't worry about saving the name parameter. Now whenever your program printf(2) to stdout, or NSLogs to stderr the data will be written to your slave FDs.
Now you must choose wether you want to poll the slave FDs or setup a signal when there is data to be read.
For polling use an NSTimer. In your timer use select(2) on your two slave FDs to see if they have data. If they do read(2) it and then output it to your window. You can also get the two slave FDs to use non blocking IO (use fcntl(2) to F_SETFL the slave FDs to O_NONBLOCK). Then you don't need select(2), you just read(2) and it will return zero if there is nothing to read.
For signaling, use fcntl(2) to F_SETFL the slave FDs to O_ASYNC. Then use signal(3) to install a signal handler for SIGIO. When your signal handler is called use one of the two methods I describe in the polling section.
If at run time you want to discard all these changes and set everything back to normal do this:
Call close(2) on FD 1, and FD 2.
Call dup(2) on the two FDs saved from step 1 in the first section, above. Do the dup(2) in the correct order so stdout uses FD 1 and stderr uses FD 2.
Now anything written to stdout and stderr will go to the original FDs.
Upvotes: 4
Reputation: 5666
Here is the solution I came up with:
readInBackgroundAndNotify
from NSFileHandle
. When notified it calls the appending method. It has a method for starting the logging on file as well, which uses freopen(3)
to redirect some stream (stderr and stdout atm) to a file in append mode.This solution was created considering both Joshua Nozzi's answer and tlindner's one, and combines them. I have and encapsulated solution that respects the three requests in the question (I have to add only a line of code, I can revert back easily and I can use this solution in other apps too). I noticed that maybe sometimes it can be wrong to have an NSWindowController encapsulated this way (whereas all the other ones are managed by some super-controller).
I finally opted for the file solution since it is very easy to implement and more Cocoa-like than tlindner's one. Also it gives the opportunity to have a logging file that persists on the disk. But of course I may have missed something, point that to me in the comments please ^^
Upvotes: 1
Reputation: 61228
How about writing your own log method that informs some controller of the log message (so it can place it into your (NSTextView?) view, then calls NSLog() in turn?
Upvotes: 1