【问题标题】:Avoid `logger=logging.getLogger(__name__)`避免使用 `logger=logging.getLogger(__name__)`
【发布时间】:2016-04-16 01:20:34
【问题描述】:

我们按照 django 文档告诉我们的方式设置日志记录:

https://docs.djangoproject.com/en/2.1/topics/logging/#using-logging

# import the logging library
import logging

# Get an instance of a logger
logger = logging.getLogger(__name__)

def my_view(request, arg1, arg):
    ...
    if bad_mojo:
        # Log an error message
        logger.error('Something went wrong!')

我想在每个想要记录的 Python 文件中避免这一行:

logger = logging.getLogger(__name__)

我希望它简单:

logging.error('Something went wrong!')

但我们想保留一个特性:我们想在日志输出中看到 Python 文件名。

到目前为止,我们使用这种格式:

'%(asctime)s %(name)s.%(funcName)s +%(lineno)s: %(levelname)-8s [%(process)d] %(message)s'

示例输出:

2016-01-11 12:12:31 myapp.foo +68: ERROR Something went wrong

如何避免logger = logging.getLogger(__name__)

【问题讨论】:

  • 通常情况下,我对你不应该这样做的问题感到恼火。不过,在这里,我不得不说这似乎是个坏主意。 “简单”,在 Pythonic 意义上和日志记录并没有真正对齐。日志是受 Java 启发的,虽然功能强大,但使用起来很棘手。我最初错误地按照您的建议进行了操作,并且正在使用 logging.error() 等。这最终使我在配置和过滤能力方面受到了打击,因为这不是它的预期使用方式。 YMMV,但我会在别处寻找简化。每个模块节省 1 行?干什么用的?
  • 这一行是允许每个模块配置日志记录的内容。例如,降低您当前正在排除故障的模块上的日志记录阈值(即更详细)而不影响其他模块。把它扔掉,使用提供的日志记录模块的许多理由变得可疑。
  • 我对您的“那一行是允许每个模块配置日志记录。”的回复:我喜欢 DevOps:开发人员应该知道如何操作(例如 nagios),操作员应该知道如何开发。我喜欢的下一件事:区分两者。配置日志记录是“操作”。 Python代码是“开发”。这就是我不想修改代码来更改日志记录配置的原因。
  • @guettli,您似乎误解了日志记录的配置方式。这个__name__ 变成类似于'abc.qwe.zxc'的东西,默认情况下,记录的所有内容都由根记录器捕获,然后在单独的配置文件中,您可以将特定记录器分配给'abc.qwe'命名空间并告诉它不要将事件传播到根记录器,而是静音或登录到单独的处理程序(文件)。您不必修改源代码来配置日志记录。由于该模块基本上是 python 的 log4j,因此大多数管理员和开发人员都了解如何在您的应用程序中配置 looffing。

标签: python logging


【解决方案1】:

路径名呢?来自https://docs.python.org/2/library/logging.html#formatter-objects

/Users/jluc/kds2/wk/explore/test_so_41.py

import logging

#another module, just to have another file...
import test_so_41b

#not so much to use basicConfig as a quick usage of %(pathname)s
logging.basicConfig(level=logging.DEBUG,
                    format='%(pathname)s %(asctime)s %(levelname)s %(message)s',
                    # filename='/tmp/myapp.log',
                    # filemode='w',
                    )

logging.debug('A debug message')
logging.info('Some information')
logging.warning('A shot across the bows')

test_so_41b.dosomething("hey there")

/Users/jluc/kds2/wk/explore/test_so_41b.py

import logging

def dosomething(msg):
    logging.info(msg)

audrey:explore jluc$ python test_so_41.py

输出:

test_so_41.py 2016-01-16 14:46:57,997 DEBUG A debug message
test_so_41.py 2016-01-16 14:46:57,997 INFO Some information
test_so_41.py 2016-01-16 14:46:57,997 WARNING A shot across the bows
/Users/jluc/kds2/wk/explore/test_so_41b.py 2016-01-16 14:46:57,997 INFO hey there

【讨论】:

    【解决方案2】:

    您可以使用logging.basicConfig 定义通过logging 可用的默认接口,如下所示:

    import logging
    logging.basicConfig(level=logging.DEBUG,
                        format='%(asctime)s %(name)s.%(funcName)s +%(lineno)s: %(levelname)-8s [%(process)d] %(message)s',
                        )
    

    现在,只要您在应用程序的任何位置执行以下操作,就会使用此定义:

    import logging
    logging.error(...)
    

    虽然__name__ 不可用,但可通过可用于错误字符串格式化的默认LogRecord attributes 获得等效(和其他选项) - 包括modulefilenamepathname。以下是对此的两个脚本演示:

    scripta.py

    import logging
    logging.basicConfig(level=logging.DEBUG,
                        format='%(asctime)s %(module)s %(name)s.%(funcName)s +%(lineno)s: %(levelname)-8s [%(process)d] %(message)s',
                        )
    
    from scriptb import my_view
    
    my_view()
    

    scriptb.py

    import logging
    
    def my_view():
        # Log an error message
        logging.error('Something went wrong!')
    

    日志定义在scripta.py 中定义,并添加了module 参数。在scriptb.py 中,我们只需导入logging 即可访问此定义的默认值。运行scripta.py 时会生成以下输出:

    2016-01-14 13:22:24,640 scriptb root.my_view +9: ERROR    [14144] Something went wrong!
    

    其中显示了发生错误记录的模块 (scriptb)。

    根据this answer,您可以继续使用来自 Django 的任何每个模块的日志配置,方法是关闭 Django 处理并设置根处理程序,如下所示:

    # settings.py - django config
    LOGGING_CONFIG = None # disables Django handling of logging
    LOGGING = {...}  # your standard Django logging configuration
    
    import logging.config
    logging.config.dictConfig(LOGGING)
    

    【讨论】:

    • 哇,如果这么简单,我问自己为什么 django 开发人员会使用 logger=logging.getLogger(__name__) 推广更复杂的方式。 Django 文档:docs.djangoproject.com/en/1.9/topics/logging/#using-logging
    • .getLogger(__name__) 样式允许过滤和处理 Django 框架内的不同(例如,每个模块、每个应用程序)记录器 - 使用 .basicConfig(...) 会丢失这些记录器。例如,请参阅您链接的页面上的 Configure Logging 部分。您必须决定这种配置丢失对您的用例是否重要。
    • 我刚刚用另一个问题上的一些信息更新了答案 - 显然您可以使用相同的结构化日志记录,使用带有字典定义的 .dictConfig。跨度>
    • 请注意,如果您从不调用logging.getLogger(__name__),那么日志条目的%(name)s 部分将始终为root
    猜你喜欢
    • 2016-12-21
    • 1970-01-01
    • 2015-02-06
    • 2018-11-15
    • 1970-01-01
    • 2021-08-07
    • 1970-01-01
    • 2012-04-18
    • 2014-10-17
    相关资源
    最近更新 更多