On 22/10/2005, at 8:05 AM, Nick wrote:

As to providing "handler()" this is again because it is a separate sample distinct from mod_python. If a part of mod_python that can all be done
transparently. I didn't want to provide a sample where people had to
hack on their mod_python installation to try it.


It seems like there should be a simpler mechanism to be able to use this code without using a separate, second handler. That's confusing to the unitiated. I guess I like the idea of providing a way for you to intialize the logging in your handler code rather than relying on another handler to do it, even though your way makes it somewhat automagic. I prefer things being explicit and simply understood rather than a "just set it up that way to make it work" explanation.

In my world, I'd rather see a call to logging.info, for example, raise an exception because I didn't tell it what req to use in some sort of initialization code. I don't think that's altogether unreasonable to ask of the user if they want to use the logging module. Obviously, since my sample implementation worked that way :) But just purely my opinion.

Not knocking your code -- I think it accomplishes what you set out to do and does it well. I'd just like to see it done in such a way that is more easily understood by noobs (and subsequently leads to fewer support requests on the list) :)

You don't need to define an extra PythonHandler, you could go the way
of making the call explicitly at the beginning of every handler, or published
function if mod_python.publisher is used. Ie.,

  AddHandler python-program .py
  PythonHandler mod_python.publisher

and:

  import apache_log_handler

  def published_function(req):
      apache_log_handler.handler(req)
      ... rest of normal handler

This would be just like you do it now. I even thought of calling the function "cache_request()" instead of "handler()" to make it obvious. Ie., so it would
be:

  AddHandler python-program .py
  PythonHandler apache_log_handler::cache_request
  PythonHandler mod_python.publisher

or if done from handler explicitly like above, would be:

  import apache_log_handler

  def handler(req):
    apache_log_handler.cache_request(req)
    ... rest of normal handler

Personally I would prefer to encourage use of multiple PythonHandler
directives. I too often see on the mailing list examples of peoples code
where they duplicate a common piece of code at the start of all these
published functions for stuff like session handling. One could put that
code in a separate function but with each published function calling that
code, but you still have to have some code in every published function

Use of a separate PythonHandler would be more sensible in my mind
for doing stuff like that as it separates out the code into an earlier step and it isn't necessary for every module to have to import the module with
the common code and call it. Where there is some state, it can be saved
into the request object, eg. "req.session", so that the published function
can access it. With care, the saving of the session could itself be done
as a latter phase. Thus:

  AddHandler python-program .py
  PythonHandler session_manager::login
  PythonHandler mod_python.publisher
  PythonHandler session_manager::save

You could very easily add to a whole bunch of published functions a
session based login mechanism without having to modify all the
published functions.

Anyway, back to the log handler. In the sample I gave, the request cache
was embedded in the log handler module itself. In mod_python 3.3 if
the module loading mechanism is improved, there will need to be an
inbuilt request cache anyway. This is to fix up problems where log and
autoreload options can't easily be supplied to apache.import_module()
when the function is used at global scope in a module. See:

http://www.dscpl.com.au/articles/modpython-003.html#configuration- of-logging http://www.dscpl.com.au/articles/modpython-003.html#disabling-of- autoreload

The idea would be that the defaults for "log" and "autoreload" parameters
would become "None". If the parameters are received as "None", ie., not
explicitly set, the request object would be obtained from the request cache
and PythonDebug and PythonAutoReload consulted as appropriate.

Thus the request cache is a totally distinct bit of functionality from logging. Since this request cache functionality would therefore be an integral part of mod_python if this is done that way, if an Apache log handler class is incorporated, it could use the inbuilt request cache. As a result, neither the PythonHandler for triggering the caching of the request, nor the alternative of explicitly calling it at the start of a handler of published function would be
required.

Thus ultimately, the user would have two options of what they could do if they wanted to using the "logging" module. The first is that they access the
"mod_python" logger instance and use that.

  import logging

  log = logging.getLogger("mod_python")
  log.warning("loaded module")

  def handler(req):
     log.warning("handler")
     ...

If they wanted to have their own logger instances but configure them to use
Apache logging, they would need to use PythonImport to import a module
against the desired interpreter, and have in that module something like:

  import logging
  from mod_python import util

  log = logging.getLogger("webapp")
  log.addHandler(util.ApacheLogHandler())

Use of PythonImport would be the preferred way and mod_python way of
doing it, but you could also do it as part of a module which is part of the web application which gets imported by all handler modules, but you would need to ensure that that module is not reloaded, or protected itself so as to
ensure that registration doesn't occur more than once.

Either way, the handler or published function wouldn't need to worry
about setting up anything, it would just use the "logging" interface and not
care whether it is attached to anything, that would be dealt with by the
module imported using PythonImport. Thus:

  import logging

  log = logging.getLogger("webapp")
  log.warning("loaded module")

  def handler(req):
     log.warning("handler")
     ...

I am not sure you can get any simpler than that.

I'll admit that at the moment I haven't looked at high the hierarchy of named loggers exactly works, but as far as I can tell, that would again be dealt with
by the configuration module imported using PythonImport and any handler
shouldn't need to worry about it, except as far as using the appropriate
named logger in the hierarchy.

I can see that I'll have to put this on my list of topics for writing a mini article. :-)

Graham

Reply via email to