Problem redirecting NSLog() output to stderr

  • Hello List

    My app consists of a GUI process, a daemon and a number of worker
    processes.
    Each of these processes has their stderr redirected via freopen() to
    the same log file.
    For the purposes of simple logging this arrangement works acceptably.
    There is a thread on why this should be: http://www.cocoabuilder.com/archive/message/cocoa/2003/6/16/3689

    The user may however delete the shared log from the GUI.
    After this the daemon and worker process log output is lost.
    In those cases can I detect that the stderr stream is no longer valid?

    I have tried fcntl(), fileno(), fstat(), ftell() and feof() without
    success.

    My actual call to NSLog() is wrapped in a generic logging class.
    My only solution so far is to issue freopen(logfile, "a", stderr)
    prior to each and every call to NSLog().
    But this seems brutal.

    Jonathan
  • On Sun, Aug 17, 2008 at 5:10 PM, <jonathan...>
    <jonathan...> wrote:
    > Hello List
    >
    > My app consists of a GUI process, a daemon and a number of worker processes.
    > Each of these processes has their stderr redirected via freopen() to the
    > same log file.
    > For the purposes of simple logging this arrangement works acceptably.
    > There is a thread on why this should be:
    > http://www.cocoabuilder.com/archive/message/cocoa/2003/6/16/3689
    >
    > The user may however delete the shared log from the GUI.
    > After this the daemon and worker process log output is lost.
    > In those cases can I detect that the stderr stream is no longer valid?
    >
    > I have tried fcntl(), fileno(), fstat(), ftell() and feof() without success.
    >
    > My actual call to NSLog() is wrapped in a generic logging class.
    > My only solution so far is to issue freopen(logfile, "a", stderr) prior to
    > each and every call to NSLog().
    > But this seems brutal.

    You can't detect that the stderr stream is no longer valid in these
    cases because, in fact, it *is* still valid.

    In UNIX, when you delete a file which some process still has open,
    that file doesn't actually go away. It remains on disk, and that
    process's file descriptor to it remains valid. Writes and reads
    continue to work as expected. Once the file descriptor is closed (or
    the process terminates, or the computer reboots, etc.) the file is
    finally removed from the disk.

    Rather than delete the file, it may work if you simply truncate it.
    New writes should then go to the end of the newly truncated file.

    If you really need to function after deletes (for example if you don't
    control the code that deletes the file, or you want to continue to
    function after the user trashes it from the Finder or something) then
    you can use kqueue to find out when something happens to the file, or
    even just poll it every few seconds if you can't rely on kqueue to be
    available on the filesystem in question.

    Mike
  • Thanks for the suggestions Mike.
    I had an intuition that my core Unix knowledge was wanting here.

    It turns out that a call to ftruncate(STDERR_FILENO, 0) does indeed do
    the job.

    Jonathan

    > You can't detect that the stderr stream is no longer valid in these
    > cases because, in fact, it *is* still valid.
    >
    > In UNIX, when you delete a file which some process still has open,
    > that file doesn't actually go away. It remains on disk, and that
    > process's file descriptor to it remains valid. Writes and reads
    > continue to work as expected. Once the file descriptor is closed (or
    > the process terminates, or the computer reboots, etc.) the file is
    > finally removed from the disk.
    >
    > Rather than delete the file, it may work if you simply truncate it.
    > New writes should then go to the end of the newly truncated file.
    >
    > If you really need to function after deletes (for example if you don't
    > control the code that deletes the file, or you want to continue to
    > function after the user trashes it from the Finder or something) then
    > you can use kqueue to find out when something happens to the file, or
    > even just poll it every few seconds if you can't rely on kqueue to be
    > available on the filesystem in question.
    >
    > Mike
    >> Hello List
    >>
    >> My app consists of a GUI process, a daemon and a number of worker
    > processes.
    >> Each of these processes has their stderr redirected via freopen()
    > to the
    >> same log file.
    >> For the purposes of simple logging this arrangement works
    > acceptably.
    >> There is a thread on why this should be:
    >> http://www.cocoabuilder.com/archive/message/cocoa/2003/6/16/3689
    >>
    >> The user may however delete the shared log from the GUI.
    >> After this the daemon and worker process log output is lost.
    >> In those cases can I detect that the stderr stream is no longer
    > valid?
    >>
    >> I have tried fcntl(), fileno(), fstat(), ftell() and feof()
    > without success.
    >>
    >> My actual call to NSLog() is wrapped in a generic logging class.
    >> My only solution so far is to issue freopen(logfile, "a", stderr)
    > prior to
    >> each and every call to NSLog().
    >> But this seems brutal.
previous month august 2008 next month
MTWTFSS
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Go to today