一篇文章教你如何用Python记录日志

发表于:2018-3-22 09:36

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:李趴趴要化身女超人    来源:伯乐在线

  过度格式化字符串
  应该尽量避免使用 loggger.info(“string template {}”.format(argument)) ,可能的话尽量使用 logger.info(“string template %s”, argument)。 这是个更好的实践,因为只有当日志被发送时,字符串才会发生真正改变。当我们记录的层级在 INFO 之上时,不这么做会导致浪费周期,因为这个改变仍然会发生。
  捕捉和格式化异常
  通常,我们想记录在抓取模块异常的日志信息,如果这样写会很直观:
try:
...
except Exception as error:
logger.info("Something bad happened: %s", error)
  但是这样的代码会给我们显示类似于 Something bad happened: “secret_key.” 的日志行,这并不是很有用。如果我们使用 exc_info 作为事先说明,那么它将会如下显示:
try:
...
except Exception:
logger.info("Something bad happened", exc_info=True)
Something bad happened
Traceback (most recent call last):
File "sample_project.py", line 10, in code
inner_code()
File "sample_project.py", line 6, in inner_code
x = data["secret_key"]
KeyError: 'secret_key'
  这不仅仅会包含异常的准确资源,同时也会包含它的类型。
  设置记录器
  装备我们的软件很简单,我们需要设置日志栈,并且制定这些记录是如何被发出的。
  以下是设置日志栈的多种方法
  基础设置
  这是至今最简单的设置日志记录的方法。使用 logging.basicConfig(level=”INFO”) 搭建一个基础的 StreamHandler ,这样就会记录在 INFO 上的任何东西,并且到控制台以上的级别。以下是编写基础设置的一些参数:
  在设置简单的脚本上,这是简单又使用的方法。
  请注意, basicConfig 仅仅在运行的一开始可以这么调用。如果你已经设置了你的根记录器,调用 basicConfig 将不会奏效。
  字典设置
  所有元素的设置以及如何连接它们可以作为字典来说明。这个字典应当由不同的部分组成,包括记录器、处理器、格式化以及一些基本的通用参数。
  例子如下:
config = {
'disable_existing_loggers': False,
'version': 1,
'formatters': {
'short': {
'format': '%(asctime)s %(levelname)s %(name)s: %(message)s'
},
},
'handlers': {
'console': {
'level': 'INFO',
'formatter': 'short',
'class': 'logging.StreamHandler',
},
},
'loggers': {
'': {
'handlers': ['console'],
'level': 'ERROR',
},
'plugins': {
'handlers': ['console'],
'level': 'INFO',
'propagate': False
}
},
}
import logging.config
logging.config.dictConfig(config)
  当被引用时, dictConfig 将会禁用所有运行的记录器,除非 disable_existing_loggers 被设置为 false。这通常是需要的,因为很多模块声明了一个全球记录器,它在 dictConfig 被调用之前被导入的时候将会实例化。
  你可以查看 schema that can be used for the dictConfig method(链接)。通常,这些设置将会存储在一个 YAML 文件中,并且从那里设置。很多开发者会倾向于使用这种方式而不是使用 fileConfig(链接),因为它为定制化提供了更好的支持。
  拓展 logging
  幸亏设计了这种方式,拓展 logging 模块很容易。让我们来看些例子:
  logging JSON | 记录 JSON
  只要我们想要记录,我们可以通过创建一种自定义格式化来记录 JSON ,它会将日志记录转化为 JSON 编码的字符串。
import logging
import logging.config
import json
ATTR_TO_JSON = ['created', 'filename', 'funcName', 'levelname', 'lineno', 'module', 'msecs', 'msg', 'name', 'pathname', 'process', 'processName', 'relativeCreated', 'thread', 'threadName']
class JsonFormatter:
def format(self, record):
obj = {attr: getattr(record, attr)
for attr in ATTR_TO_JSON}
return json.dumps(obj, indent=4)
handler = logging.StreamHandler()
handler.formatter = JsonFormatter()
logger = logging.getLogger(__name__)
logger.addHandler(handler)
logger.error("Hello")
  添加更多上下文
  在格式化中,我们可以指定任何日志记录的属性。
  我们可以通过多种方式增加属性,在这个例子中,我们用过滤器来丰富日志记录。
import logging
import logging.config
GLOBAL_STUFF = 1
class ContextFilter(logging.Filter):
def filter(self, record):
global GLOBAL_STUFF
GLOBAL_STUFF += 1
record.global_data = GLOBAL_STUFF
return True
handler = logging.StreamHandler()
handler.formatter = logging.Formatter("%(global_data)s %(message)s")
handler.addFilter(ContextFilter())
logger = logging.getLogger(__name__)
logger.addHandler(handler)
logger.error("Hi1")
logger.error("Hi2")
  这样有效地在所有日志记录中增加了一个属性,它可以通过记录器。格式化会在日志行中包含这个属性。
  请注意这会在你的应用中影响所有的日志记录,包含你可能用到以及你发送日志的库和其他的框架。它可以用来记录类似于在所有日志行里的一个独立请求 ID ,去追踪请求或者去添加额外的上下文信息。
  从 Python 3.2 开始,你可以使用 setLogRecordFactory 去获得所有日志的创建记录和增加额外的信息。这个 extra attribute 和 LoggerAdapter class 或许同样是有趣的。
  缓冲日志
  有时候当错误发生时,我们想要排除日志故障。创建一个缓冲的处理器,来记录当错误发生时的最新故障信息是一种可行的办法。下面的代码是个非人为策划的例子:
import logging
import logging.handlers
class SmartBufferHandler(logging.handlers.MemoryHandler):
def __init__(self, num_buffered, *args, **kwargs):
kwargs["capacity"] = num_buffered + 2  # +2 one for current, one for prepop
super().__init__(*args, **kwargs)
def emit(self, record):
if len(self.buffer) == self.capacity - 1:
self.buffer.pop(0)
super().emit(record)
handler = SmartBufferHandler(num_buffered=2, target=logging.StreamHandler(), flushLevel=logging.ERROR)
logger = logging.getLogger(__name__)
logger.setLevel("DEBUG")
logger.addHandler(handler)
logger.error("Hello1")
logger.debug("Hello2")  # This line won't be logged
logger.debug("Hello3")
logger.debug("Hello4")
logger.error("Hello5")  # As error will flush the buffered logs, the two last debugs will be logged
  更多信息
  这篇关于日志记录库的灵活性和可配置性的介绍,目的在于证明它如何设计了分别的关注点的美学。它同样为任何对 logging documentation 和 how-to guide 感兴趣的人提供了一个坚实的基础。虽然这篇文章对于 Python 日志模块并不是一个综合性的知道,但是这里有一些针对于常见的问题的回答。
  问:我的库发送了一个“ no logger configured” 的警告
  答:从 The Hitchhiker’s Guide to Python 查阅 how to configure logging in a library
  问:如果一个记录器没有层级设置会怎么样?
  答:记录器的有效层级,会由它的父级递归定义。
  问:我所有的日志都在本地时间,我如何记录在 UTC ?
  答:格式化就是答案!你需要在你的格式化中设置 converter 属性为通用的 UTC 时间。使用 converter = time.gmtime 。

上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
22/2<12
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号