Eric S. Johansson wrote:
> Peter Otten wrote:
>> Eric S. Johansson wrote:
>>
>>> I need to to be able to conditionally log based on the method the log
>>> statement is in and one other factor like a log level. in order to do
>>> so, I need to be able to automatically find out the name of the method
>>> and its class but I haven't found out how to do that yet.
>>>
>>> for example,
>>>
>>> class catus(Felis):
>>> def Siamese_cat( yowl, purr, demand_food):
>>>
>>> ...
>>> log("state of litter box %s"% litter_box.smell, level = 1)
>>>
>>>
>>> If the table of methods logged contains "catus.Siamese_cat", then I
>>> would expect to see the output of the log statements in a log file. If
>>> not then I wouldn't see anything in the log.
>>>
>>> Has somebody done this already? Is it even possible to do without
>>> manually adding the class and method information for every log
>>> statement?
>>>
>>> a related question is using signals for reloading configurations etc. I
>>> have to find any good examples of how to use signals to cause a
>>> long-running process to reload external data. Any good pointers?
>>
>> Instead of rolling your own, use the logging package which can handle
>> everything but the class info out of the box (levels are spelt as method
>> names info(), warn() etc.).
>
> I was planning on using logging. I've been using syslog for too long
>>
>> import logging
>>
>> class LoggedType(type):
>> def __new__(mcl, name, bases, classdict):
>> classdict["logger"] = logging.getLogger(name)
>> return type.__new__(mcl, name, bases, classdict)
>
> __new__ is new to me. took a look at
> http://www.python.org/download/releases/2.2.3/descrintro/#__new__ which
> give me some clue but not enough. what I get is that in call
> initialization, you add an entry to the class dict (adds new method??).
> I see that name, bases, or classdict are part of the normal class
> construction process and refer to the class under construction. I'm
> guessing mcl comes from __metaclass__ and defaults to type?
The first parameter to __new__() is always the actual class (here
LoggedType). Because LoggedType's purpose is to serve as a metaclass I used
the shortcut mcl.
> the getLogger creates a logging channel so there is one channel per
> class? but what selects the class for output or is that a derived
> logger class I need to create?
As a general direction try to understand the logging package, the __new__()
method (a constructor in C++), and metaclasses (a class is an instance of
another class which is called metaclass to avoid confusion when talking
about both) independently before jumping into the mix.
> also, how could one automatically determine the method doing the logging?
>
>>
>> class Felis:
>> __metaclass__ = LoggedType
>
> needed in every top level class?
Yes. The good news is that you only need one toplevel class
class Logged:
__metaclass__ = LoggedType
that you can inherit from.
>> def alpha(self):
>> self.logger.info("felis-alpha")
>>
>> class Catus(Felis):
>> def alpha(self):
>> self.logger.info("catus-alpha")
>> def beta(self):
>> self.logger.info("catus-beta")
>>
>> if __name__ == "__main__":
>> logging.basicConfig(format="%(name)s.%(funcName)s: %(message)s",
>> level=logging.INFO)
>> f = Felis()
>> f.alpha()
>> c = Catus()
>> c.alpha()
>> c.beta()
>
>
>>
>> If the metaclass bothers you, here's a simpler alternative:
>
> simpler to implement but more error prone. I like the metaclass model.
> now if one could fill in the class and method name automatically, life
> would be good.
Well, the method name is already there in my example; a class name is there,
too (disguised as the logger name), but it is the name of the actual
instance's class, not the class where the method is defined.
Here is a revised example that logs the defining class:
import logging
class LoggedType(type):
def __new__(mcl, name, bases, classdict):
classdict["_%s__logger" % name] = logging.getLogger(name)
return type.__new__(mcl, name, bases, classdict)
class Logged:
__metaclass__ = LoggedType
class Felis(Logged):
def alpha(self):
self.__logger.info("Felis.alpha")
def gamma(self):
self.__logger.info("Felis.gamma")
class Catus(Felis):
def alpha(self):
self.__logger.info("Catus.alpha")
def beta(self):
self.__logger.info("Catus.beta")
if __name__ == "__main__":
logging.basicConfig(
format="EXPECTED %(message)s GOT %(name)s.%(funcName)s",
level=logging.INFO)
f = Felis()
f.alpha()
f.gamma()
c = Catus()
c.alpha()
c.beta()
c.gamma()
Peter
--
http://mail.python.org/mailman/listinfo/python-list