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