回答此问题可获得 20 贡献值,回答如果被采纳可获得 50 分。
<p>我想从一个基本的日志类开始,它继承自Python的<code>logging.Logger</code>类。但是,我不确定应该如何构造类,以便建立自定义继承的记录器所需的基础。</p>
<p>这就是我目前为止在<code>logger.py</code>文件中的内容:</p>
<pre><code>import sys
import logging
from logging import DEBUG, INFO, ERROR
class MyLogger(object):
def __init__(self, name, format="%(asctime)s | %(levelname)s | %(message)s", 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("myApp")
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>这是主要的<code>myApp.py</code>:</p>
<pre><code>import entity
from core import MyLogger
my_logger = MyLogger("myApp")
def cmd():
my_logger.info("Hello from %s!" % ("__CMD"))
entity.third_party()
entity.another_function()
cmd()
</code></pre>
<p>这是<code>entity.py</code>模块:</p>
<pre><code># Local modules
from core import MyLogger
# Global modules
import logging
from logging import DEBUG, INFO, ERROR, CRITICAL
my_logger = MyLogger("myApp.entity", level=DEBUG)
def third_party():
my_logger.info("Initial message from: %s!" % ("__THIRD_PARTY"))
def another_function():
my_logger.warn("Message from: %s" % ("__ANOTHER_FUNCTION"))
</code></pre>
<p>当我运行主应用程序时,我会得到:</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>所有内容都打印了两次,可能是因为我未能正确设置logger类。</p>
<p>--<strong>更新(01):澄清我的目标</strong>--</p>
<p><strong>(1)</strong>我想将主要日志功能封装在一个位置,这样我就可以做到:</p>
<pre><code> from mylogger import MyLogger
my_logger = MyLogger("myApp")
my_logger.info("Hello from %s!" % ("__CMD"))
</code></pre>
<p><strong>(2)</strong>我计划使用<code>CustomFormatter</code>和<code>CustomAdapter</code>类。此位不需要自定义日志类,可以直接插入。</p>
<p><strong>(3)</strong>我可能不需要深入了解底层日志类(记录等)的定制,截取<code>logger.info</code>、<code>loggin.debug</code>等就足够了。</p>
<p>因此,回到在这些论坛上多次流传的<a href="http://code.activestate.com/recipes/474089-extending-the-logging-module/" rel="nofollow">this python receipt</a>:</p>
<p>我试图在拥有一个<code>Logger Class</code>之间找到一个最佳点,但仍然能够使用内置函数,如赋值<code>Formatters</code>和<code>Adapters</code>等,因此所有的东西都与<code>logging</code>模块兼容。</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 "extra"
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 ["message", "asctime"]) or (key in rv.__dict__):
raise KeyError("Attempt to overwrite %r in LogRecord" % key)
rv.__dict__[key] = extra[key]
return rv
</code></pre>
<p>--<strong>更新(02):正在进行的工作可能的解决方案</strong>--</p>
<p>我用一个简单的python应用程序创建了一个repo,演示了一个可能的解决方案。请随时登峰造极,帮助我改进。</p>
<p><a href="https://github.com/symbolix/xlog_example" rel="nofollow">xlog_example</a></p>
<p>这个例子有效地演示了通过继承重写<code>logging.Logger</code>类和<code>logging.LogRecord</code>类的技术。</p>
<p>两个外部项混合到日志流中:<code>funcname</code>和<code>username</code>,而不使用任何<code>Formatters</code>或<code>Adapters</code>。</p>