开发者

How do I get the name of the class containing a logging call in Python?

If I want the function name I can simply include %(funcName)s in the Formatter. But how do I get the name of the class conta开发者_开发百科ining the logging call instead?

I've gone through the documentation for logging, but I can't find any mentioning of it.


For a rather easy, pythonic way to get the class name to output with your logger, simply use a logging class.

import logging


# Create a base class
class LoggingHandler:
    def __init__(self, *args, **kwargs):
        self.log = logging.getLogger(self.__class__.__name__)


# Create test class A that inherits the base class
class testclassa(LoggingHandler):
    def testmethod1(self):
        # call self.log.<log level> instead of logging.log.<log level>
        self.log.error("error from test class A")


# Create test class B that inherits the base class
class testclassb(LoggingHandler):
    def testmethod2(self):
        # call self.log.<log level> instead of logging.log.<log level>
        self.log.error("error from test class B")


testclassa().testmethod1()
testclassb().testmethod2()

By naming the logger as above, the %(name)s will be the name of your class

example output

$ python mymodule.py
[2016-02-03 07:12:25,624] ERROR [testclassa.testmethod1:29] error from test class A
[2016-02-03 07:12:25,624] ERROR [testclassb.testmethod2:36] error from test class B

Alternative(s)

Non-inheritance

import logging


def log(className):
    return logging.getLogger(className)


class testclassa:
    def testmethod1(self):
        log(self.__class__.__name__).error("error from test class A")


class testclassb:
    def testmethod2(self):
        log(self.__class__.__name__).error("error from test class B")


testclassa().testmethod1()
testclassb().testmethod2()


You should use extra argument:

views.py

import logging

class SampleClass():
    def sample_func(self):
        logging.getLogger('info_logger').info('some text', extra={'className': self.__class__.__name__})

logger_settings.py

'format': '%(className)s | %(message)s ',

output log:

INFO | SampleClass | "some text" 


There is almost certainly a better way of doing this, but until someone points that out, this will work:

import inspect

class testclass:
    def testmethod(self):
        log()

def log():
    stack = inspect.stack()
    try:
        print "Whole stack is:"
        print "\n".join([str(x[4]) for x in stack])
        print "-"*20
        print "Caller was %s" %(str(stack[2][4]))
    finally:
        del stack

testclass().testmethod()

The output of this is the following:

Whole stack is:
['    stack = inspect.stack()\n']
['        f()\n']
['testclass().testmethod()\n']
['                exec code in self.locals\n']
['            ret = method(*args, **kwargs)\n']
None
--------------------
Caller was ['testclass().testmethod()\n']


Yet another approach if you also want the module name:

class MyClass(object):
    @property
    def logger(self):
        return logging.getLogger(f"{__name__}.{self.__class__.__name__}")

    def what(self, ever):
        self.logger.info("%r", ever)


I personally just tend to name my loggers after classes, as it makes it much easier to track down where a particular message came from. So you can have a root logger named "top", and for the module "a" and class "testclass", I name my logger "top.a.testclass".

I don't see the need to otherwise retrieve the classname, since the log message should give you all the information you need.

@ed's response above, it feels very unpythonic to me and it is not something I would be comfortable with using on production code.


This is a function to make an informative log message using the representation class method:

https://docs.python.org/3/library/functions.html#repr

def log_message(thing: object = None, message: str = '') -> str:
    """:returns: detailed error message using reflection"""
    return '{} {}'.format(repr(thing), message)

This can be implemented to any class using a mix-in:

class UtilMixin(object):
    def log(self, message: str = '') -> str:
        """:returns: Log message formatting"""
        return log_message(thing=self, message=message)

You can than be associated with a class using multiple inheritance:

class MyClass(object, UtilMixin):
    def __repr__(self) -> str:
        return '<{}>'.format(self)
    pass

Usage

logger.warning(self.log('error message goes here'))
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜