一、日志相关概念
日志是一种可以追踪某些软件运行时所发生事件的方法。软件开发人员可以向他们的代码中调用日志记录相关的方法来表明发生了某些事情。一个事件可以用一个可包含可选变量数据的消息来描述。此外,事件也有重要性的概念,这个重要性也可以被称为严重性级别(level)。
1.日志的作用
通过log的分析,可以方便用户了解系统或软件、应用的运行情况;如果你的应用log足够丰富,也可以分析以往用户的操作行为、类型喜好、地域分布或其他更多信息;如果一个应用的log同时也分了多个级别,那么可以很轻易地分析得到该应用的健康状况,及时发现问题并快速定位、解决问题,补救损失。
简单来讲就是,我们通过记录和分析日志可以了解一个系统或软件程序运行情况是否正常,也可以在应用程序出现故障时快速定位问题。比如,做运维的同学,在接收到报警或各种问题反馈后,进行问题排查时通常都会先去看各种日志,大部分问题都可以在日志中找到答案。再比如,做开发的同学,可以通过IDE控制台上输出的各种日志进行程序调试。对于运维老司机或者有经验的开发人员,可以快速的通过日志定位到问题的根源。可见,日志的重要性不可小觑。日志的作用可以简单总结为以下3点:
程序调试
了解软件程序运行情况,是否正常
软件程序运行故障分析与问题定位
如果应用的日志信息足够详细和丰富,还可以用来做用户行为分析,如:分析用户的操作行为、类型好、地域分布以及其它更多的信息,由此可以实现改进业务、提高商业利益。
2.日志的等级
我们先来思考下下面的两个问题:
作为开发人员,在开发一个应用程序时需要什么日志信息?在应用程序正式上线后需要什么日志信息?
作为应用运维人员,在部署开发环境时需要什么日志信息?在部署生产环境时需要什么日志信息?
在软件开发阶段或部署开发环境时,为了尽可能详细的查看应用程序的运行状态来保证上线后的稳定性,我们可能需要把该应用程序所有的运行日志全部记录下来进行分析,这是非常耗费机器性能的。当应用程序正式发布或在生产环境部署应用程序时,我们通常只需要记录应用程序的异常信息、错误信息等,这样既可以减小服务器的I/O压力,也可以避免我们在排查故障时被淹没在日志的海洋里。那么,怎样才能在不改动应用程序代码的情况下实现在不同的环境记录不同详细程度的日志呢?这就是日志等级的作用了,我们通过配置文件指定我们需要的日志等级就可以了。
不同的应用程序所定义的日志等级可能会有所差别,分的详细点的会包含以下几个等级:
DEBUG
INFO
NOTICE
WARNING
ERROR
3.日志功能的实现
几乎所有开发语言都会内置日志相关功能,或者会有比较优秀的第三方库来提供日志操作功能,比如:java的log4j。它们功能强大、使用简单。Python自身也提供了一个用于记录日志的标准库模块--logging。
二、logging模块简介
logging模块定义的函数和类为应用程序和库的开发实现了一个灵活的事件日志系统。logging模块是Python的一个标准库模块,由标准库模块提供日志记录API的关键好处是所有Python模块都可以使用这个日志记录功能。所以,你的应用日志可以将你自己的日志信息与来自第三方模块的信息整合起来。
1. logging模块的日志级别
logging模块默认定义了以下几个日志等级,它允许开发人员自定义其他日志级别,但是这是不被推荐的,尤其是在开发供别人使用的库时,因为这会导致日志级别的混乱。
日志等级(level) | 描述 |
DEBUG | 最详细的日志信息,典型应用场景是 问题诊断 |
INFO | 信息详细程度仅次于DEBUG,通常只记录关键节点信息,用于确认一切都是按照我们预期的那样进行工作 |
WARNING | 当某些不期望的事情发生时记录的信息(如,磁盘可用空间较低),但是此时应用程序还是正常运行的 |
ERROR | 由于一个更严重的问题导致某些功能不能正常运行时记录的信息 |
CRITICAL | 当发生严重错误,导致应用程序不能继续运行时记录的信息 |
示例:
import logging
# 将信息打印到控制台上
logging.debug("Python UI自动化测试")
logging.info("Python 全栈自动化测试")
logging.warning("Python 全栈自动化测试")
logging.error("Python 全栈自动化测试")
logging.critical("Python 全栈自动化测试")复制
上面可以看到只有后面三个能打印出来
默认生成的root logger的level是logging.WARNING,低于该级别的就不输出了
logging的等级依次为:
CRITICAL > ERROR > WARNING > INFO > DEBUG
等级 | 描述 |
debug | 打印全部的日志,详细的信息,通常只出现在诊断问题上 |
info | 打印info,warning,error,critical级别的日志,确认一切按预期运行 |
warning | 打印warning,error,critical级别的日志,一个迹象表明,一些意想不到的事情发生了,或表明一些问题在不久的将来(例如。磁盘空间低”),这个软件还能按预期工作 |
error | 打印error,critical级别的日志,更严重的问题,软件没能执行一些功能 |
critical | 打印critical级别,一个严重的错误,这表明程序本身可能无法继续运行 |
这时候,如果需要显示低于WARNING级别的内容,可以引入NOTSET级别来显示:
import logging
# 引入logging模块
logging.basicConfig(level=logging.NOTSET)
# 设置日志级别 logging.debug(u"如果设置了日志级别为NOTSET,那么这里可以采取debug、info的级别的内容也可以显示在控制台上了")
# 将信息打印到控制台上
logging.debug("Python UI自动化测试")
logging.info("Python 全栈自动化测试")
logging.warning("Python 全栈自动化测试")
logging.error("Python 全栈自动化测试")
logging.critical("Python 全栈自动化测试")复制
2、部分名词解释
Logging.Formatter:这个类配置了日志的格式,在里面自定义设置日期和时间,输出日志的时候将会按照设置的格式显示内容。(是logging中的四大組件之一,日志格式器)
Logging.Logger:Logger是Logging模块的主体,进行以下三项工作:
1. 为程序提供记录日志的接口
2. 判断日志所处级别,并判断是否要过滤
3. 根据其日志级别将该条日志分发给不同handler
常用函数有:
Logger.setLevel() 设置日志级别
Logger.addHandler() 和 Logger.removeHandler() 添加和删除一个Handler
Logger.addFilter() 添加一个Filter,过滤作用
Logging.Handler:Handler基于日志级别对日志进行分发,如设置为WARNING级别的Handler只会处理WARNING及以上级别的日志。
常用函数有:
setLevel() 设置级别
setFormatter() 设置Formatter(日志格式器)
3、在控制台中进行日志输出
import logging # 引入logging模块
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s') # logging.basicConfig函数对日志的输出格式及方式做相关配置
logging.debug("Python UI自动化测试")
logging.info("Python 全栈自动化测试")
logging.warning("Python 全栈自动化测试")
logging.error("Python 全栈自动化测试")
logging.critical("Python 全栈自动化测试")复制
由于日志基本配置中级别设置为DEBUG,所以打印信息将会全部显示在控制台上
4、日志输出-文件
第一步,创建一个logger实例
import logging # 引入logging模块
import os.path
import datetime
logger = logging.getLogger()
logger.setLevel(logging.DEBUG) # Log等级总开关复制
第二步,创建一个日志处理器(Handler)
# 定义日志文件名称、使用时间进行区分不同阶段的日志文件存储
logfile = os.path.join(r'F:\demo\interface\logs',datetime.datetime.now().strftime("%Y-%m-%d") + ".log")
fh = logging.FileHandler(logfile, mode='w')
fh.setLevel(logging.DEBUG) # 输出到file的log等级的开关复制
先运行下是否正常、没有报错就什么配置正常、进行去对应的存放目录下查看会生成一个日志文件
第三步,进行使用格式器定义具体的日志格式
formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
fh.setFormatter(formatter)复制
第四步,将logger实例添加到处理器(handler)里面
logger.addHandler(fh)
复制
第五步:定义输出对应的日志内容
logging.debug("Python UI自动化测试")
logging.info("Python 全栈自动化测试")
logging.warning("Python 全栈自动化测试")
logging.error("Python 全栈自动化测试")
logging.critical("Python 全栈自动化测试")复制
完整代码
import logging # 引入logging模块
import os.path
import datetime
logger = logging.getLogger()
logger.setLevel(logging.DEBUG) # Log等级总开关
# 定义日志文件名称、使用时间进行区分不同阶段的日志文件存储
logfile = os.path.join(r'F:\demo\interface\logs',datetime.datetime.now().strftime("%Y-%m-%d") + ".log")
fh = logging.FileHandler(logfile, mode='w')
fh.setLevel(logging.DEBUG) # 输出到file的log等级的开关
formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
fh.setFormatter(formatter)
logger.addHandler(fh)
logging.debug("Python UI自动化测试")
logging.info("Python 全栈自动化测试")
logging.warning("Python 全栈自动化测试")
logging.error("Python 全栈自动化测试")
logging.critical("Python 全栈自动化测试")复制
进行输出控制台及文件日志
日志组件
一、logging模块四大组件类
日志器Logger:提供程序一直使用的接口;
处理器Handler:将日志器创建的日志记录输出到指定位置,不同的处理器可将日志输出到不同的位置;
过滤器Filter:过滤日志,输出哪条日志记录,丢弃哪条日志记录;
格式器Formatter:日志记录的最终输出格式;
详细操作描述:日志器作为入口,通过设置多个处理器的方式将日志输出,处理器再通过过滤器和格式器对日志进行处理操作。
(1) Logger是以 (.)分割的层级结构,每个 . 前面的logger是后面logger的parent;
(2)一个Logger可以包含多个Handler;
(3)每个Handler可以设置自己的Filter和Formatter;
二、 Logger对象方法详解
setLevel对象方法
logging.getLogger(Logname) | 初始化 |
setLevel(level) | 设置Logger对象日志消息级别 |
示例代码1-为日志添加等级
logger = logging.getLogger("app")
logger.setLevel("INFO")
get_name = logger.level # 获取日志对象名称
print(get_name)复制
其实在logging中每一个等级都有自己的编号
每一个日志级别都对应的一个int值,如果日志级别小于设定值:logging.INFO,就不会打印出来
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0复制
(2)Logger对象创建日志记录
debug(msg, *args, **kwargs) | 创建一个与方法名等级相同为debug的日志记录 |
info(msg, *args, **kwargs) | 创建一个与方法名等级相同为info的日志记录 |
warning(msg, *args, **kwargs) | 创建一个与方法名等级相同为warning的日志记录 |
error(msg, *args, **kwargs) | 创建一个与方法名等级相同为error的日志记录 |
critical(msg, *args, **kwargs) | 创建一个与方法名等级相同为critical的日志记录 |
Logger.exception(msg,*args, exc_info=True, **kwargs) | 创建一个类似Logger.error()的日志消息,但exception函数会输出堆栈追踪信息,通常在exception handler中调用 |
Logger.log(level, msg, *args, **kwargs) | 创建一个level参数的日志记录 |
(3)获取Logger对象
logging.getLogger(name):用来创建Logger对象
name为可选参数,表示将要返回的日志器的名称标识;若不提供参数name,则默认返回root;使用同一name多次调用方法,则指向同一logger对象。
示例代码1:
logger = logging.getLogger("app")
get_name = logger.name # 获取日志对象名称
print(get_name)
>>> app复制
注:getLogger()对象名称可自定义
示例代码2:
logger = logging.getLogger("app")
get_name = logger.name # 获取日志对象名称
get_level = logger.level # 获取日志水平
get_filters = logger.filters # 获取日志过滤器列表
get_handlers = logger.handlers # 获取日志处理器列表
get_disabled = logger.disabled # 获取日志对象是否为无效的复制
三、Handler处理器
Handler对象方法
Handler.setLevel(level) | 设置处理器将会处理的日志消息的最低级别 |
Handler.setFormatter(fmt) | 为处理器设置格式器对象 |
Handler.addFilter(filter) | 为处理器添加过滤器对象 |
Handler.removeFilter(filter) | 为处理器删除过滤器对象 |
获取Handler对象
logging.StreamHandler([stream]) | 将日志消息输出到stream |
logging.FileHandler(filename[, ..]) | 将日志消息输出到文件,文件大小无限增长 |
RotatingFileHandler(filename[, ..]) | 将日志消息输出到文件,并支持文件按大小切割 |
四、Formatter对象
日志格式化输出
可通过logging.basicConfig或logging.Formatter函数来配置格式化日志输出内容
具体格式参数配置如下:
%(name)s | Logger的名字 |
%(levelno)s | 数字形式的日志级别 |
%(levelname)s | 文本形式的日志级别 |
%(pathname)s | 调用日志输出函数的模块的完整路径名 |
%(filename)s | 调用日志输出函数的模块的文件名 |
%(module)s | 调用日志输出函数的模块名 |
%(funcName)s | 调用日志输出函数的函数名 |
%(lineno)d | 调用日志输出函数的语句所在的代码行 |
%(created)f | 当前时间,用UNIX标准的表示时间的浮 点数表示 |
%(relativeCreated)d | 输出日志信息时的,自Logger创建以 来的毫秒数 |
%(asctime)s | 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 |
%(thread)d | 线程ID。 |
%(threadName)s | 线程名。 |
%(process)d | 进程ID。 |
%(message)s | 用户输出的消息 |