How to extend the logging.Logger Class?
<p>I would like to start with a basic logging class that inherits from Python's <code>logging.Logger</code> class. However, I am not sure about how I should be constructing my class so that I can establish the basics needed for customising the inherited logger.</p>
<p>This is what I have so far in my <code>logger.py</code> file:</p>
<pre><code>import sys
import logging
from logging import DEBUG, INFO, ERROR

class MyLogger(object):
    def __init__(self, name, format=&quot;%(asctime)s | %(levelname)s | %(message)s&quot;, level=INFO):
        # Initial construct.
        self.format = format
        self.level = level
        self.name = name

        # Logger configuration.
        self.console_formatter = logging.Formatter(self.format)
        self.console_logger = logging.StreamHandler(sys.stdout)
        self.console_logger.setFormatter(self.console_formatter)

        # Complete logging config.
        self.logger = logging.getLogger(&quot;myApp&quot;)
        self.logger.setLevel(self.level)
        self.logger.addHandler(self.console_logger)

    def info(self, msg, extra=None):
        self.logger.info(msg, extra=extra)

    def error(self, msg, extra=None):
        self.logger.error(msg, extra=extra)

    def debug(self, msg, extra=None):
        self.logger.debug(msg, extra=extra)

    def warn(self, msg, extra=None):
        self.logger.warn(msg, extra=extra)
</code></pre>
<p>This is the main <code>myApp.py</code>:</p>
<pre><code>import entity
from core import MyLogger

my_logger = MyLogger(&quot;myApp&quot;)

def cmd():
    my_logger.info(&quot;Hello from %s!&quot; % (&quot;__CMD&quot;))

entity.third_party()
entity.another_function()
cmd()
</code></pre>
<p>And this is the <code>entity.py</code> module:</p>
<pre><code># Local modules
from core import MyLogger

# Global modules
import logging
from logging import DEBUG, INFO, ERROR, CRITICAL

my_logger = MyLogger(&quot;myApp.entity&quot;, level=DEBUG)

def third_party():
    my_logger.info(&quot;Initial message from: %s!&quot; % (&quot;__THIRD_PARTY&quot;))

def another_function():
    my_logger.warn(&quot;Message from: %s&quot; % (&quot;__ANOTHER_FUNCTION&quot;))
</code></pre>
<p>When I run the main app, I get this:</p>
<pre><code>2016-09-14 12:40:50,445 | INFO | Initial message from: __THIRD_PARTY!
2016-09-14 12:40:50,445 | INFO | Initial message from: __THIRD_PARTY!
2016-09-14 12:40:50,445 | WARNING | Message from: __ANOTHER_FUNCTION
2016-09-14 12:40:50,445 | WARNING | Message from: __ANOTHER_FUNCTION
2016-09-14 12:40:50,445 | INFO | Hello from __CMD!
2016-09-14 12:40:50,445 | INFO | Hello from __CMD!
</code></pre>
<p>Everything is printed twice, as probably I have failed to set the logger class properly.</p>
<h2>Update 1</h2>
<p>Let me clarify my goals.</p>
<p><strong>(1)</strong> I would like to encapsulate the main logging functionality in one single location so I can do this:</p>
<pre><code> from mylogger import MyLogger
 my_logger = MyLogger(&quot;myApp&quot;)
 my_logger.info(&quot;Hello from %s!&quot; % (&quot;__CMD&quot;))
</code></pre>
<p><strong>(2)</strong> I am planning to use <code>CustomFormatter</code> and <code>CustomAdapter</code> classes. This bit does not require a custom logging class, those can be plugged in straight away.</p>
<p><strong>(3)</strong> I probably do not need to go very deep in terms of customisation of the underlying logger class (records etc.), intercepting <code>logger.info</code>, <code>loggin.debug</code> etc. should be enough.</p>
<p>So referring back to <a href="http://code.activestate.com/recipes/474089-extending-the-logging-module/" rel="noreferrer">this python receipt</a> that has been circulated many times on these forums:</p>
<p>I am trying to the find the sweet point between having a <code>Logger Class</code>, yet still be able to use the built in functions like assigning <code>Formatters</code> and <code>Adapters</code> etc. So everything stays compatible with the <code>logging</code> module.</p>
<pre><code>class OurLogger(logging.getLoggerClass()):
    def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None):
        # Don't pass all makeRecord args to OurLogRecord bc it doesn't expect &quot;extra&quot;
        rv = OurLogRecord(name, level, fn, lno, msg, args, exc_info, func)
        # Handle the new extra parameter.
        # This if block was copied from Logger.makeRecord
        if extra:
            for key in extra:
                if (key in [&quot;message&quot;, &quot;asctime&quot;]) or (key in rv.__dict__):
                    raise KeyError(&quot;Attempt to overwrite %r in LogRecord&quot; % key)
                rv.__dict__[key] = extra[key]
        return rv
</code></pre>
<h2>Update 2</h2>
<p>I have created a repo with a simple python app demonstrating a possible solution. However, I am keen to improve this.</p>
<p><a href="https://github.com/symbolix/xlog_example" rel="noreferrer">xlog_example</a></p>
<p>This example effectively demonstrates the technique of overriding the <code>logging.Logger</code> class and the <code>logging.LogRecord</code> class through inheritance.</p>
<p>Two external items are mixed into the log stream: <code>funcname</code> and <code>username</code> without using any <code>Formatters</code> or <code>Adapters</code>.</p>