logging模块

日志级别
日志级别Level数值
CRITICAL50
ERROR40
WARNING30,默认级别
INFO20
DEBUG10
NOTSET0

日志级别指的是产生日志的事件的严重程度
设置一个级别后,严重程度低于设置值的日志消息将被忽略
debug(),info(),warning(),error()和critical()方法

格式字符串
属性名格式描述
日志消息内容%(message)sThe logged message,computed as msg %args.当调用Formatter.format()时设置
asctime%(asctime)s创建LogRecord时的可读时间。默认情况下,它的格式为“2003-07-08 16:49:45,896”(逗号后面的数字是毫秒部分的时间)
函数名%(funcName)s日志调用所在的函数名
日志级别名称%(levelname)s消息的级别名称’DEBUG’,‘INFO’,‘WARNING’,‘ERROR’,‘CRITICAL’
日记级别数值%(levelno)s消息的级别数字,对应DEBUG,INFO,WARNING,ERROR,CRITICAL
行号%(lineno)d日志调用所在的源码行号
模块%(module)s模块(filename的名字部分)
进程ID%(process)d进程ID
线程ID%(thread)d线程ID
进程名称%(processName)s进程名
线程名称%(threadName)s线程名
logger名称%(name)slogger名
默认级别
#默认为WARRING
import logging
FORMAT="%(asctime)s\t Thread info: %(thread)d %(threadName)s %(message)s " \
       "simple level: %(levelno)d %(levelname)s"
logging.basicConfig(format=FORMAT)
logging.info(20)
logging.warning(10)

在这里插入图片描述

构建消息
import logging
FORMAT="%(asctime)s\t Thread info: %(thread)d %(threadName)s %(message)s " \
       "simple level: %(levelno)d %(levelname)s"
logging.basicConfig(format=FORMAT,level=logging.INFO)
logging.info(20)
logging.warning(10)
字符串扩展

如果需要输出其他内容可以使用extra扩展

import logging
FORMAT="%(asctime)s\t Thread info: %(thread)d %(threadName)s %(message)s " \
       "simple level: %(levelno)d %(levelname)s~~~~~~~%(school)s"
logging.basicConfig(format=FORMAT,level=logging.INFO)
d={'school':'university'}
logging.info(20,extra=d)
logging.warning(10,extra=d)

在这里插入图片描述

修改日期和输出到文件
import logging
logging.basicConfig(format='%(asctime)s %(message)s',datefmt="%Y/%m/%d %H:%M:%S",filename='C:/Users/ASUS/temp/o.txt')
logging.warning('this')
logging.warning('is')
logging.warning('sssssss')

 v
在这里插入图片描述

Logger类

在logging模块中,顶层代码中有

在这里插入图片描述
logging模块加载的时候,会创建一个全局对象root,它是一个RootLogger实例,即root logger。根Logger对象的默认等级为WARNING。
RootLogger类继承自Logger类
类Logger初始化方法签名是(name,level=0)
类RootLogger初始化方法签名(level),本质上调用的是logger.init(self,“root”,WARNING)
调用logging,basicConfig来调整级别,就是对这个根Logger的级别进行修改

构造

Logger实例的构建,使用Logger类也行,推荐使用getLogger函数

import logging
from logging import Manager,Logger
Logger.manager=Manager(Logger.root)
def getLogger(name=None):
    if name:
        return Logger.manager.getLogger(name)
    else:
        return root

使用工厂方法返回一个Logger实例
指定name,返回一个名称为name的Logger实例,如果再次使用相同的名字,返回同一个实例,背后使用一个字典保证同一个名称返回同一个Logger实例
未指定name,返回根Logger实例。

import logging
a=logging.Logger('hello',20)
b=logging.Logger('hello',30)
print(a,id(a))
print(b,id(b))

c=logging.getLogger('hello')
print(c,id(c))
d=logging.getLogger('hello')
print(d,id(d))
层次结构

Logger是层次结构的,使用.点号分割。

import logging
root=logging.root
print(root,id(root))
root=logging.getLogger()
print(root,id(root))
print(root.name,type(root),root.parent)

parent=logging.getLogger(__name__)
print(parent.name,type(parent),id(parent.parent),id(parent),parent.parent,parent)

child=logging.getLogger("{}{}".format(__name__,'.child'))
print(child.name,type(child),id(child.parent),id(child))

在这里插入图片描述

Level级别设置

每一个logger实例都有级别设置

import logging
FORMAT="%(asctime)s\t Thread info: %(thread)d %(threadName)s %(message)s %(levelname)s"
logging.basicConfig(format=FORMAT,level=logging.INFO)
logger=logging.getLogger(__name__)
print(logger.name,type(logging),logger.level)
logger.info('1 info')
print(logger.getEffectiveLevel())

logger.setLevel(28)
print(logger.getEffectiveLevel(),logger.level,'~~~~~~~~~``')
# INFO的级别是20,所以不会输出
logger.info('2 info')

logger.setLevel(42)
logger.warning('3 warning')
logger.error('4 error')
logger.critical('5 critical')

root=logging.getLogger()
root.info('6 root info')

在这里插入图片描述
每一个logger实例,都有一个等效的level
logger对象可以在创建后动态的修改自己的level
等效level决定这logger实例能输出什么级别信息

Handler

Handler控制日志信息的输出目的地,可以是控制台、文件

  • 可以单独设置level
  • 可以单独设置格式
  • 可以设置过滤器

Handler类层次

  • Handler
    • StreamHandler #不指定使用sys.stderr
      • FileHandler #文件
      • _StderrHandler#标准输出
    • NullHandler#什么都不做
      日志输出其实是Handler做的,也就是真正起作用的是Handler
      在logging.basicConfig函数中:
            if handlers is None:
                filename = kwargs.pop("filename", None)
                mode = kwargs.pop("filemode", 'a')
                if filename:
                    h = FileHandler(filename, mode)
                else:
                    stream = kwargs.pop("stream", None)
                    h = StreamHandler(stream)
                handlers = [h]

如果设置文件名,则为根Logger加一个输出到文件的FileHandler;如果没有设置文件名,则为根Logger加一个StreamHandler,默认输出到sys.stderr。
也就是说,根logger一定会至少有一个handler的。

import logging
FORMAT='%(asctime)s %(name)s %(message)s'
logging.basicConfig(format=FORMAT,level=logging.INFO)

logger=logging.getLogger('test')
print(logger.name,type(logger))
logger.info('line 1')

handler=logging.FileHandler('C:/Users/ASUS/temp/o.txt','w')
logger.addHandler(handler)
logger.info('line 2')

在这里插入图片描述

日志流

level继承

import logging
logging.basicConfig(format="%(asctime)s %(name)s [%(message)s]")

log1=logging.getLogger('s')
print(log1.level,log1.getEffectiveLevel())
log1.info('1 info')

log2=logging.getLogger('s.s1')
print(log2.level,log2.getEffectiveLevel())
log2.info('2.info')
print('~~~~~~~~~~~~')

log1.setLevel(20)
log1.info('3 info')
print(log1.level,log1.getEffectiveLevel())
print(log2.level,log2.getEffectiveLevel())
log2.info('4.info')

在这里插入图片描述
logger实例
如果不设置level,则初始level为0
如果设置了level,就优先使用自己的level,否则,继承最近的祖先的level。
信息是否能够从该logger实例上输出,就要看当前的函数的level是否大于等于logger的有效level。

继承关系及信息传递
  • 每一个Logger实例会有一个level,如果输出等级小于这个level,无法输出

  • 如果level没有设置,就用父logger的,如果父logger的level没有设置,继续找父的父,最终找到root上,如果root设置了就用root的,如果没有设置,采用默认值WARNING。

  • 消息传递流程

    • 如果消息在某一个logger对象上产生,这个对象就是当前logger,首先消息level要和当前logger的EffectiveLevel比较,如果低于当前logger的EffectiveLevel,则流程结束,否则生成log记录。
    • 日志记录会交给当前logger的所有handler处理,记录还要和每一个handler的级别分别比较,低的不处理,否则按照handler输出日志记录
    • 当前logger的所有handler处理完后,就要看自己的propagate属性,如果是True表示向父logger传递这个日志记录,否则流程到此结束
    • 如果日志记录传递到了父logger,不需要和父logger的level比较,而是直接交给父的所有handler,父logger成为当前logger,直到当前logger的父logger是None退出。
  • logger实例初始的propagate属性为True,即允许向父logger传递消息

  • logging.basicConfig函数
    如果root没有handler,就默认创建一个StreamHandler,如果设置了filename,就创建一个FileHandler。如果设置了format参数,就会用它生成一个Formatter对象,否则会生成缺省Formatter,并把这个formatter加入到刚才创建的handler,然后把这些handler加入到root.handlters列表上,level是设置给root loggre的,如果root.handler列表不为空,logging.basicConfig的调用什么都不做。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值