Python基础之日志标准库logging

1、日志基础知识

1.1 日志是什么

日志(logging)是一种可追踪(track)某些软件运行时所发生事件的方法。软件开发人员可在他们代码中调用日志记录相关方法来表明发生了某些事件。通过一个描述性的消息来描述这个事件,该消息能够可选地包含可变数据。而事件有重要性概念,重要性被称为严重级别(level)。

1.2 日志的作用

通过记录和分析日志可以了解一个系统或软件程序运行情况是否正常,也可以在应用程序出现故障时快速定位问题。

1.3 日志级别

DEBUG # 调试

INFO # 通知

WARN # 警告

ERROR # 错误

1.4 日志的内容

一条日志信息对应的是一个事件的发生,通常包括以下内容:

1.发生时间

2.发生位置

3.严重程度

4.内容

2、 logging基础介绍

logging模块提供了在项目出现故障时根据运行时产生的日志快速定位问题出现位置的功能

2.1 logging库日志级别

DEBUG--INFO--WARNING--ERROR--CRITICAL

开发应用程序或部署开发环境时,应该使用DEBUG或INFO级别的日志获取尽可能详细的日志信息来进行开发或者部署测试

应用上线或者部署生产环境时:应该使用WARNING或CRITICAL级别的日志来降低机器I/O压力和提高获取错误日志信息的效率

注意:当为某个应用程序指定一个日志级别后,应用程序会记录所有日志级别大于或等于指定日志级别的日志信息,而不是仅仅记录指定级别的日志信息,只要级别大于或等于该指定日志级别的日志记录才会被输出,小于该级别日志记录将会被丢弃。

2.1 logging工作流程

Logger:日志,暴露函数给应用程序,基于日志记录器和过滤器级别决定哪些日志有效

LogRecord:日志记录器,将日志传到相应的处理器处理

Handler:处理器,将(日志记录器产生的)日志记录发送到合适的目的地

Filter:过滤器,提供了更好的粒度控制,它可以决定输出哪些日志记录

Formatter:格式化器,指明了最终输出中日志记录的布局

流程描述:

1.判断日志的级别是否大于Logger对象的等级,如果大于,则往下执行,否则流程结束。

2.产生日志:第一步,判断是否有异常,如果有,则添加异常信息。第二步,处理日志记录额方法(如debug,info等)中的占位符,即一般字符的字符串格式化处理

3.使用注册到Logger对象中的Filers进行过滤,如果有多个过滤器,则一次过滤,只要有一个过滤器返回假,则过滤结束,且该日志信息将丢弃,不再处理,而处理流程也至此结束,否则,处理流程往下执行。

4.在当前Logger对象中查找Handlers,如果查找不到任何Handler,则往上到该Logger对象的父Logger中查找;如果找到一个或多个Handler,则依次用Handler来处理日志信息。但每个Handler处理日志信息的过程中,会首先判断日志信息的等级是否大于该Handler的等级,如果大于,则往下继续执行(由Logger对象进入Handler对象中),否则,处理流程结束。

5.执行Handler对象中的filter方法,该方法会一次执行注册到该Handler对象中的Filter。如果由一个Filter判断该日志信息为假,则此后所有Filter都不再执行,而直接将该日志信息丢弃,处理流程结束。

6.使用Formatter类格式化最终的输出结果。注:Formatter同上述第2步的字符串格式不同,它会添加额外的信息,比如日志产生的时间,产生日志的源代码所在源文件的路径等。

7.真正的输出日志信息(到网络、文件、终端、邮件等)至于输出到那个目的地,由Handler的种类来决定

2.3 日志输出格式

日志输出格式可以设置

默认格式:日志级别:Logger实例名称:日志消息内容

2.4 基本使用

loggering使用非常简单,使用basicConfig()方法就可以满足基本使用,如果方法没有传入参数,会根据默认的配置创建Logger对象,默认的日志级别设置为WARNING,默认的日志输出格式如上,该函数可选参数如下:

filename  # 日志输出到文件的文件名

filemode  # 文件模式,r,w,a

format  # 文件输出格式

datefat  # 日志附带日期时间的格式

style  # 格式占位符默认为%和{}

level  # 设置日志输出级别

stream  # 定义输出流,来初始化StreamHandler对象,不能filename参数一起使用,否则ValueError异常

handlers  # 定义处理器,用来创建Handler对象,不能和filename、stream参数一起使用,否则也会抛出ValueError异常

2.5 代码实战

使用baseconfig()指定日志输出级别

logging.basicConfig(level=logging.DEBUG)

logging.debug('This is debug log')  # 调试级别
logging.info('This is info log')  # 信息级别
logging.warning('This is warning log')  # 警告级别
logging.error('This is error log')  # 错误级别
logging.critical('This is critical log')  # 严重错误级别

输出到日志文件

import logging


logging.basicConfig(level=logging.DEBUG, filename='test.log')

logging.debug('This is debug log')  # 调试级别
logging.info('This is info log')  # 信息级别
logging.warning('This is warning log')  # 警告级别
logging.error('This is error log')  # 错误级别
logging.critical('This is critical log')  # 严重错误级别

注意:默认情况下再执行程序会换行追加,如果想要每次执行程序,先清空文件,然后输出日志到文件中,只需要新增一个属性filemode='w'文件模式(先清空再写入)

logging.basicConfig(level=logging.DEBUG, filename='test.log', filemode='w')

输出对象 

import logging


logging.basicConfig(level=logging.DEBUG, filename='test.log', filemode='w')
name = '张三'
age = 18
logging.debug('姓名是:%s, 年龄是:%s', name, age)  # 调试级别
logging.info('姓名是:%s, 年龄是:%s' % (name, age))  # 信息级别
logging.warning('姓名是:{}, 年龄是:{}'.format(name, age))  # 警告级别
logging.error(f'姓名是:{name}, 年龄是:{age}')  # 错误级别
logging.critical('This is critical log')  # 严重错误级别

添加重要信息

asctime:当前时间

levelname:输出日志级别

filename:文件名称

lineno:报错文件行号

message:输出信息

import logging


logging.basicConfig(level=logging.DEBUG, filename='test.log', filemode='w',
                    format='%(asctime)s %(name)s:%(levelname)s:%(message)s|%(filename)s:%(lineno)s',
                    datefmt='%Y-%m-%d %H:%M:%S')
name = '张三'
age = 18
logging.debug('姓名是:%s, 年龄是:%s', name, age)  # 调试级别
logging.info('姓名是:%s, 年龄是:%s' % (name, age))  # 信息级别
logging.warning('姓名是:{}, 年龄是:{}'.format(name, age))  # 警告级别
logging.error(f'姓名是:{name}, 年龄是:{age}')  # 错误级别
logging.critical('This is critical log')  # 严重错误级别

3、logging高级应用

logging模块采用了模块化设计,主要包含四种组件

Loggers  # 记录器,提供应用陈鼓写代码直接使用接口

Handlers  # 处理器,将记录器产生的日志文件发送到目的地

Filters  # 过滤器,提供更好的力粒度控制,决定哪些日志会被输出

Formatters  # 格式化器,设置日志内容的组成结构和消息字段

3.1 loggers记录器

1.提供应用程序的调用接口(logger是单例的)

logger = logging.getLogger(__name__)

2.决定日志记录的级别

logger.setLevel()

3.将日志内容传递到相关关联的handlers中

logger.addHandler()和logger.removeHandler()

3.2 Handlers处理器

它们将日志分发到不同的目的地:文件、标准输出、邮件、或者通过socke、http等协议发送到任何地方

SreamHandler:标准输出stdout(如显示器)分发器

sh = loggering.StreamHandler(stream=None)

FileHanlder:将日志保存到磁盘文件的处理器

fh = logging.FileHandler(filename, mode='a', encoding=None, delay=False)

setFormatter():设置当前handler对象使用的消息格式

3.3 Formatters格式

Formatter对象用来最终设置日志信息的顺序、结构、内容

ft = logging.Formatter.__init__(fmt=None,datefmt=None,style='%')

datefmt默认格式为:%Y-%m-%d %H:%M:%S;style参数默认%,这表示%(<dictionary key>)s格式的字符串

asctime  %(asctime)s  # 日志产生时间

created  %(created)f  # time.time()生成的日志创建时间戳

filename  %(filename)s #  生成日志的程序名

funcName  %(funcName)s  # 调用日志的函数名

levelname  %(levelname)s  # 日志级别

levelno  %(levelno)  # 日志级别对应数值

lineno  %(lineno)s  # 日志所针对的代码行数

module  %(module)s  # 生成日志模块名

msecs  %(msecs)d  # 日志生成时间的毫秒部分

message  %(message)s  # 具体日志信息

name  %(name)s  # 日志调用者

pathname  %(pathname)s  # 生成日志完整路径

processName  %(processName)s  # 进程名

thred  %(thred)d  # 生成日志的线程id

process  %(process)d  # 生成日志的进程id

thredName  %(thredName)s  # 线程名

4、高级用法实战

4.1 记录器


logger = logging.getLogger()
print(logger)  # 默认情况级别:warning
print(type(logger))

修改为指定级别


logger = logging.getLogger('applog')
logger.setLevel(logging.DEBUG)
print(logger) 
print(type(logger))

 4.2 处理器、过滤器

# 记录器
logger = logging.getLogger('app.log')
logger.setLevel(logging.DEBUG)

# 普通处理器定义
consoleHandler = logging.StreamHandler()
consoleHandler.setLevel(logging.DEBUG)
# 写入文件处理器定义
fileHandler = logging.FileHandler(filename='test.log')
fileHandler.setLevel(logging.INFO)
# 设置formatter格式
formatter = logging.Formatter('%(asctime)s %(name)s:%(levelname)s:%(message)s|%(filename)s:%(lineno)s')
# 处理器设置格式
consoleHandler.setFormatter(formatter)
fileHandler.setFormatter(formatter)
# 记录器要设置处理器
logger.addHandler(consoleHandler)
logger.addHandler(fileHandler)

ft = logging.Filter('app.log')  # 定义过滤器
logger.addFilter(ft)




# 打印日志代码
logger.debug('This is debug log')
logger.info('This is info log')
logger.warning('This is warning log')
logger.error('This is error log')
logger.critical('This is critical log')

4.3 配置文件定义

[loggers]
keys=root,applog

[handlers]
keys=fileHandler,consoleHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=DEBUG
handlers=consoleHandler

[logger_applog]
level=DEBUG
handlers=fileHandler,consoleHandler
qualname=applog
propagate=0


[handler_consoleHandler]
class=StreamHandler
args=(sys.stdout,)
level=DEBUG
formatter = simpleFormatter

[handler_fileHandler]
class=handlers.TimedRotatingFileHandler
args=("applog.log","midnight",1,0,'utf-8')
level=DEBUG
formatter = simpleFormatter

[formatter_simpleFormatter]
format=%(asctime)s|%(levelname)8s|%(name)s:%(lineno)s|%(message)s|%(processName)s
datafm=%Y-%m-%d %H:%M:%S
import logging.config


# 使用配置文件的方式处理日志
logging.config.fileConfig('logging.conf')

rootLogger = logging.getLogger()
rootLogger.debug('This is root Logger, debug')

# 记录器
logger = logging.getLogger('applog')
# 打印日志的代码
logger.debug('This is debug log, dbug')

# 设置报错将str转换成int
try:
    int(input('请输入一个数字:'))
except Exception as e:
    logger.exception(e)

猜你喜欢

转载自blog.csdn.net/xiao__dashen/article/details/125324223