Nic Ferrier wrote:
Jim Gallacher <[EMAIL PROTECTED]> writes:


There is a typo in your code: s/logging.debug/logging.DEBUG/


Got me. It ran for me though...



Beyond that it still segfaults for me.


I can't get it to segfault.

Can you share your test?

Sure, but it's not doing anything fancy.

Debian Sid, apache2-mpm-prefork 2.0.54, python 2.3.5, mod_python 3.2.2b.
The ApacheLogHandler class is in module mod_python/future/mplog.py
Using mod_python.publisher handler:


test.py
-------

from mod_python.future.mplog import ApacheLogHandler
import logging

def index(req):
    return '''<html><body>
              <a href="test.py/segfault">seg fault</a><br />
              <a href="test.py/no_segfault">no seg fault</a><br />
              </body></html>'''

def segfault(req):
    log = logging.getLogger()
    hdlr = ApacheLogHandler(req)
    log.addHandler(hdlr)
    log.critical('test.segfault: seg fault?')
    return '''removeHandler cleanup NOT registered:
              check the log for a segfault'''

def no_segfault(req):
    log = logging.getLogger()
    hdlr = ApacheLogHandler(req)
    log.addHandler(hdlr)
    req.register_cleanup(log.removeHandler, hdlr)
    log.critical('test.no_segfault: seg fault?')
    return '''removeHandler cleanup registered:
              check the log for a segfault'''

The other problem is that you are not removing the handler instance
from the logging instance so you still have a memory leak. 100k
requests would result in 100k handler instances. Oh, and there might
be a bit of a performance issue when emit() gets fired 100k
times. ;)


Good point... here's another one:


  # A log handler for mod-python

  import logging
  from mod_python import apache


  class ApacheLogHandler(logging.Handler):
      """A handler class which sends all logging to Apache."""

      def __init__(self, request):
          """
          Initialize the handler (does nothing)
          """
          logging.Handler.__init__(self)
          self.request = request

          def cleanup(data = None):
              self.request = None
              logging.getLogger().removeHandler(self)

          request.register_cleanup(cleanup)

          # Set up the thing
          self.level_mapping = { }

          self.level_mapping[logging.CRITICAL] = apache.APLOG_CRIT
          self.level_mapping[logging.ERROR] = apache.APLOG_ERR
          self.level_mapping[logging.WARNING] = apache.APLOG_WARNING
          self.level_mapping[logging.INFO] = apache.APLOG_INFO
          self.level_mapping[logging.DEBUG] = apache.APLOG_DEBUG

      def emit(self, record):
          """Emit a record."""
          msg = self.format(record)
          if self.request != None:
              self.request.log_error(msg, self.level_mapping[record.levelno])

          # We *could* log to apache here:
          #else:
          #    apache.log(msg)


  # End

This version does not segfault, and should take care of the memory leak but only for the root logger. If the user specifies a different logger...

log = logging.getLogger('myLooger')

... we are back to the potential segfault problems.

I also want to mention that there will be a performance impact in using logging since only one thread can access the logging object at a time. I'm including this comment now just in case I forget later. Not a big deal but it is something that should be considered for a high traffic site and is an argument for not using the standard python logging facility internally in mod_python... which Nic was *not* asking for anyway. :)

Regards,
Jim

Reply via email to