订阅博客
收藏博客
微博分享
QQ空间分享

葡萄胎,Python 中更高雅的日志记载计划,宝鉴

频道:民生新闻 标签:潘伟珀微博lsd 时间:2020年02月14日 浏览:190次 评论:0条

后台回复【入门材料】

送你十本Python电子书

文 | 六合图库崔庆才

引荐 | 编程派大众号

微信号:codingpy

阅览本文大约需求 5 分钟。

在 Python 中,一般状况下咱们或许直接用自带的 logging 模块来记载日志,包括我之前的时分也是相同。在运用时咱们需求装备一些 Handler、Formatter 来进行一些处理,比方把日志输出到不同的方位,或许设置一个不同的输出格局,或许设置日志分块和备份。但其实个人感觉 logging 用起来其实并不是那么好用,其实首要仍是装备较为繁琐。

常见运用

首要看看 logging 常见的解决方案吧,我一般会装备输出到文件、控制台和 Elasticsearch。输出到控制台就只是是便利直接检查的葡萄胎,Python 中更典雅的日志记载方案,宝鉴;输出到文件是便利直接存储,保存一切前史记载的备份;输出到 Elasticsearch,直接将 Elasticsearch 作为存储和剖析的中心,运用 Kibana 能够十分便利地剖析和检查运转状况。

所以在这儿我根本会对 logging 做如下的封装写法:

import loggingimport sysfrom os import makedirsfrom os.path import dirname, exists
from cmreslogging.handlers import CMRESHandler
loggers = {}
LOG_ENABLED = True # 是否敞开日志LOG_TO_CONSOLE = True # 是否输出到控制台LOG_TO_FILE = True # 是否输出到文件LOG_TO_ES = True # 是否输出到 Elasticsearch
LOG_PATH = './runtime.log' # 日志文件途径LOG_LEVEL = 'DEBUG' # 日庄茱凌图片志等级LOG_FORMAT = '%(levelname)s - %(asctime)s - process: %(process)d - %(filename)s - %(name)s - %(lineno)d - %(module)s - %(message)s' # 每条日志输出格局ELASTIC_SEARCH_HOST = 'eshost' # Elasticsearch HostELASTIC_SEARCH_PORT = 9200 # Elasticsearch PortELASTIC_SEARCH_INDEX = 'runtime' # Elasticsearch Index NameAPP_ENVIRONMENT = 'dev' # 运转环境,如测验环境仍是出产环境
def get_logger(name=None): """ get logger by name :param name: name of logger :return: logger """ global loggers
if not name: name = __name__
if loggers.get(name): return loggers.get(name)
logger = logging.getLogger(name) logger.setLevel(LOG_LEVEL)
# 输出到控制台 if LOG_ENABLED and LOG_TO_CONSOLE: stream_handler = logging.StreamHandler(sys.stdout) stream_handler.setLevel(level=LOG_LEVEL) formatter = logging.For诗篇大全matter(LOG_六艺FORMAT) stream_handler.setFormatter(formatter) logger.addHandler(stream_handler)
# 输出到文件 if LOG_ENABLED and LOG_TO_FILE: # 假如途径不存在,创立日志吾日三省吾身文件文件夹 log_dir = dirname(log_path) if not exists(log_dir): makedirs(log_dir) # 增加 FileHandler file_handler = logging.FileHandler(log_path, encoding='utf-8') file_handler.setLevel(level=LOG_LEVEL) formatter = logging.Formatter(LO我有一个隐秘G_FORMAT) file_handler.setFormatter(formatter) logger.addHandler(file_handler)
# 输出到 Elasticsearch if LO葡萄胎,Python 中更典雅的日志记载方案,宝鉴G_ENABLED and LOG_TO_ES: # 增加 CMR花卷ESHandler es_handler = CMRESHandler(hosts=[{'host': ELASTIC_SEARCH_HOST, 'port': ELASTIC_SEARCH_PORT}], # 能够装备对应的认证权限 auth_type=CMRESHandler.AuthType.NO_AUTH,葡萄胎,Python 中更典雅的日志记载方案,宝鉴 es_index_name=滕子萱ELASTIC_SEARCH_INDEX, # 一个月分一个 Index index_name_frequency=CMRESHandler.IndexNameFrequency.MONTHLY, # 额足疗外增加环境标识 es_additional_fields={'environment': APP_ENV异界封神录IRONMENT} ) es_handler.setLevel(level=LOG_LEVEL) formatter = logging.Formatter(LOG_FORMAT) es_handler.setFormatter(formatter) logger.addHandler(es_handler)
# 保存到大局 loggers loggers[name] = logger return logger

界说完了怎样运用呢?只需求运用界说的办法获取一个 logger,然后 log 对应的内容即可:

logger = get_loggerlogger.debug('this is a message')

运转成果如下:

DEBUG - 2019-10-1122:27:35,923- process:99490- lo本澤朋美gger.py - __main__ -81- logger -thisisa message

咱们看看这个界说的根本完成吧。省份简称首要这儿一些常量是用来界说 logging 模块的一些根本特点的,比方 LOG_ENABLED代表是否敞开日志功用,LOG_TO_ES代表是否将日志输出到 Elasticsearch,别的还有许多其他的日志根本装备,如LOG_FORMAT装备了日志每个条目输出的根本格局,别的还有一些衔接的必要信息。这些变量能够和运转时的命令行或环境变量对接起来,能够便利地完成一些开关和装备的替换。

然后界说了这么一个 get_logger 办法,接纳一个参数 name。首要该办法拿到 name 之后,会到大局的 loggers 变量里边查找,logg远足牦牛在哪买ers 变量是一个大局字典,假如有现已声明过的 logger,直接将其获取回来即可,不必再将其二次初始化。假如 loggers 里边没有找到 name 对应的 logger,那就进行创立即可。创立 logger 之后,能够为其增加各种对应的 Handler,如输出到控制台就用 StreamHandler,输出到文件就用 FileHandler 或 RotatingFileHandler,输出到 Elasticsearch 就用 CMRESHandler,别离装备好对应的信息即可。

最终呢,将新建的 logger 保存到大局的 loggers 里边并回来即可,这样假如有同名的 logge葡萄胎,Python 中更典雅的日志记载方案,宝鉴r 便能够直接查找 loggers 直接回来了。

在这儿依靠了额定的输出到 Elasticsearch 的包,叫做 CMRESHandler,它能够支撑将日志输出到 Elasticsearch 里边,假如要运用的话能够装置一下:

pip install CMRESHandler

其 GitHub 地址是:https://github.com/cmanaha/python-elasticsearch-logger,具体的运用办法能够看看它的官方阐明,如装备认证信息,装备 Index 分隔信息等等。

好,上面便是我之前常用的 logging 装备,经过如上的装备,我就能够完成将 logging 输出到三个方位,并能够完成对应的作用。比方输出到 Elasticsearch 之后,我就能够十分便利地运用 Kibana 来检查其时运转状况,ERROR Log 的份额等等,如图所示:

也能够在它的根底上做更进一步的统计剖析。

loguru

上面的完成办法现已是一个较为可行的装备方案了。但是,我仍是会感觉到有些 Handler 配起来费事,尤其是新建一个母女网项目的许多时分懒得去写一些装备。即使是不必上文的装备,用最根本的几行 logging 装备,像如下的通用装备:

importlogginglogging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')logger = logging.getLogger(__name__)

我也懒得去写,感觉并不是一个典雅的完成办法。

有需求就有动力啊,这不,就有人完成了这么一个库,叫做 loguru,能够将 log 的装备和运用愈加简略和便利。

下面咱们来看看它到底是怎样用的吧。

装置

首要,这个库的装置办法很简略,就用根本的 pip 装置即可,Python 3 版别的装置如下:

pip3 install loguru

装置结束之后,咱们就能够在项目里运用这个 loguru 库了。

根本运用

那么这个库怎样来葡萄胎,Python 中更典雅的日志记载方案,宝鉴用呢?咱们先用一个实例感触下:

fromloguruimportlogger
logger.debug('this is a debug message')

看到了吧,不需求装备什么东西,直接引进一个 logger,然后调用其 debug 办法即可。

在 loguru 里边有且仅有一个首要目标,那便是 logger,loguru 里边有且仅有一个 logger,并且它现已被提早装备了一些根底信息,比方比较友爱的格局化、文本色彩信息等等。

上面的代码运转成果如下:

2019-10-1322:46:12.367| DEBUG | __main__:<module>:4-thisisa debug message

能够看到其默许的输出格局是上面的内容,有时刻、等级、模块名、行号以及日志信息,不需求手动创立 logger,直接运用即可,别的其输出仍是五颜六色的,看起来会愈加友爱。

以上的日志信息是直接输出到控制台的,并没有输出到其他的当地,假如想要输出到其他的方位,比方存为文件,咱们只需求运用一行代码声明即可。

例如将成果一起输出到一个 runtime.log 文件里边,能够这么写:

fromloguruimportlogger
logger.add('runtime.log')logger.debug('this is a debug')

很简略吧,咱们也不需求再声明一个 FileHandler 了,就红尘情歌歌词一行 add 句子搞定,运转之后会发现目录下 runtime.lo逆袭g 里边相同呈现了刚刚控制台输出的 DEBUG 信息。

上面便是一些根本的运用,但这还远远不够,下面咱们来具体了解下它的一些功用模块。

具体运用

既然是日志,那么最常见的便是输出到文件了。loguru 对输出到文件的装备有十分强壮的支撑,比方支撑输出到多个文件,分等等级离输出,过大创立新文件,过久主动删去等等。

下面咱们别离看看这些怎样来完成,这儿根本上便是 add 办法的运用介绍。由于这个 add 办法就相当于给 logger 增加了一个 Handler,它给咱们暴露了许多参数来完成 Handler 的装备,下面咱们来具体介绍下。

首要看看它的办法界说吧:

defadd( self, sink, *, level=_defaults.LOGURU_LEVEL, format=_defaults.LOGURU_FORMAT, filter=_defaults.LOGURU_FILTER, colorize=_defaults.LOGURU_COLORIZE, serialize=_defaults.LOGURU_SERIALIZE, backtrace=_defaults.LOGURU_BACKTRACE, diagnose=_defaults.LOGURU_DIAGNOSE, enqueue=_defaults.LOGURU_ENQUEUE, catch=_defaults.LOGURU_CATCH, **kwargs ): pass

看看它的源代码,它支撑这么多的参数,如 level、format、filter、color 等等。

sink

别的咱们还注意到它有个十分重要的参数 sink,咱们看看官方文档:https://loguru.readthedocs.io/en/stable/api/logger.html#sink,能够了解到经过 sink 咱们能够传入多种不同的数据结构,汇总如下:

•sink 能够传入一个 file 目标,例如 sys.stderr或许open('file.log', '葡萄胎,Python 中更典雅的日志记载方案,宝鉴w')都能够。•sink 能够直接传入一个str字符串或许pathlib.Path目标,其实便是代表文件途径的,假如识别到是这种类型,它会主动创立对应途径的日志文件并将日志输出进去。•sink 能够是一个办法,能够自行界说输出完成。•sink 能够是一个 logging 模块的 Handler,比方 FileHandler、StreamHandler 等等,或许上文中咱们说到的 CMRESHandler 照样也是能够的,这样就能够完成自界说 Handler 的装备。•sink 还能够是一个自界说的类,具体的完成标准能够拜见官方文档。

所以说,方才咱们所演示的输出到文件,只是给它传了一个 str 字符串途径,他就给咱们创立了一个日志文件,便是这个原理。

format、filter、level

下面咱们再了解下它的其他参数,例如 format、filter、level 等等。

其实它们的概念和格局和 logging 模块都是根本相同的了,例如这儿运用 format、filter、level 来规则输出的格局:

logger.add('runtime.log', format="{time} {level} {message}", filter="my_module", level="INFO")

删去 sink

别的增加 sink 之后咱们也能够对其进行删去,相当于从头改写并写入新的内容。

删去的时分依据刚刚 add 办法回来的 id 进行删去即可,看下面的比方:

fromloguruimportlogger
trace = logger.add('runtime.log')logger.debug('this is a debug message')logger.remove(trace)logger.debug('this is another debug message')

看这儿,咱们首要 add 了一个 sink,然后获取它的回来值,赋值为 trace。随后输出了一条日志,然后将 trace 变量传给 remove 办法,再次输出一条日志,看看成果是怎样的。

控制台输出如下:

2019-10-1323:18:26.469| DEBUG | __main__:<module>:4-thisisa debug message2019-10-1323:18:26.469| DEBUG | _透视之眼_main__:<module>:6-thisisanother debug message

日志文件 runtime.log 内容如下:

2019-10-1323:18:26.469| DEBUG | __main__:<module>:4-thisisa debug message

能够发现,在调用 remove 办法之后,确实将前史 log 删去了。

这样咱们就能够完成日志的改写从头写入操作。

rotation 装备

用了 loguru 咱们还能够十分便利地运用 rotation 装备,比方咱们想一天输出一个日志文件,或许文件太大了主动分隔日志文件,咱们能够直接运用 add 办法的 rotation 参数进行装备。

咱们看看下面的比方:

logger.add('runtime_{time}.log', rotation="500 MB")

经过这样的装备咱们就能够完成每 500MB 存储一个文件,每个 log 文件过大就会新创立一个 log 文件。咱们在装备 log 姓名时加上了一个 time 占位符,这样在生成时能够主动将时刻替换进去,生成一个文件名包括时刻的 log 文件。

别的咱们也能够运用 rotation 参数完成守时创立 log 文件,例如:

logger.add('runtime_{time}.log', rotation='00:00')

这样就能够完成每天 0 点新创立一个 log 文件输出了。

别的咱们也能够装备 log 文件的循环时刻,比方每隔一周创立一个 log 文件,写法如下:

logger.add('runtime_{time}.log', rotation='1 week')

这样咱们就能够完成一周创立一个 log 文件了。

retention 装备

许多状况下,一些十分长远的 log 对咱们来说并没有什么用处了,它白白占有了一些存储空间,不清除去就会十分糟蹋。retention 这个参数能够装备日志的最长保存时刻。

比方咱们想要设置日志文件最长保存 10 天,能够这么来装备:

logger.add('runtime.log', retention='10 days')

这样 log 文件里边就会保存最新 10 天的 log,妈妈再也不必忧虑 log 堆积的问题啦。

compression 装备

loguru 还能够装备对立文件的紧缩格局,比方运用 zip 文件格局保存,示例如下:

l葡萄胎,Python 中更典雅的日志记载方案,宝鉴ogger.add('runtime.log', compression='zip')

这样能够愈加节约存储空间。

字符串格局化

loguru 在输出 log 的时分还供给了十分友爱的字符串格局化功用,像这样:

logger.info('If you are using Python {}, prefer {feature} of course!', 3.6, feature='f-strings')

这样在增加参数就十分便利了。

Traceback 记载

在许多状况下,假如遇到运转过错,而咱们在打印输出 log 的时分如果不小心没有装备好 Traceback 的输出,很有或许咱们就无法追寻过错地点了。

但用了 loguru 之后,咱们用它供给的装修器就能够直接进行 Traceback 的记载,相似这样的装备即可:

@logger.catchdef my_function(x, y, z): # An error? It's caught anyway! return 1 / (x + y + z)

咱们做个测验,咱们在调用时三个参数都传入 0,直接引发除以 0 的过错,看看会呈现什么状况:

my_function(0,0,0)

运转结束之后,能够发现 log 里边就呈现了 Traceback 信息,并且给咱们输出了其时的变量值,真的是不能再赞了!成果如下:

> File"run.py", line15,in my_function(0,0,0) └ <functionmy_function at0x1171dd510>
File"/private/var/py/logurutest/demo5.py", line13,inmy_function return1/ (x + y + z) │ │ └ 0 │ └ 00
ZeroDivisionError: divisionbyzero

因而,用 loguru 能够十分便利地完成日志追寻,debug 功率或许要高上十倍了?

别的 loguru 还有许多许多强壮的功用,这儿就不再逐个打开讲解了,更多的内容我们能够看看 loguru 的官方文档具体了解一下:https://loguru.readthe高中作文docs.io/en/stable/index.html。

看完之后,是时分把自己的 logging 模块替换成 loguru 啦!

题图:pexels,CC0 授权。