Search code examples
pythondjangologgingpyobjcnslog

How to make NSLog work with Python's logging module when using PyObjC?


I'm writing a Django-based webapp that imports a Cocoa framework via PyObjC. The Cocoa framework has NSLog() littered all through it and while I can see them when running the Django server in non-daemon mode, as soon as I go to daemon I simply lose all this useful NSLog() output.

Is there any easy way to get NSLog stuff to bubble up into the Python logging module's world so it can be merged in with the log messages being emitted by the actual Python code?

Did a little Googling and it seems like you might have to redirect stderr and somehow suck it back into Python in order to achieve this, which would be kind of a bummer ...

Any help much appreciated.


Solution

  • According to this page, NSLog basically works like

    fprintf(stderr, format_string, args ...);
    

    so you do need to capture / redirect the standard error output. I wrote a post some time ago which might help for Python-only programs, but I would guess that the Cocoa code accesses the process-level file descriptor 2 (stderr) under the covers. So you'll need to do some low-level fiddling around with the process' stderr. Here's an example:

    old_stderr = os.dup(sys.stderr.fileno()) # keep a copy
    fd = os.open('path/to/mylog', os.O_CREAT | os.O_WRONLY)
    os.dup2(fd, sys.stderr.fileno())
    # Now, stderr output, including NSLog output, should go to 'path/to/mylog'
    ...
    os.dup2(old_stderr, sys.stderr.fileno())
    #stderr restored to its old state
    

    Once you have fd, you can create a file-like object out of it and pass it to StreamHandler, for example, as a means to merging the output from Python code and Cocoa code.