2013-04-08 102 views
15

任务的Python:在所有模块自定义日志记录

我有脚本的集合,我想他们产生最小的改动统一日志消息模块做记录的实际信息。

我写了一个小模块'custom_logger',我打算从主应用程序调用一次,让它返回一个记录器,然后我将继续使用。

我会导入到应用程序的子模块只能(或者更确切地说,我希望他们)

  • 只能“进口记录日志” - 这样没有具体到我的网站需要做如果有人发现它们有用,它们就会运行。
  • 应该只是记录与log.info/error('message消息“),而不添加任何特定的站点到他们
  • 应该使用已配置‘与所有的格式和左撇子,而不是根’记录影响根记录的配置

* custom_logger.py *

import logging 
import logging.handlers 
import os 
import sys 


def getLogger(name='root', loglevel='INFO'): 
    logger = logging.getLogger(name) 

    # if logger 'name' already exists, return it to avoid logging duplicate 
    # messages by attaching multiple handlers of the same type 
    if logger.handlers: 
    return logger 
    # if logger 'name' does not already exist, create it and attach handlers 
    else: 
    # set logLevel to loglevel or to INFO if requested level is incorrect 
    loglevel = getattr(logging, loglevel.upper(), logging.INFO) 
    logger.setLevel(loglevel) 
    fmt = '%(asctime)s %(filename)-18s %(levelname)-8s: %(message)s' 
    fmt_date = '%Y-%m-%dT%T%Z' 
    formatter = logging.Formatter(fmt, fmt_date) 
    handler = logging.StreamHandler() 
    handler.setFormatter(formatter) 
    logger.addHandler(handler) 

    if logger.name == 'root': 
     logger.warning('Running: %s %s', 
        os.path.basename(sys.argv[0]), 
        ' '.join(sys.argv[1:])) 
    return logger 

然后是它有什么不的什么作品例子几个测试消息的子模块。

submodule.py

import sys 
import custom_logger 
import logging 


class SubClass(object): 

    def __init__(self): 
    # NOK (no idea why since by default (no name parameter), it should return the root logger) 
    #log = logging.getLogger() 
    #log.info('message from SubClass/__init__') 

    # OK (works as expected) 
    #log = logging.getLogger('root') 
    #log.info('message from SubClass/__init__') 

    # OK (works as expected) 
    log = custom_logger.getLogger('root') 
    log.info('message from SubClass/__init__') 


    def SomeMethod(self): 
    # OK but I'd have to define `log` for every method, which is unacceptable 
    # Please see question below all code snippets 
    log = custom_logger.getLogger('root') 
    log.info('message from SubClass/SomeMethod') 

和主要应用:app.py这里没有什么特别的:

#!/usr/bin/python 

import custom_logger 
import submodule 

log = custom_logger.getLogger('root', loglevel='DEBUG') 

log.debug('debug message') 
log.info('info message') 
log.warning('warning message') 
log.error('error message') 

a = submodule.SubClass() # this should produce a log message 
a.SomeMethod()   # so should this 

输出,我以后和我得到我,只是以极其丑陋的方式:

% ./app.py 
2013-04-08T03:07:46BST custom_logger.py WARNING : Running: app.py 
2013-04-08T03:07:46BST app.py    DEBUG : debug message 
2013-04-08T03:07:46BST app.py    INFO : info message 
2013-04-08T03:07:46BST app.py    WARNING : warning message 
2013-04-08T03:07:46BST app.py    ERROR : error message 
2013-04-08T03:07:46BST submodule.py  INFO : message from SubClass/__init__ 
2013-04-08T03:07:46BST submodule.py  INFO : message from SubClass/SomeMethod 

我希望能够在app.py中定义一个记录器,然后在子模块中只使用标准的Python日志记录库来使用app.py中已配置的记录器。

此外,一个丑陋的解决方法:如果我把下面的代码在submodule.py进口后:

log = custom_logger.getLogger('root') 

之前我在记录器被app.py配置,有效地使子模块将被执行,不是我的应用程序配置日志

另一个解决办法我认为是:子类的constuctor内,我可以定义

self.log = custom_logger.getLogger('root')

然后用self.log.error( '一些错误')。必须有更好的方法 - 如果您能提出有用的建议或指出我误解了文档的地方,我会非常感激!

PS。我花了很多时间阅读Python日志记录howto(basic和advanced)和cookbook,如果我错过了某些有用的东西,请指出。

谢谢!

回答

3

如果你想改变你可以只使用getLogger()无处不在,不带任何参数根记录。

关于实例安装只在主模块,你可以实例化你的记录,添加自己的处理程序,并在所有其它子模块使用它(像我一样波纹管)。

custom_logger.py创建继承StreamHandler中的一类:

class MyHandler(logging.StreamHandler): 

    def __init__(self): 
     logging.StreamHandler.__init__(self) 
     fmt = '%(asctime)s %(filename)-18s %(levelname)-8s: %(message)s' 
     fmt_date = '%Y-%m-%dT%T%Z' 
     formatter = logging.Formatter(fmt, fmt_date) 
     self.setFormatter(formatter) 

然后,在submodule.py,我把getLogger进口之后,并在方法评价它:

import sys 
import logging 

log = logging.getLogger('root') 

class SubClass(object): 

    def __init__(self): 
     log.info('message from SubClass/__init__') 

    def SomeMethod(self): 
     log.info('message from SubClass/SomeMethod') 

然后,在app.py我创建了一个记录器实例(这将是在所有模块相同),并加入我的处理程序,其格式输出:

#!/usr/bin/python 

import logging 
import custom_logger 
import submodule 

log = logging.getLogger('root') 
log.setLevel('DEBUG') 
log.addHandler(custom_logger.MyHandler()) 

log.debug('debug message') 
log.info('info message') 
log.warning('warning message') 
log.error('error message') 

a = submodule.SubClass() # this should produce a log message 
a.SomeMethod()   # so should this 

输出:

./app.py 
2013-04-08T15:20:05EEST app.py    DEBUG : debug message 
2013-04-08T15:20:05EEST app.py    INFO : info message 
2013-04-08T15:20:05EEST app.py    WARNING : warning message 
2013-04-08T15:20:05EEST app.py    ERROR : error message 
2013-04-08T15:20:05EEST submodule.py  INFO : message from SubClass/__init__ 
2013-04-08T15:20:05EEST submodule.py  INFO : message from SubClass/SomeMethod 
+0

谢谢米哈伊。我想我会有更多的时间来看看它,但我需要等待周末。到目前为止,我已经能够通过在submodule.py中将日志定义为getLogger对象来使我的类可以完成所有工作(附加格式器,处理程序和设置日志级别)。我希望这可以在不将事物放在类定义之外的情况下完成。 我的问题更多的是“为什么我所做的某些方法没有按预期工作,因为我想了解其背后的原因,而不是将代码交给我,但我非常感谢您的帮助: ) – 2013-04-10 01:27:35

+0

我更新了我的答案,除此之外,您可以查看模块的代码。您可以看到根记录器在导入过程中被实例化了,我也不明白为什么getLogger(“root”)不能正常工作在所有情况下(你可以在app.py中执行getLogger(),在submodule.py中执行getLogger(“root”),你将得到你所需要的东西,但是反之亦然) – Mihai 2013-04-10 14:15:47

+0

如何使用stdout重定向到文件例如python ./app.py >> file.log? – 2016-04-14 11:37:45