把我自己理解的概念用通俗易懂的话讲出来大概就是
2. 级别分类查看日志是开发人员日常获取信息、排查异常、发现问题的最好途径,日志记录中通常会标记有异常产生的原因、发生时间、具体错误行数等信息,这极大的节省了我们的排查时间,无形中提高了编码效率。
下表是日志按照级别分类,指的是 DeBUG、Info、WARNING、ERROR 、CRITICAL
等严重等级进行划分。
级别 | 数值 | 说明 |
---|---|---|
CRITICAL | 50 | 十分严重的问题导致程序已经不能运行 |
ERROR | 40 | 有错误导致程序的某些功能不能按照预期工作 |
WARNING | 30 | 可以是一些意料之外的问题,也可以是一些预期将要发生的问题的警告 |
INFO | 20 | 表明程序正常运行 |
DEBUG | 10 | 比较详细的信息,一般在调试问题的时候使用 |
NOTSET | 0 | 没有日志级别,任何信息都会输出 |
上述级别分类是在日志系统里通用的。在 python 中对应的模块函数分别为 deBUG()、info()、warning()、error()、critical()
Python 中日志的默认等级是 WARNING
, DEBUG
和 INFO
级别的日志将不会得到显示,在 logging 中更改设置。
先来简单使用下 python 的 logging 模块输出日志的功能
import logginglogging.deBUG('this is a deBUG msg')logging.info('this is a info msg')logging.warning('this is a warning msg')logging.error('this is a error msg')
输出如下
WARNING:root:this is a warning msgERROR:root:this is a error msg
这样的输出证实了上面所说
“Python 中日志的默认等级是
WARNING
,DEBUG
和INFO
级别的日志将不会得到显示”
我们来修改下 Python 默认的日志等级为 DEBUG
import logginglogging.basicConfig(level=logging.DEBUG)logging.deBUG('this is a deBUG msg')logging.info('this is a info msg')logging.warning('this is a warning msg')logging.error('this is a error msg')
再来看看输出结果,正如我们所预期的那样
DEBUG:root:this is a deBUG msgINFO:root:this is a info msgWARNING:root:this is a warning msgERROR:root:this is a error msg
4. 模块函数及四大组件上面的代码只是将我们想要的日志信息输出到了控制台,如果我们要记录日志到文件中,就要用到强大的logging
模块级别的函数,或者是 logging
的四大组件了。
上面设置日志级别的 logging.DEBUG
就是所说的级别函数,而四大组件分别是 loggers、handlers、filters、formatters
,从名字上也不难看出这些组件的作用
组件名称 | logging中对应的类 | 功能 |
---|---|---|
日志器 | Logger | 提供日志系统使用的接口 |
处理器 | Handler | 将 logger 收集到的日志发送到指定的地方 |
过滤器 | Filter | 在 logger 收集日志的时候提供过滤规则 |
格式器 | Formatter | 设定日志的输出格式 |
工作原理
日志器(logger)是入口,真正工作的是处理器(handler),处理器(handler)还可以通过过滤器(filter)和格式器(formatter)对要输出的日志内容做过滤和格式化等处理 *** 作。
LoggerLogger
的三个功能点
logging.deBUG
基于日志的严重级别或 filter 对象来对日志进行处理,过滤将处理过的日志信息发送到设定的 handlersLogger
对象常用方法如下
方法 | 功能描述 |
---|---|
Logger.setLevel() | 设置日志处理的最低严重级别 |
Logger.addHandler() | 将 handler 对象添加到 logger 对象中 |
Logger.removeHandler() | 将 hanlder 对象从 logger 对象中移除 |
Logger.addFilter() | 将 filter 对象添加到 logger 对象中 |
Logger.removeFilter() | 将 filter 对象从 logger 对象中移除 |
获取 logger 对象有两种方式,我们通常使用第二种方式
通过 Logger 类的实例化方法创建一个 Logger 类的实例,, 例如logger = Logger()
通过logging.getLogger()
方法。 logging.getLogger()
方法有一个可选参数 name
,该参数表示将要返回的日志器的名称标识,如果不提供该参数,则其值为 ‘root’。若以相同的 name 参数值多次调用 getLogger()
方法,将会返回指向同一个 logger 对象的引用。对于 logger 层级的补充
logger 的名称是一个以.
分割的层级结构,每个 .
后面的 logger 都是 .
前面的 logger 的 child。例如,有一个名称为 A
的 logger,其它 logger 名称分别为 A.B, A.B.C
都是 A
的后代。logger 有一个"有效等级(effective level)"的概念。如果一个 logger 上没有被明确设置一个 level,那么该logger将会向上查找已经明确定义了 level 的 logger 。需要说明的是,root logger 总是会有一个明确的level设置(默认为 WARNING)。当决定是否去处理一个已发生的事件时,logger 的有效等级将会被用来决定是否将该事件传递给该 logger 的 handlers 进行处理。child loggers 在完成对日志消息的处理后,默认会将日志消息传递给与它们的祖先 loggers 相关的 handlers。因此,我们不必为一个应用程序中所使用的所有 loggers 定义和配置 handlers,只需要为一个顶层的 logger 配置 handlers,然后按照需要创建 child loggers 就可足够了。我们也可以通过将一个 logger 的 propagate
属性设置为False来关闭这种传递机制。HandlerHander 常用的方法也不多
方法 | 功能描述 |
---|---|
Handler.setLevel() | 设置日志处理的最低严重级别 |
Handler.setFormatter() | 为 handler 对象设置一个格式器对象 |
Handler.addFilter() | 将 filter 对象添加到 handler 对象中 |
Handler.removeFilter() | 将 filter 对象从 handler 对象中移除 |
但是和 Logger 类似,我们在获取 handler 对象的时候最好不要直接实例化 Handler 这个基类。logging 模块已经为我们定义好了一些常用的 handler
logging.StreamHandler
将日志消息发送到 Stream, 如 std.out, std.err
logging.fileHandler
将日志消息发送到文件中,默认是 a
模式追加写入logging.handlers.SMTPHandler
将日志消息发送到指定邮箱logging.handlers.httpHandler
将日志消息以 GET 或是 POST 的方式发送到一个 http服务器logging.handlers.RotatingfileHandler
日志文件支持按照大小切割并发送到文件logging.handlers.TimedRotatingfileHandler
日志文件支持按照时间切割并发送到文件FormatterFormater 对象用于配置日志信息的最终顺序、结构和内容。与 logging.Handler 基类不同的是,可以直接实例化 Formatter 类。另外,如果你的应用程序需要一些特殊的处理行为,也可以实现一个 Formatter 的子类来完成。 Formatter 类的构造方法定义如下
logging.Formatter.__init__(fmt=None, datefmt=None, style='%')
该构造方法接收 3 个可选参数:
fmt
:指定消息格式化字符串,如果不指定该参数则默认使用 message 的原始值datefmt
:指定日期格式字符串,如果不指定该参数则默认使用 %Y-%m-%d %H:%M:%s
style
:可取值为 %, {, $
,如果不指定该参数则默认使用 “%”fmt
中允许使用的变量可以参考下表。
**%(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**
字符串形式的当前时间。默认格式是 “yyyy-mm-dd HH:MM:SS,SSS”**%(thread)d**
线程ID**%(threadname)s**
线程名**%(process)d**
进程ID**%(message)s**
用户输出的消息FilterFilter 可以被 Handler 和 Logger 用来做比 level 更细粒度的、更复杂的过滤功能。Filter 是一个过滤器基类,它只允许某个 logger 层级下的日志事件通过过滤。
比如,一个 filter 实例化时传递的 name 参数值为 A.B
,那么该 filter 实例将只允许名称为类似如下规则的 loggers 产生的日志记录通过过滤: A.B, A.B.C, A.B.C.D, A.B.D
,而名称为 A.BB, B.A.B
的 loggers 产生的日志则会被过滤掉。如果 name 的值为空字符串,则允许所有的日志事件通过过滤。
import loggingimport osimport sysBASE_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))sys.path.append(BASE_PATH)def my_logger(log_name='NANCY_LOG', log_file=f'{BASE_PATH}/log_demo/log/nancy.log', level=logging.DEBUG): # 创建logger对象 logger = logging.getLogger(log_name) logger.setLevel(level) # 添加等级 # 创建控制台 console handler ch = logging.StreamHandler() ch.setLevel(level) # 创建文件 handler fh = logging.fileHandler(log_file) fh.setLevel(level) # 创建 formatter formatter = logging.Formatter('%(asctime)s ' '%(filename)s ' '[line:%(lineno)s] ' '%(name)s ' '%(levelname)s: ' '%(message)s') # 添加日志格式 formatter # ch.setFormatter(formatter) fh.setFormatter(formatter) # 把ch fh 添加到 logger中 logger.addHandler(ch) logger.addHandler(fh) return loggerdef main(): # 测试 logger = my_logger(log_name='nancy test', level=logging.DEBUG) logger.info('test logging info'.center(30, '*')) logger.deBUG('test logging deBUG'.center(30, '*')) logger.error('test logging error'.center(30, '*')) logger.warning('test logging warning'.center(30, '*')) logger.critical('test logging critical'.center(30, '*'))if __name__ == '__main__': main()
总结 以上是内存溢出为你收集整理的Python日志logging模块详解全部内容,希望文章能够帮你解决Python日志logging模块详解所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)