logging模块从入门到精通

日常开发或者写脚本的时候都会有日志模块,订单日志,流水日志等,如果使用的是python,logging模块无疑是最好的选择记录重要信息相关内容的操作,通常我们记录日志需要通过打开文件去记录日志,logging 模块不需要我们反复的去打开文件,每一条日志的格式很规范,一次定好格式,就可以一直使用,类似提供了一个接口。存到对应的文件里面去。通过logging模块让日志简单化

import logging
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')

debug

WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message

这是因为默认的基本是 warning,只会打印大于等于warning 级别的日志到标准输出中,debug就没用了。
如果想打印所有的怎么做呢?调整参数。WARNING是日志级别,root是默认用户,不写默认root,后面是我们的日志内容,放什么都ok

logging.basicConfig(
    level=logging.DEBUG
)

插入这段代码后就默认都会打印出来。

DEBUG:root:debug message
INFO:root:info message
WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message

日志显示到了屏幕,我们要保存到文件里呢

logging.basicConfig(
    level=logging.DEBUG,
    filename="logger.log"
)

filename 可以指定日志输出路径,默认和脚本相同路径,日志为追加的形式
如果想写入呢?

logging.basicConfig(
    level=logging.DEBUG,
    filename="logger.log",
    filemode="w"
)

这样日志就是重新写入啦。filemode 文件打开方式,在指定了filename时使用这个参数,默认值为“a”,还可指定为“w”.
stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr.sys.stdout或者文件(f=open(‘test.log’,’w’)),默认为sys.stderr.若同时列出了filename和stream两个参数,则stream参数会被忽略,所以我们只能选择一个地方输出。做不到即显示到屏幕又输出到文件中。
format:指定handler使用的日志格式。
format 参数中可能用的的格式串:格式 %(xx)s
%(name)s Logger的名字 也就是root
%(levelno)s 数字形式的日志级别
%(levelname)s 文本形式的日志级别
%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
%(filename)s 调用日志输出函数的模块的文件名
%(module)s 调用日志输出函数的模块名
%(funcName)s 调用日志输出函数的函数名
%(lineno)d 调用日志输出函数的语句所在的代码行
%(created)f 当前时间,用UNIX标准的表示时间的浮点数表示
%(relativeCreated)d 输出日志信息时,自Logger创建以来的毫秒数
%(asctime)s 字符串形式的当前时间。默认格式是“2017-07-08 19:41:03,888”.逗号后是毫秒
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(message)s 用户输出的消息

logging.basicConfig(
    level=logging.DEBUG,
    filename="logger.log",
    filemode="w",
    format="%(asctime)s [%(lineno)d] %(message)s",
)

上面是一种方式,使用不太灵活,只能输出到一个地方,而且都是通过basicConfig来配置,接下来介绍另一个 logger,不止输出到文本,还能输出到终端
还有一个模块级别的函数是logging.getLogger([name])(返回一个logger对象,如果没有指定名字将返回root logger)
举个栗子:

    logger=logging.getLogger()
    #创建一个handler,用户写入日志文件
    fh=logging.FileHandler("test.log")
    #再创建一个handler,用户输出到控制台
    ch=logging.StreamHandler()
    fm=logging.Formatter("%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s %(message)s")
    fh.setFormatter(fm)
    ch.setFormatter(fm)
    logger.addHandler(fh)  #logger对象可以添加多个fh和ch对象
    logger.addHandler(ch)

logging库提供了多个组件,logger,Handler,Filter,Formatter.Logger对象提供应用程序可直接使用的接口,Handler发送日志到适当的目的地,Filter提供了过滤日志信息的方法,Formatter指定日志显示格式
logger是一个树形层级结构,输出信息之前都要获得一个Logger(如果没有显示的获取则自动创建并使用root Logger)
这个有2个地方需要注意

logger1=logging.getLogger('mylogger')
logger2=logging.getLogger('mylogger')
.....

如果我们定义了2个相同的对象,logger1和logger2对应同一个logger实例,只要logging.getLogger(name)中名称参数name相同则返回的logger实例就是同一个,且仅有一个,logger1最后会遵从后来设置的日志级别。
第二种情况:

logger1=logging.getLogger()
logger2=logging.getLogger(mylogger)

这种情况会 mylogger日志会打印2遍,logger会执行一遍。这是为啥呢?
这是因为logger2作为logger1的子,会看logger1有没有输出,是一个树的关系。logger2会看它的父辈是否有输出,如果有就再打印一次父级的输出。
解决办法:
logger1禁止输出,这样logger2就不会重复输出。
名字定义一定要唯一,不要重复。

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页