赞
踩
logging模板块是Python的一个内置标准库,用于实现对日志的控制输出,对于日常的日志输出,甚至是系统级的日志输出,也均可以使用logging模块来进行实现。日志信息默认输出到sys.stdout输出流,更换输出流后需要重新指定日志的输出流!
logging.basicConfig:用于对logging模块整个日志输出的一次性配置,也就是说屡次配置时以第一次配置的为准,以后再使用basicConfig进行配置则无效。实例:
- # -*- coding:utf-8 -*-
- import logging
- import datetime
-
- # filename:设置日志输出文件,以天为单位输出到不一样的日志文件,以避免单个日志文件日志信息过多,
- # 日志文件若是不存在则会自动建立,但前面的路径如log文件夹必须存在,不然会报错
- log_file = 'log/sys_%s.log' % datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d')
- # level:设置日志输出的最低级别,即低于此级别的日志都不会输出
- # 在平时开发测试的时候能够设置成logging.debug以便定位问题,但正式上线后建议设置为logging.WARNING,既能够下降系统I/O的负荷,也能够避免输出过多的无用日志信息
- log_level = logging.WARNING
- # format:设置日志的字符串输出格式
- log_format = '%(asctime)s[%(levelname)s]: %(message)s'
- logging.basicConfig(filename=log_file, level=logging.WARNING, format=log_format)
- logger = logging.getLogger()
-
- # 如下日志输出因为level被设置为了logging.WARNING,因此debug和info的日志不会被输出
- logger.debug('This is a debug message!')
- logger.info('This is a info message!')
- logger.warning('This is a warning message!')
- logger.error('This is a error message!')
- 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参数就会被忽略。日志
logging.StreamHandler()和FileHandler():将日志同时输出到文件和控制台
- # -*- coding:utf-8 -*-
- import logging
- import datetime
-
- logger = logging.getLogger()
- # 设置此logger的最低日志级别,以后添加的Handler级别若是低于这个设置,则以这个设置为最低限制
- logger.setLevel(logging.INFO)
-
- # 建立一个FileHandler,将日志输出到文件
- log_file = 'log/sys_%s.log' % datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d')
- file_handler = logging.FileHandler(log_file)
- # 设置此Handler的最低日志级别
- file_handler.setLevel(logging.WARNING)
- # 设置此Handler的日志输出字符串格式
- log_formatter = logging.Formatter('%(asctime)s[%(levelname)s]: %(message)s')
- file_handler.setFormatter(log_formatter)
-
- # 建立一个StreamHandler,将日志输出到Stream,默认输出到sys.stderr
- stream_handler = logging.StreamHandler()
- stream_handler.setLevel(logging.INFO)
-
- # 将不一样的Handler添加到logger中,日志就会同时输出到不一样的Handler控制的输出中
- # 注意若是此logger在以前使用basicConfig进行基础配置,由于basicConfig会自动建立一个Handler,因此此logger将会有3个Handler
- # 会将日志同时输出到3个Handler控制的输出中
- logger.addHandler(file_handler)
- 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: 将日志发送到一个指定的邮件地址。
最低级别:logger.setLevel为设置logger的最低日志级别,若是handler中也设置了级别,则不能低于这个级别,低于这个级别的设置是无效的。
不一样级别的意义:在开发或者部署应用程序时,须要尽量详尽的信息来进行开发和调试,这时候用的比较多的是来自DEBUG和INFO级别的日志信息,可是到了正式上线或者生产环境时,应该使用WARNING和CRITICAL级别的日志信息以下降机器的I/O压力和提升获取到错误信息的效率。
日志量:日志的信息量应该是与日志级别成反比的:DEBUG>INFO>WARNING>ERROR>CRITICAL。
- >>> from loguru import logger
- >>> logger.add('out.log')
- 1
- >>> logger.info('hello world')
- 2022-03-01 20:42:22.011 | INFO | __main__:<module>:1 - hello world
- >>> with open('out.log') as f:
- ... print(f.read())
- ...
- 2022-03-01 20:42:22.011 | INFO | __main__:<module>:1 - hello world
- >>> import sys
- >>> from loguru import logger
- >>> logger.remove()
- >>> logger.add(sys.stdout, format='{time} {level} {message}')
- 1
- >>> logger.info('hello world')
- 2022-03-01T21:26:46.850506+0800 INFO hello world
- import sys
- from loguru import logger
- logger.remove()
- logger.add(sys.stdout, level='INFO', format='{message}')
- logger.add('output.log', level='INFO', format='{message}')
- logger.info('hello world')
- #1 输出流
- import sys
- f = open('a.log', 'a')
- sys.stdout = f
- sys.stderr = f
-
- #2 tee
- python a_script.py 2>&1 | tee a.log
-
- #3 自定义logger
- import sys
- class Logger(object):
- def __init__(self, filename='default.log', stream=sys.stdout):
- self.terminal = stream
- self.log = open(filename, 'a')
-
- def write(self, message):
- self.terminal.write(message)
- self.log.write(message)
- self.log.flush() #即时将缓存区数据导出
-
- def flush(self):
- pass
-
- sys.stdout = Logger(a.log, sys.stdout)
- sys.stderr = Logger(a.log_file, sys.stderr) # redirect std err, if necessary
在问题1切换输出流后导致日志不能输出
- #问题1中的自定义logger
- sys.stdout = Logger('a.log', sys.stdout)
- sys.stderr = Logger('a.log', sys.stderr)
-
- #将logging的stream指定为新的sys.stdout
- logging.basicConfig(stream=sys.stdout, level = logging.INFO, format='%(asctime)s-%(levelname)s-%(message)s')
- #之后可以正常调用logger
pycharm中或者更换了新的输出流后,换行了,说明此处self._dynamic_display
为False
- self._dynamic_display = ((hasattr(sys.stdout, 'isatty') and
- sys.stdout.isatty()) or
- 'ipykernel' in sys.modules)
_dynamic_display为True有两种条件
第一种是检测当前输出是否在终端上,第二种是当前导入的包里有没有ipykernel
而pycharm中直接运行的脚本,sys.stdout.isatty()为False,故我们需要满足另一个条件,才能进入正确的分支。
于是只要在代码中 import ipykernel
就可以解决
http://www.javashuo.com/article/p-ytorvmmq-c.html
【Python】将控制台输出保存至文件(loguru)_Xavier Jiezou的博客-CSDN博客_loguru 文件
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。