小编写这篇文章的主要目的,就是给大家介绍下关于在Python中,有内置的logging,那么,我们在进行使用它的时候,有什么使用方法呢?下面就给大家详细介绍。
logging的主要作用
它的作用是给日志记录的接口和众多处理模块,供用户存储各种格式的日志,帮助调试程序或者记录程序运行过程中的输出信息。
logging日志等级
logging日志等级分为五个等级,优先级从高到低依次是:
**CRITICAL;**程序严重错误
**ERROR;**程序错误/部分功能错误
**WARNING;**程序有发生错误的可能
**INFO;**程序正常运行时的信息
DEBUG程序调试信息
默认的日志的记录等级为WARNING,即当日志的等级大于获等于WARNING时才会被记录。
一般常用的记录等级为INFO,其用于记录程序的正常运行的一些信息(类似于print)。
当日志的等级达到WARNING以上时,表明此时程序不能正常运行;
logging的基础函数
logging.basicConfig(**kwargs)
在没有显式的进行创建记录器(logger)时,会默认创建一个root logger,而logging.basicConfig(**kwargs)可以创建带有默认的Formatter的streamHandle并将其添加到根日志记录器中来初始化基本配置。
比如
import logging logging.debug('Debug code!') logging.info('Run code!') logging.warning('Watch out!') logging.error('This is an error') logging.critical('This is a ciritical')
上面代码中logging并没有显式的创建logger(logging.getLogger),其在直接使用debug(),info(),warning(),error(),critical()时会使用默认的root logger,并会自动调用自定义的或者默认的logging.basicConfig(**kwargs)初始化root logger。
自定义的logging.basicConfig(**kwargs)中的参数有以下的主要的选项:
例如下面通过自定义logging.basicConfig(**kwargs)来初始化root logger来获得DEBUG级别及以上的日志记录并保存到log.txt文件中。
import logging logging.basicConfig(filename='./log.txt', format='%(asctime)s-%(name)s-%(levelname)s-%(message)s-%(funcName)s:%(lineno)d', level=logging.DEBUG) logging.debug('Debug code!') logging.info('Run code!') logging.warning('Watch out!') logging.error('This is an error') logging.critical('This is a ciritical')
logging的四大组件(类)
Logger
除了根记录器(root logger)外,最主要的是可以自己创建日志记录器。
通过模块级别的函数logging.getLogger(name)实例化记录器
默认情况下,记录器采用层级结构,通过.来区分不同的层级。比如有个名叫foo的记录器则foo.a和foo.b都是foo的子级记录器。当然,最开始的或者说最上层的记录器就是root logger。如果name=None,构建的是root logger。
可以直接用当前模块的名称当作记录器的名字logging.getLogger(__name__)
子级记录器通常不需要多带带设置日志级别以及Handler,如果子级记录器没有多带带设置,则它的行为会委托给父级。比如说,记录器foo的级别为INFO,而foo.a和foo.b都不设置日志级别。此时foo.a和foo.b会遵循foo的级别设置,即只记录大于等于INFO级别的日志;而如果foo也没设置的话,就会找到根记录器root logger,root默认的级别为WARGING。
logger类的一些常用的方法
logger结合后面要介绍的其他的三个组件可以实现以下的功能:
Logger需要通过handler将日志信息输出到目标位置,目标位置可以是sys.stdout和文件等(这与logging.basicConfig(**kwargs)设置中不太一致)。
一个Logger可以设置不同的Handler,而不同的Handler可以将日志输出到不同的位置(不同的日志文件),并且每个Handler都可以设置自己的filter从而实现日志过滤,保留实际项目中需要的日志。同时每个Handler也可以设置不同的Formatter,在每个Formatter实现同一条日志以不同的格式输出到不同的地方。
Handle
处理器;其可以控制记录的日志输出到什么地方(标准输出/文件/...),同时处理器也可以添加过滤器(filter)和格式控制器(formatter)来控制输出的内容和输出的格式。
其具有几种常见的处理器:
logging.StreamHandler标准流处理器,将消息发送到标准输出流、错误流-->logging.StreamHandler(sys.stdout)#sys.stdout表示的是指向控制台即标准输出;当我们在Python中打印对象调用print obj时候,事实上是调用了sys.stdout.write(obj+'\n')。
print将你需要的内容打印到了控制台,然后追加了一个换行符
logging.FileHandler文件处理器,将消息发送到文件-->logging.FileHandler(log_path)
logging.RotatingFileHandler文件处理器,文件达到指定大小后,启用新文件存储日志
logging.TimedRotatingFileHandler文件处理器,日志以特定的时间间隔轮换日志文件
handle类的一些常用的方法
Filter
filter组件用来过滤logger对象,一个filter可以直接添加到logger对象上,也可以添加到handler对象上,而如果在logger和handler中都设置了filter,则日志是先通过logger的filter,再通过handler的filter。由于所有的信息都可以经过filter,所以filter不仅可以过滤信息,还可以增加信息。
Filter类的实例化对象可以通过logging.Filter(name)来创建,其中name为记录器的名字,如果没有创建过该名字的记录器,就不会输出任何日志:
filter=logging.Filter("foo.a")
基本过滤器类只允许低于指定的日志记录器层级结构中低于特定层级的事件,例如这个用foo.a初始化的过滤器,则foo.a.b;foo.a.c等日志记录器记录的日志都可以通过过滤器,而foo.c;a.foo等就不能通过。如果name为空字符串,则所有的日志都能通过。
Filter类有三个方法:
addFilter(filter):为logger(logger..addFilter(filter))或者handler(handler..addFilter(filter))增加过滤器
removeFilter(filter):为logger或者handler删除一个过滤器
filter(record):表示是否要记录指定的记录?返回零表示否,非零表示是。一般自定义Filter需要继承Filter基类,并重写filter方法
Formatter
格式化日志的输出;实例化:formatter=logging.Formatter(fmt=None,datefmt=None);如果不指明fmt,将默认使用‘%(message)s’,如果不指明datefmt,将默认使用ISO8601日期格式。
其中fmt参数有以下选项:
例如:
formatter=logging.Formatter('%(asctime)s%(levelname)-8s:%(message)s')#-表示右对齐8表示取8位 handler.formatter=formatter
datefmt参数有以下选项:
例如:
formatter=logging.Formatter('%(asctime)s%(levelname)-8s:%(message)s')#-表示右对齐8表示取8位
handler.formatter=formatter
datefmt参数有以下选项:
例子:
formatter=logging.Formatter("%(asctime)s%(levelname)s%(message)s","%Y%m%d-%H:%M:%S") handler.formatter=formatter
logging的配置
conf形式的配置
在loguser.conf中写入相关的信息
[loggers] keys=root,fileLogger,rotatingFileLogger [handlers] keys=consoleHandler,fileHandler,rotatingFileHandler [formatters] keys=simpleFormatter [logger_root] level=INFO handlers=consoleHandler [logger_fileLogger] level=INFO handlers=fileHandler qualname=fileLogger propagate=0 [logger_rotatingFileLogger] level=INFO handlers=consoleHandler,rotatingFileHandler qualname=rotatingFileLogger propagate=0 [handler_consoleHandler] class=StreamHandler level=INFO formatter=simpleFormatter args=(sys.stdout,) [handler_fileHandler] class=FileHandler level=INFO formatter=simpleFormatter args=("logs/fileHandler_test.log","a") [handler_rotatingFileHandler] class=handlers.RotatingFileHandler level=WARNING formatter=simpleFormatter args=("logs/rotatingFileHandler.log","a",10*1024*1024,50) [formatter_simpleFormatter] format=%(asctime)s-%(module)s-%(levelname)s-%(thread)d:%(message)s datefmt=%Y-%m-%d%H:%M:%S
在使用logger时,直接导入配置文件即可
from logging import config with open('./loguser.conf','r',encoding='utf-8')as f: ##加载配置 config.fileConfig(f) ##创建同名Logger,其按照配置文件的handle,formatter,filter方法初始化 logger=logging.getLogger(name="fileLogger")
yaml形式配置文件
在loguser.yaml文件中配置相关信息 version:1 disable_existing_loggers:False #formatters配置了日志输出时的样式 #formatters定义了一组formatID,有不同的格式; formatters: brief: format:"%(asctime)s-%(message)s" simple: format:"%(asctime)s-[%(name)s]-[%(levelname)s]:%(levelno)s:%(message)s" datefmt:'%F%T' #handlers配置了需要处理的日志信息,logging模块的handler只有streamhandler和filehandler handlers: console: class:logging.StreamHandler formatter:brief level:DEBUG stream:ext://sys.stdout info_file_handler: class:logging.FileHandler formatter:simple level:ERROR filename:./logs/debug_test.log error_file_handler: class:logging.handlers.RotatingFileHandler level:ERROR formatter:simple filename:./logs/errors.log maxBytes:10485760#10MB#1024*1024*10 backupCount:50 encoding:utf8 loggers: #fileLogger,就是在代码中通过logger=logging.getLogger("fileLogger")来获得该类型的logger my_testyaml: level:DEBUG handlers:[console,info_file_handler,error_file_handler] #root为默认情况下的输出配置,当logging.getLogger("fileLoggername")里面的fileLoggername没有传值的时候, #就是用的这个默认的root,如logging.getLogger(__name__)或logging.getLogger() root: level:DEBUG handlers:[console]
同样的可以通过导入yaml文件加载配置
with open('./loguser.yaml','r',encoding='utf-8')as f: yaml_config=yaml.load(stream=f,Loader=yaml.FullLoader) config.dictConfig(config=yaml_config) root=logging.getLogger() #子记录器的名字与配置文件中loggers字段内的保持一致 #loggers: #my_testyaml: #level:DEBUG #handlers:[console,info_file_handler,error_file_handler] my_testyaml=logging.getLogger("my_testyaml")
logging和print的区别
看起来logging要比print复杂多了,那么为什么推荐在项目中使用logging记录日志而不是使用print输出程序信息呢。
相比与print logging具有以下优点:
可以通过设置不同的日志等级,在release版本中只输出重要信息,而不必显示大量的调试信息;
print将所有信息都输出到标准输出中,严重影响开发者从标准输出中查看其它数据;logging则可以由开发者决定将信息输出到什么地方,以及怎么输出;
和print相比,logging是线程安全的。(python 3中print也是线程安全的了,而python 2中的print不是)(线程安全是指在多线程时程序不会运行混乱;而python 2中的print分两步打印信息,第一打印字符串,第二打印换行符,如果在这中间发生线程切换就会产生输出混乱。这就是为什么python2的print不是原子操作,也就是说其不是线程安全的)印信息,第一打印字符串,第二打印换行符,如果在这中间发生线程切换就会产生输出混乱。这就是为什么python2的print不是原子操作,也就是说其不是线程安全的)
综上所述,具体的详细内容,小编就给大家介绍完毕了,希望可以给大家带来帮助。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/127992.html
摘要:每一条日志记录也包含级别,代表对应消息的严重程度。即格式化器,主要功能是确定最终输出的形式和内容。最好是日志能够按自然天进行记录和分割。 上一章学习了自动化测试,很好,现在我们可以绞尽脑汁写出一份全面的测试,来保证代码永远健康了。 话虽如此,但是作为一个独立开发者很难写出真正全面的测试代码。这是因为用户在使用你的网站时可不会循规蹈矩,而是会以各种怪异的姿势浏览网页、上传数据。但这也不是...
Python的三种主要模块介绍 小编写这篇文章的主要目的,给大家介绍三种主要的模块,包括系统内的几种模块,对其做个具体的介绍,下面就给大家详细的解答下。 在python中,一个文件(以.py为后缀名的文件)就叫做一个模块,每一个模块在python里都被看做是一个独立的文件。 模块可以被项目中的其他模块、一些脚本甚至是交互式的解析器所使用,它可以被其他程序引用,从而使用该模块里的函数等功能...
摘要:尽量使用内置的异常处理语句来替换语句,比如语句,方法。以上是最简单的重新抛出异常的做法,也是推荐的做法。除了包含所有的外还包含了,和三个异常。避免在语句块中干一些没意义的事情,捕获异常也是需要成本的。 异常处理在任何一门编程语言里都是值得关注的一个话题,良好的异常处理可以让你的程序更加健壮,清晰的错误信息更能帮助你快速修复问题。在Python中,和不部分高级语言一样,使用了try/ex...
摘要:下载器负责获取页面,然后将它们交给引擎来处理。内置了一些下载器中间件,这些中间件将在后面介绍。下载器中间件下载器中间件可以在引擎和爬虫之间操纵请求和响应对象。爬虫中间件与下载器中间件类似,启用爬虫中间件需要一个字典来配置。 前段时间我写了一篇《scrapy快速入门》,简单介绍了一点scrapy的知识。最近我的搬瓦工让墙了,而且我又学了一点mongodb的知识,所以这次就来介绍一些scr...
阅读 910·2023-01-14 11:38
阅读 877·2023-01-14 11:04
阅读 739·2023-01-14 10:48
阅读 1980·2023-01-14 10:34
阅读 941·2023-01-14 10:24
阅读 818·2023-01-14 10:18
阅读 498·2023-01-14 10:09
阅读 571·2023-01-14 10:02