Loading... ## 日志级别 | 日志级别Level | 数值 | | --------------- | ------------- | | `CRITICAL` | 50 | | `ERROR` | 40 | | `WARNING` | 30,默认级别 | | `INFO` | 20 | | `DEBUG` | 10 | | `NOSET` | 0 | <div class="tip inlineBlock info"> 日志级别指的是产生日志的事件的严重程度. 设置一个级别后,严重程度低于设置值的日志消息将被忽略 </div> ## 格式化字符串 | 属性名 | 格式 | 描述 | | -------------- | ------------------- | --------------------------------------------------------------- | | 日志消息内容 | `%(message)s` | 当调用`Formatter.format`是设置 | | asctime | `%(asctime)s` | 创建LogRecord时的可读时间, 默认格式:`2021-06-17 16:33:45.145` | | 函数名 | `%(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)` | logger名称 | ```python import logging import threading # 设置日志输出格式 FORMAT = '%(asctime)s %(levelname)s %(thread)d %(message)s' logging.basicConfig(level=logging.INFO, format=FORMAT, datefmt='%Y-%m-%d %H:%M:%S') def add(x, y): logging.warning('{}'.format(threading.current_thread())) logging.info('%s %s %s', x, y, x + y) # 这里可以使用C风格的 info('%s %s %s', x, y, x + y) ``` ### 自定义字段 ```python FORMAT = '%(asctime)s %(levelname)s %(thread)d %(message)s %(school)s' # 添加了自定义school logging.basicConfig(level=logging.INFO, format=FORMAT, datefmt='%Y-%m-%d %H:%M:%S') # 日志输出, 通过字典传入 logging.info('This Test Log', extra={'school': 'Beijixs'}) ``` ### 输出到文件 ```python FORMAT = '%(asctime)s %(levelname)s %(thread)d %(message)s' logging.basicConfig(level=logging.INFO, format=FORMAT, filemode='a', # 输出文件模式, a追加(默认), w覆盖 filename='test.log', # 输出到文件 datefmt='%Y-%m-%d %H:%M:%S') logging.info('This is test log') ``` ## logger类 ### 构造 使用工厂方法构造一个`logger` ```python import logging logger = logging.getLogger(name="Main") # getLogger(name=名称) print(logger.name) ``` <div class="tip inlineBlock info"> logger是层次结构的, 使用`.`号分割, 如`a`, `a.b` </div> ```python import logging logger = logging.getLogger(name="Main") # getLogger(name=名称) print(logger.name) logger.info('Main 记录日志') logger.parent.info('root 记录日志') ``` ### logger 的属性和方法 #### 方法 - `getEffectiveLevel()`: 获取当前`logger`的有效级别 - `setLevel(int)`: 设置当前`logger`的级别 ```python logger = logging.getLogger(__name__) logger.setLevel(logging.WARN) def add(x, y): logger.warning('{}'.format(threading.current_thread())) logger.info('%s %s %s', x, y, x + y) logger.debug('DEBUG log') logger.error('ERROR log') ``` ## Handler <div class="tip inlineBlock info"> `Handler`控制日志信息的输出目的地,可以是控制台, 文件. 可以单独设置`level` 可以单独设置格式 可以设置过滤器 </div> ### 举例 ```python import time import logging import threading FORMAT = '%(asctime)s %(name)s %(levelname)s %(thread)d %(message)s' logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) # 终端输出处理器 hdl = logging.StreamHandler() hdl.setFormatter(logging.Formatter(FORMAT, datefmt='%Y-%m-%d %H:%M:%S')) hdl.setLevel(logging.INFO) # 文件输出处理器 f_hdl = logging.FileHandler('test.log', encoding='utf8') f_hdl.setLevel(logging.DEBUG) f_hdl.setFormatter(logging.Formatter(FORMAT, datefmt='%Y-%m-%d %H:%M:%S')) logger.addHandler(hdl) # 可以添加多个handler logger.addHandler(f_hdl) def add(x, y): logger.warning('{}'.format(threading.current_thread())) logger.info('%s %s %s', x, y, x + y) logger.debug('DEBUG log') logger.error('ERROR log') logger.critical('CRITICAL log') add(54, 89) # logger的日志信息会向上传递 # 父logger如果有处理该级别日志的能力将会继续处理 """ 当前logger能够处理级别的日志, 当前logger会把消息发送给自己的handler, 然后将该消息传递给父logger, 父logger如果能够处理就继续处理并传递给父,直到不能处理 """ ``` <div class="tip inlineBlock warning"> handler的日志级别受到logger的级别限制, 假如: logger的级别为INFO, handler最高也就只能输出到INFO级别的日志, 就算设置为DEBUG,handler也只能记录到INFO </div> ### 总结 1. 每一个`Logger`实例的`level`如同入口,让水流进来,如果这个门槛太高,信息就进不来 2. 如果`level`没有设置, 就使用父`logger`的, 以此类推.直到`root`都还没有找到级别,就直接继承`root`的,默认是`WARNING` 3. 在某个`logger`上产生某种级别的消息, 首先和`logger`的`level`检查, 如果消息`level`低于`logger`的`EffectiveLevel`有效级别, 消息丢弃. 不会继续传递给父`logger`.如果通过(级别大于等于)检出后, 且`propagate`为`True`, 消息交给`logger`的所有的`handler`进行处理, 如果没有`handler`或以及被`handler`处理过的, 该消息会向上传递给父`logger`处理 4. 父`logger`拿到消息, 会重复第三天的过程, 直至消息被丢弃或到`root` 5. `logger`实例化的`propagate`属性为`True`即允许向父传递`logger`消息 ## Formatter `logging`的`Fromatter`类, 它允许指定某个格式的字符串. 如果提供`None`, 那么`%(message)s`会被作为默认值. ```python formatter = logging.Formatter('%(asctime)s %(name)s %(levelname)s %(thread)d %(message)s', datefmt='%Y-%m-%d %H:%M:%S') hdl.setFromatter(formatter) ``` ## Filter 可以为`Handler`添加一个过滤器, 所以过滤器会影响某一个`handler`, 不会影响整个流程 ```python filter = logging.Filter(__name__) # logging.Filter(name=logger名称) # 如果name为空, 那么所有消息都可以通过 # 如果设置了name, 那么就只有设置的logger name会通过 logger.addFilter(filter) # 可以多添加几个filter ``` <div class="tip inlineBlock info"> `logging`是线程安全的. </div> 最后修改:2021 年 06 月 18 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 0 如果觉得我的文章对你有用,请随意赞赏