当前位置:   article > 正文

Python日志全攻略_python 日志

python 日志

前言


 logging模板块是Python的一个内置标准库,用于实现对日志的控制输出,对于日常的日志输出,甚至是系统级的日志输出,也均可以使用logging模块来进行实现。日志信息默认输出到sys.stdout输出流,更换输出流后需要重新指定日志的输出流!

一、Python内置logging模块


1. 使用basicConfig进行简单的一次性配置服务

logging.basicConfig用于对logging模块整个日志输出的一次性配置,也就是说屡次配置时以第一次配置的为准,以后再使用basicConfig进行配置则无效。实例:

  1. # -*- coding:utf-8 -*-
  2. import logging
  3. import datetime
  4. # filename:设置日志输出文件,以天为单位输出到不一样的日志文件,以避免单个日志文件日志信息过多,
  5. # 日志文件若是不存在则会自动建立,但前面的路径如log文件夹必须存在,不然会报错
  6. log_file = 'log/sys_%s.log' % datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d')
  7. # level:设置日志输出的最低级别,即低于此级别的日志都不会输出
  8. # 在平时开发测试的时候能够设置成logging.debug以便定位问题,但正式上线后建议设置为logging.WARNING,既能够下降系统I/O的负荷,也能够避免输出过多的无用日志信息
  9. log_level = logging.WARNING
  10. # format:设置日志的字符串输出格式
  11. log_format = '%(asctime)s[%(levelname)s]: %(message)s'
  12. logging.basicConfig(filename=log_file, level=logging.WARNING, format=log_format)
  13. logger = logging.getLogger()
  14. # 如下日志输出因为level被设置为了logging.WARNING,因此debug和info的日志不会被输出
  15. logger.debug('This is a debug message!')
  16. logger.info('This is a info message!')
  17. logger.warning('This is a warning message!')
  18. logger.error('This is a error message!')
  19. logger.critical('This is a critical message!')

logging.basicConfig的参数:

filename:设置日志输出的文件,默认输出到控制台。
filemode:设置打开日志文件的方式,默认为“a”,即追加。
format:设置日志输出的字符串格式,具体的格式有以下几种:

  • %(name)s:日志记录器的名称
  • %(levelno)s:日志级别数值
  • %(levelname)s:日志级别名称
  • %(pathname)s:输出日志时当前文件的绝对路径
  • %(filename)s:输出日志时当前文件名(包含后缀)
  • %(module)s:输出日志时的模块名(即%(filename)s不包含后缀名)
  • %(funcName)s:输出日志时所在函数名
  • %(lineno)d:输出日志时在文件中的行号
  • %(asctime)s:输出日志时的时间
  • %(thread)d:输出日志的当前线程ID
  • %(threadName)s:输出日志的当前线程名称
  • %(process)s:输出日志的当前进程ID
  • %(processName)s:输出日志的当前进程名称
  • %(message)s:输出日志的内容

datefmt:设置日志时间字符串的输出格式,默认时间字符串格式为%Y-%m-%d %H:%M:%S。
style:设置format字符串格式化的风格,能够是“%”,“{”或“$”,默认是“%”。
level:设置日志的级别,具体有如下几种(由高到低):调试

  • CRITICAL:致命错误
  • ERROR:严重错误
  • WARNING:须要给出的提示
  • INFO:通常的日志信息
  • DEBUG:在debug过程当中的debug信息

stream:指定日志的输出Stream,能够是sys.stderr,sys.stdout或者是文件(即便用open函数打开的文件流,可是这个文件流logging模块不会主动关闭它),默认是sys.stderr,若是同时指定了filename参数和stream参数,那stream参数就会被忽略。日志

2. 使用Handler将日志同时输出到文件和控制台

logging.StreamHandler()和FileHandler()将日志同时输出到文件控制台

  1. # -*- coding:utf-8 -*-
  2. import logging
  3. import datetime
  4. logger = logging.getLogger()
  5. # 设置此logger的最低日志级别,以后添加的Handler级别若是低于这个设置,则以这个设置为最低限制
  6. logger.setLevel(logging.INFO)
  7. # 建立一个FileHandler,将日志输出到文件
  8. log_file = 'log/sys_%s.log' % datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d')
  9. file_handler = logging.FileHandler(log_file)
  10. # 设置此Handler的最低日志级别
  11. file_handler.setLevel(logging.WARNING)
  12. # 设置此Handler的日志输出字符串格式
  13. log_formatter = logging.Formatter('%(asctime)s[%(levelname)s]: %(message)s')
  14. file_handler.setFormatter(log_formatter)
  15. # 建立一个StreamHandler,将日志输出到Stream,默认输出到sys.stderr
  16. stream_handler = logging.StreamHandler()
  17. stream_handler.setLevel(logging.INFO)
  18. # 将不一样的Handler添加到logger中,日志就会同时输出到不一样的Handler控制的输出中
  19. # 注意若是此logger在以前使用basicConfig进行基础配置,由于basicConfig会自动建立一个Handler,因此此logger将会有3个Handler
  20. # 会将日志同时输出到3个Handler控制的输出中
  21. logger.addHandler(file_handler)
  22. logger.addHandler(stream_handler)

经过给logger添加不一样的Handler,能够将日志同时输出到不一样的地方,须要注意的是使用basicConfig进行一次性基础配置时,会根据配置内容自动建立一个Handler,因此若是以后再添加了N个Handler,实际上总的Handler数量有N+1个。

通常在logging或者logging.handlers下就能够你想要的Handler,不一样的Handler会以不一样的方式输出到不一样的地方,如下是几种经常使用的Handler:

from logging import FileHandler: 以“a”(追加)的方式将日志输出到文件,若是文件不存在,则自动建立该文件。
from logging import StreamHandler: 将日志输出到Stream,好比sys.stderr、sys.stdour、文件流等。
from logging.handlers import RotatingFileHandler: 将日志输出到文件,能够经过设置文件大小,文件达到上限后自动建立一个新的文件来继续输出文件。
from logging.handlers import TimedRotatingFileHandler: 将日志输出到文件,能够经过设置时间,使日志根据不一样的时间自动建立并输出到不一样的文件中。
from logging.handlers import HTTPHandler: 将日志发送到一个HTTP服务器。
from logging.handlers import SMTPHandler: 将日志发送到一个指定的邮件地址。

3. 使用不一样的日志级别输出日志

最低级别:logger.setLevel为设置logger的最低日志级别,若是handler中也设置了级别,则不能低于这个级别,低于这个级别的设置是无效的。

不一样级别的意义:在开发或者部署应用程序时,须要尽量详尽的信息来进行开发和调试,这时候用的比较多的是来自DEBUG和INFO级别的日志信息,可是到了正式上线或者生产环境时,应该使用WARNING和CRITICAL级别的日志信息以下降机器的I/O压力和提升获取到错误信息的效率。

日志量:日志的信息量应该是与日志级别成反比的:DEBUG>INFO>WARNING>ERROR>CRITICAL。

二、loguru库


1. 将日志信息输出到控制台的同时保存至本地文件

  1. >>> from loguru import logger
  2. >>> logger.add('out.log')
  3. 1
  4. >>> logger.info('hello world')
  5. 2022-03-01 20:42:22.011 | INFO | __main__:<module>:1 - hello world
  6. >>> with open('out.log') as f:
  7. ... print(f.read())
  8. ...
  9. 2022-03-01 20:42:22.011 | INFO | __main__:<module>:1 - hello world

2. 更改日志信息格式

  1. >>> import sys
  2. >>> from loguru import logger
  3. >>> logger.remove()
  4. >>> logger.add(sys.stdout, format='{time} {level} {message}')
  5. 1
  6. >>> logger.info('hello world')
  7. 2022-03-01T21:26:46.850506+0800 INFO hello world

3. 通用框架

  1. import sys
  2. from loguru import logger
  3. logger.remove()
  4. logger.add(sys.stdout, level='INFO', format='{message}')
  5. logger.add('output.log', level='INFO', format='{message}')
  6. logger.info('hello world')

三、nb_log库

GitHub - ydf0509/nb_log: pip install nb_log 各种日志handler和自动转化项目的任意print的效果。日志自动彩色炫酷,可点击控制台的日志自动精确跳转到pycharm的文件和行号。文件日志多进程切割安全。在10个最重要方面全方位超过loguru

问题


1. 将控制台输出保存到文件 (更换输出流)

  • 重定向标准输出流,但不会再控制台输出
  • 使用tee命令重定向,但是控制台信息断断续续
  • 自定义logger,显示正常
  1. #1 输出流
  2. import sys
  3. f = open('a.log', 'a')
  4. sys.stdout = f
  5. sys.stderr = f
  6. #2 tee
  7. python a_script.py 2>&1 | tee a.log
  8. #3 自定义logger
  9. import sys
  10. class Logger(object):
  11. def __init__(self, filename='default.log', stream=sys.stdout):
  12. self.terminal = stream
  13. self.log = open(filename, 'a')
  14. def write(self, message):
  15. self.terminal.write(message)
  16. self.log.write(message)
  17. self.log.flush() #即时将缓存区数据导出
  18. def flush(self):
  19. pass
  20. sys.stdout = Logger(a.log, sys.stdout)
  21. sys.stderr = Logger(a.log_file, sys.stderr) # redirect std err, if necessary

2. 将日志信息添加到新的输出流

在问题1切换输出流后导致日志不能输出

  1. #问题1中的自定义logger
  2. sys.stdout = Logger('a.log', sys.stdout)
  3. sys.stderr = Logger('a.log', sys.stderr)
  4. #将logging的stream指定为新的sys.stdout
  5. logging.basicConfig(stream=sys.stdout, level = logging.INFO, format='%(asctime)s-%(levelname)s-%(message)s')
  6. #之后可以正常调用logger

3. tf.Keras训练进度条在多行输出

 pycharm中或者更换了新的输出流后,换行了,说明此处self._dynamic_displayFalse

  1. self._dynamic_display = ((hasattr(sys.stdout, 'isatty') and
  2. sys.stdout.isatty()) or
  3. 'ipykernel' in sys.modules)

_dynamic_display为True有两种条件

  • hasattr(sys.stdout, ‘isatty’) and sys.stdout.isatty()
  • ‘ipykernel’ in sys.modules

第一种是检测当前输出是否在终端上,第二种是当前导入的包里有没有ipykernel
而pycharm中直接运行的脚本,sys.stdout.isatty()为False,故我们需要满足另一个条件,才能进入正确的分支。
于是只要在代码中 import ipykernel 就可以解决

References


http://www.javashuo.com/article/p-ytorvmmq-c.html

【Python】将控制台输出保存至文件(loguru)_Xavier Jiezou的博客-CSDN博客_loguru 文件

python将控制台输出保存至文件_KFXW的博客-CSDN博客_python输出结果存到文件

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/810480
推荐阅读
相关标签
  

闽ICP备14008679号