Logging messages with dictionary args in Python 2.4b1 leads to exception
Steve Holden
steve at holdenweb.com
Wed Oct 20 11:25:34 EDT 2004
Stefan Behnel wrote:
> Paul Clinch schrieb:
>
>> logging.fatal( 'Test is %(test)s' % values)
>> is fine. An why shouldn't you use it in this fashion?
>
>
> I thought a logging API was usually trying to do costly things only when
> it knows it has to. You /could/ do that, but since it doesn't come for
> free - why not first do the check if you will actually log this message?
>
> Ok, I know there's an overhead anyway: function calls, object creation,
> etc. But copying strings and creating string representations of objects
> can be /very/ expensive and should only be done if the log message is
> definitely written.
>
Well that's as may be, but is the logging function going to be taking up
much of your program's run time? I'd suspect not. Premature
optimisation, etc., etc.
> I'd simply say that constructing a log message from arguments is such a
> common thing that it is worth providing efficient API support for it.
> And I think it's truely counter-pythonic to prevent the usage of
> dictionaries at this point.
>
Your original message observed that LogRecord performs
msg = msg % self.args
and you said "this should work"; that was where your mistake lay. The
call was constructed using
apply(root.log, (level, msg)+args, kwargs)
and I presume that args was actually obtained from a formal parameter
*args (allowing the functiopn call to aggregate all non-keyword
arguments). Thus for your call to work the usage in LogRecord would have
had to be
msg = msg % self.args[0]
The point of the interface currently used is that it allows you to pass
a variable number of arguments for substitution into the message when
it's actually built. The *args construct neatly aggregates them into a
tuple. So when the substituion was performed inside LogRecord you were
actually providing a tuple whose single element was a dictionary, an
attempt doomed to failure.
A possible enhancement which might meet your arguments would allow the
user to provide EITHER a tuple of arguments OR a set of keyword
arguments. LogRecord could then say:
if args:
msg = msg % args
else:
msg = msg % kwargs
and you would then be able to make a call like
logging.log(logging.FATAL, 'Test is %(test)s', **values)
But with the code you presented, it's no use bleating that "values *is*
a mapping". While this is certainly true, values was unfortunately just
the only element in the args tuple, and it's the args tuple that's
currently used for substituion. I presume the patch you sent Vijay will
do something similar?
regards
Steve
--
http://www.holdenweb.com
http://pydish.holdenweb.com
Holden Web LLC +1 800 494 3119
More information about the Python-list
mailing list