文章目录
- 1、前言
- 2、日志的等级
- 3、logging的基本应用
- 4、logging的进阶应用
- 5、logging的高阶应用
- 6、简单调用
- 7、参考
1、前言
编程代码中,日志的合理使用,能够很好地监控代码的运行过程;在业务部署中,通过日志的记录情况,快速查看代码状态,定位代码运行异常信息,能高效地进行代码维护、管理、执行等。
2、日志的等级
日志包含以下等级;设置日志等级之后,日志输出只会包含大于等于设置等级的日志信息。
3、logging的基本应用
- 尝试创建一条日志,结果会打印所有的的信息
import logging
# level默认为WARNING级别,不传入参数只会打印logging.waring及以下的日志
logging.basicConfig(level=logging.DEBUG)
logging.debug('这是一条debug日志')
logging.info('这是一条info日志')
logging.warning('这是一条warning日志')
logging.error('这是一条error日志')
logging.critical('这是一条critical日志')
此外,可以设定参数控制日志输出的格式;
参数 | 功能 |
---|---|
%(asctime)s | 日志事件的发生时间 |
%(levelname)s | 该日志事件的级别 |
%(message)s | 日志记录的文本内容 |
%(name)s | 所使用日志器的名称,默认为’root’ |
%(pathname)s | 调用日志记录函数的文件全路径 |
%(filename)s | 调用日志记录函数的函数名 |
%(funcname)s | 调用日志记录函数的函数名 |
%(lineno)d | 调用日志记录函数的代码所在的行号 |
- 使用以下代码再次尝试,对比不同之处
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', datefmt="%Y-%m-%d %H:%M:%S")
logging.debug('这是一条debug日志')
logging.info('这是一条info日志')
logging.warning('这是一条warning日志')
logging.error('这是一条error日志')
logging.critical('这是一条critical日志')
- 在logging.basicConfig中加入filename参数,将日志输出到文件中
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', datefmt="%Y-%m-%d %H:%M:%S", filename='demo.log')
logging.debug('这是一条debug日志')
logging.info('这是一条info日志')
logging.warning('这是一条warning日志')
logging.error('这是一条error日志')
logging.critical('这是一条critical日志')
4、logging的进阶应用
- 相关组件
名称 | 作用 |
---|---|
Loggers | 记录器,提供应用程序代码直接使用的接口 |
Handles | 处理器,将记录器产生的日志发送到目的地 |
Filters | 过滤器,提供更好的粒度控制,决定哪些日志会被输出 |
Formatters | 格式化器,设置日志内容的组成结构和消息字段 |
# 标准输出handler, 在终端输出
console_handler = logging.StreamHandler(stream=None)
# 文件handler, 将日志输出到文件中
file_handler = logging.FileHandler(filename,mode='a',encoding=None,delay=False)
# 其它handler
# BaseRotatingHandler
# Rotating Filehandler 滚动的多日志输出,按照时间or其他方式去生成多个日志
# TimedRotatingfilehandler
# ===========================
# 以下的使用较少
# Sockethandler
# Dataaramhandler
# Smtphandler
# Sysloghandler
# Nteventloghandler
# Httphandler
# WatchedFilehandler
# Qutelehandler
# Nullhandler
属性 | 格式 | 描述 |
---|---|---|
asctime | %(asctime)s | 日志产生的时间,默认格式为msecs2003-07-0816:49:45,896 |
msecs | %(msecs)d | 日志生成时间的亳秒部分 |
created | %(created)f | 生成的日志创建时间戳 |
message | %(message)s | 具体的日志信息 |
filename | %(filename)s | 生成日志的程序名 |
name | %(name)s | 日志调用者 |
funcname | %( funcname)s | 调用日志的函数名 |
levelname | %(levelname)s | 日志级別( DEBUG,INFO, WARNING, 'ERRORCRITICAL) |
levene | %( leveling)s | 日志级别对应的数值 |
lineno | %(lineno)d | 日志所针对的代码行号(如果可用的话) |
module | %( module)s | 生成日志的模块名 |
pathname | %( pathname)s | 生成日志的文件的完整路径 |
process | %( (process)d | 生成日志的进程D(如果可用) |
processname | (processname)s | 进程名(如果可用) |
thread | %(thread)d | 生成日志的线程D(如果可用) |
threadname | %( threadname)s | 线程名(如果可用) |
- 示例
#记录器
logger = logging.getLogger('cn.cccb.applog')
logger.setLevel(logging.DEBUG)
#必须设置为两个handler中级别更低的
#处理器handler
consoleHandler = logging.StreamHandler()
consoleHandler.setLevel(logging.DEBUG)
#没有给handler指定日志级别,将使用logger的级别
fileHandler = logging.FileHandler(filename='addDemo.log')
consoleHandler.setLevel(logging.INFO)
#formatter格式
formatter = logging.Formatter("%(asctime)s|%(levelname)8s|%(filename)10s%lineno)s|%(message)s")
#里面的8,10实现了占位对齐
#给处理器设置格式
consoleHandler.setFormatter(formatter)
fileHandler.setFormatter(formatter)
#记录器要设置处理器
logger.addHandler(consoleHandler)
logger.addHandler(fileHandler)
#定义一个过滤器
flt = logging.Filter("cn.cccb")
#关联过滤器
# logger.addFilter(flt)
fileHandler.addFilter(flt)
#打印日志的代码
#logging.debug()#不能使用这个了!!!会使用WARNING的版本,不会用之前的记录器
logger.debug("姓名 %s, 年龄%d",name,age)
logger.debug("姓名 %s, 年龄%d",% (name,age))
logger.debug("姓名 {}, 年龄{}"。format(name,age))
logger.debug(f"姓名{name}, 年龄{age}")
5、logging的高阶应用
- logging的配置文件形式 .conf
#./logging.conf
#记录器:提供应用程序代码直接使用的接口
#设置记录器名称,root必须存在!!!
[loggers]
keys=root,applog
#处理器,将记录器产生的日志发送至目的地
#设置处理器类型
[handlers]
keys=fileHandler,consoleHandler
#格式化器,设置日志内容的组成结构和消息字段
#设置格式化器的种类
[formatters]
keys=simpleFormatter
#设置记录器root的级别与种类
[logger_root]
level=DEBUG
handlers=consoleHandler
#设置记录器applog的级别与种类
[logger_applog]
level=DEBUG
handlers=fileHandler,consoleHandler
#起个对外的名字
qualname=applog
#继承关系
propagate=0
#设置
[handler_consoleHandler]
class=StreamHandler
args=(sys.stdout,)
level=DEBUG
formatter=simpleFormatter
[handler_fileHandler]
class=handlers.TimedRotatingFileHandler
#在午夜1点(3600s)开启下一个log文件,第四个参数0表示保留历史文件
args=('applog.log','midnight',3600,0)
level=DEBUG
formatter=simpleFormatter
[formatter_simpleFormatter]
format=%(asctime)s|%(levelname)8s|%(filename)s[:%(lineno)d]|%(message)s
#设置时间输出格式
datefmt=%Y-%m-%d %H:%M:%S
- logging的字典配置形式
# logging_config.py
LOGGING_CONFIG = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'simpleFormatter': {
'format': '%(asctime)s|%(levelname)8s|%(filename)s[:%(lineno)d]|%(message)s',
'datefmt': '%Y-%m-%d %H:%M:%S'
}
},
'handlers': {
'consoleHandler': {
'class': 'logging.StreamHandler',
'stream': 'ext://sys.stdout',
'level': 'DEBUG',
'formatter': 'simpleFormatter'
},
'fileHandler': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': 'applog.log',
'when': 'midnight',
'interval': 1,
'backupCount': 0,
'level': 'DEBUG',
'formatter': 'simpleFormatter'
}
},
'loggers': {
'root': {
'handlers': ['consoleHandler'],
'level': 'DEBUG',
'propagate': False
},
'applog': {
'handlers': ['fileHandler', 'consoleHandler'],
'level': 'DEBUG',
'propagate': False
}
}
}
- 配置文件加载、调用
import logging
import logging.config
from logging_config import LOGGING_CONFIG
logging.config.fileConfig('logging.conf')
#使用字典就能从任意格式文件进行配置,字典是一种接口格式
# logging.config.dictConfig(LOGGING_CONFIG)
rootLogger = logging.getLogger('applog')
rootLogger.debug("This is root Logger, debug")
logger = logging.getLogger('cn.cccb.applog')
logger.debug("This is applog, debug")
try:
int(a)
except Exception as e:
logger.exception(e)
6、简单调用
- 使用以上配置文件过程中,想要进行每天日志输出,输出日志的文件名每天不一样,发现总有些问题。问题是我在只使用root_logger记录器时,依然生成了datetime.now().strftime(‘applog_%Y-%m-%d.log’)命名的日志文件,代码如下:
import os
import logging
import logging.config
from datetime import datetime
# 确保日志目录存在
log_dir = 'logs'
if not os.path.exists(log_dir):
os.makedirs(log_dir)
LOGGING_CONFIG = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standardFormatter': {
'format': '%(asctime)s | %(levelname)8s | %(name)s | %(filename)s[:%(lineno)d] | %(message)s',
'datefmt': '%Y-%m-%d %H:%M:%S'
}
},
'handlers': {
'consoleHandler': {
'class': 'logging.StreamHandler',
'stream': 'ext://sys.stdout',
'level': 'DEBUG',
'formatter': 'standardFormatter'
},
'fileHandler': {
'class': 'logging.FileHandler',
'filename': os.path.join(log_dir, datetime.now().strftime('applog_%Y-%m-%d.log')),
'level': 'INFO',
'formatter': 'standardFormatter',
'encoding': 'utf-8' # 指定编码
}
},
'loggers': {
'root': { # root logger
'handlers': ['consoleHandler'], # 只包含控制台处理器
'level': 'DEBUG',
'propagate': False
},
'MyLogger': {
'handlers': ['fileHandler', 'consoleHandler'], # 包含文件和控制台处理器
'level': 'INFO',
'propagate': False
}
}
}
# 应用配置
logging.config.dictConfig(LOGGING_CONFIG)
# 使用root logger
root_logger = logging.getLogger('root')
root_logger.debug("This is a DEBUG message from root logger")
root_logger.info("This is an INFO message from root logger")
# 使用MyLogger logger
my_logger = logging.getLogger('MyLogger')
my_logger.debug("This is a DEBUG message from MyLogger") # 不会显示,因为level是INFO
my_logger.info("This is an INFO message from MyLogger")
my_logger.error("This is an ERROR message from MyLogger")
- 所以,采用了以下方法实现
import logging
import os
from datetime import datetime
def setup_logger(config):
"""
使用配置字典创建并返回一个定制化的logger。
:param config: 包含日志配置的字典
"""
# 创建日志目录
log_dir = config.get('log_dir', 'logs')
if not os.path.exists(log_dir):
os.makedirs(log_dir)
# 创建logger
logger = logging.getLogger(config.get('name', 'PIESAT'))
logger.setLevel(config.get('log_level', logging.INFO))
# 创建日志格式
formatter_config = config.get('formatter', {})
formatter = logging.Formatter(formatter_config.get('format', '%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
# 创建文件处理器
file_handler_config = config.get('file_handler', {})
if file_handler_config:
log_filename = datetime.now().strftime(
file_handler_config.get('filename_format', "log_%Y-%m-%d_%H-%M-%S.log")) # 修改这里
file_handler = logging.FileHandler(os.path.join(log_dir, log_filename))
# 设置等级
file_handler.setLevel(file_handler_config.get('level', logging.DEBUG))
# 设置格式
file_handler.setFormatter(formatter)
# 添加处理器
logger.addHandler(file_handler)
# 创建终端处理器
console_handler_config = config.get('console_handler', {})
console_handler = logging.StreamHandler()
console_handler.setLevel(console_handler_config.get('level', logging.DEBUG))
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
return logger
# 使用示例
logger_config = {
'log_dir': 'logs',
'name': 'MuYe',
'log_level': logging.INFO,
'file_handler': {
'filename_format': "log_%Y-%m-%d_%H-%M.log", # 修改这里
'level': logging.INFO,
},
'console_handler': {
'level': logging.DEBUG,
},
'formatter': {
'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
}
}
logger = setup_logger(logger_config)
logger.info("This is an info message")
7、参考
Python基础之标准库logging
标准库系列:logging 日志打印