logging基本知识
logging是一个python内置的包,即文件夹logging下有一个__init__.py文件
知识点主要包括:
- 日志5个级别:logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL
- 配置:logging.basicConfig(…)
- 配置信息:日志输出文件filename, 日志格式format, 日期格式datefmt, 日志级别level)
- 格式信息:%(asctime)s %(levelname)s %(thread)-8d %(name)s %(message)s
- 日期格式:%Y-%m-%d %H:%M:%S
- logger = logging.getLogger(‘loggername’)这里的loggername即格式中的name
- logging.info(msg, args, **kwargs), msg和args可以使用%s一起进行格式化,**kwargs可以填入
exc_info=True
,这样能够捕获异常信息
日志基础版
# -*- coding:utf-8 -*-
import logging
import traceback
logging.basicConfig(filename='log_learn.log',
format='[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
level=logging.INFO)
logger = logging.getLogger(__file__)
def division(v):
return 10/v
# 使用exc_info参数来捕获异常信息,%s可以进行格式化
try:
division(0)
except:
logger.error('函数%s报错,报错信息为:', division.__name__, exc_info=1)
# 使用traceback.format_exc()来捕获异常信息
try:
division(0)
except:
trace_info = traceback.format_exc()
msg = '函数{func_name}报错,报错信息为:\n{trace_info}'.format(
func_name=division.__name__,
trace_info=trace_info)
logger.error(msg)
format
| %(name)s Name of the logger (logging channel)
| %(levelno)s Numeric logging level for the message (DEBUG, INFO,
| WARNING, ERROR, CRITICAL)
| %(levelname)s Text logging level for the message ("DEBUG", "INFO",
| "WARNING", "ERROR", "CRITICAL")
| %(pathname)s Full pathname of the source file where the logging
| call was issued (if available)
| %(filename)s Filename portion of pathname
| %(module)s Module (name portion of filename)
| %(lineno)d Source line number where the logging call was issued
| (if available)
| %(funcName)s Function name
| %(created)f Time when the LogRecord was created (time.time()
| return value)
| %(asctime)s Textual time when the LogRecord was created
| %(msecs)d Millisecond portion of the creation time
| %(relativeCreated)d Time in milliseconds when the LogRecord was created,
| relative to the time the logging module was loaded
| (typically at application startup time)
| %(thread)d Thread ID (if available)
| %(threadName)s Thread name (if available)
| %(process)d Process ID (if available)
| %(message)s The result of record.getMessage(), computed just as
| the record is emitted
logging高级知识
- Logger 提供接口给代码,让其操作记录日志
- Handler 确定日志输出的目的地,可以是文件、控制台等
- Filter 拒绝不需要的日志内容
- Formatter 日志内容的格式
日志记录的流程(官网流程图)
- 代码调用接口如 logger.info
- 判断是否满足logger的level,满足则创建LogRecord
- Filter是否要拒绝日志,如果不拒绝则进入handler
- handler判断日志是否满足level,满足则进行Filter
- Filter如果没有拒绝,则emit,进行发出
创建3个输出地方的日志记录器
# -*- coding:utf-8 -*-
import logging
# 1、创建日志记录器,使用当前文件路径名作为日志名称,级别为INFO
logger = logging.getLogger(__file__)
logger.setLevel(logging.INFO)
# 2、创建3个日志输出,2个文件,一个控制台
handler_file_1 = logging.FileHandler('file_1.log')
handler_file_1.setLevel(logging.INFO) # 打印INFO级别及以上的日志信息
handler_file_2 = logging.FileHandler('file_2.log')
handler_file_2.setLevel(logging.ERROR) # 只打印报错级别及以上的日志信息
handler_stream = logging.StreamHandler()
handler_stream.setLevel(logging.ERROR) # 只打印报错级别及以上的日志信息
# 3、创建格式
formatter = logging.Formatter('[%(asctime)s] %(levelname)s %(name)s %(message)s')
handler_file_1.setFormatter(formatter)
handler_file_2.setFormatter(formatter)
handler_stream.setFormatter(formatter)
# 4、操作输出器handler添加到logger
logger.addHandler(handler_file_1)
logger.addHandler(handler_file_2)
logger.addHandler(handler_stream)
def add_value(value):
logger.info('参数值为:%s', value)
return value
def division(value):
try:
10/value
except:
logger.error('发生报错,报错信息为:', exc_info=1)
add_value(0)
division(0)
使用dictConfig
来简化上边的操作(功能内容并非完全一致,仅供参考)
# -*- coding:utf-8 -*-
import logging
from logging import config
log_config = {
'version': 1,
'loggers': {
'': {
'handlers': ['file', 'stream'],
'level': 'INFO',
}
},
'handlers': {
'file': {
'class': 'logging.FileHandler',
'filename': 'log/log_config.log',
'level': 'INFO',
'formatter': 'default'
},
'stream': {
'class': 'logging.StreamHandler',
'level': 'INFO',
'formatter': 'simple'
}
},
'formatters': {
'default': {
'format': '[%(asctime)s] %(levelname)s %(pathname)s %(message)s',
'datefmt': '%Y-%m-%d %H:%M:%S'
},
'simple': {
'format': '[%(asctime)s] %(message)s'
}
}
}
logging.config.dictConfig(log_config)
logger = logging.getLogger(__file__)
def add_log(data):
logger.info('执行函数,打印日志,参数为:%s', data)
def division(v):
try:
10/v
except:
logger.error('函数报错,报错信息为:', exc_info=1)
add_log(10)
division(0)
dictConfig
注意事项:
- 编写dictConfig,实际上就是对logging使用logger, handler, filter, formatter的使用,将参数统一写到这里
- 第一层的这几个单词要加s:loggers,handlers,formatters
- loggers底下的handlers是加s的
- handlers底下的formatter是不加s的
- loggers底下不能直接写handlers,level,要多一层字典,可以用
'':{}
的形式(如果命名一个会出现报错,不知道什么原因) - class和level的填写,也是用字符串,就是要加上引号,而不是直接写类和常量。
- loggers下的handlers的值是一个列表,如果只有一个handler,也要写成列表形式
- delay表示延时,FileHandler默认是False,表示实时写入日志,TimedRotatingHandler默认是True,要改成False才会实时写入日志
日志高级版
# -*- coding:utf-8 -*-
import logging
from logging import config
import os
# 创建log文件夹,使用项目名设置log文件名称
project_name = os.path.dirname(__file__).split('/')[-1]
if not os.path.exists('log'):
os.mkdir('log')
log_file = 'log/' + str(project_name) + '.log'
log_rotate_file = 'log/' + str(project_name) + '_rotate.log'
log_config = {
'version': 1,
'loggers': {
'': {
'handlers': ['file', 'rotate_file'],
'level': 'INFO'
}
},
'handlers': {
'file': {
'class': 'logging.FileHandler', # delay默认是False,实时写入
'filename': log_file,
'level': 'INFO',
'formatter': 'default_fmt'
},
'rotate_file': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': log_rotate_file,
'level': 'INFO',
'formatter': 'default_fmt',
'when': 'D',
'interval': 1, # 配合when使用,1D表示间隔1天就会分割一个日志
'backupCount': 90, # 保留90个日志,每天1个,相当于一共保留90天
'delay': False # 默认是True,不会实时写入,改成False,就不会推迟,实时写入日志
}
},
'formatters': {
'default_fmt': {
'format': '[%(asctime)s] %(levelname)s %(pathname)s:%(lineno)d %(message)s',
# 'datefmt': '%Y-%m-%d %H:%M:%S'
},
'simple_fmt': {
'format': '[%(asctime)s] %(message)s'
}
}
}
logging.config.dictConfig(log_config)
logger = logging.getLogger(__file__)
logger.debug('这是debug信息')
logger.info('这是info信息')
logger.error('这是error信息')