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