一、日志模块
import logging
logging.debug("调试日志")
logging.info('消息日志')
logging.warning("告警日志") # 异常但是确定可以恢复
logging.error('错误日志') # 异常,确定不能处理,并会产生严重影响
logging.critical('严重错误日志') # 异常,谁知道影响会是怎样
- debug: 用于开发者调试,显示变量等详细信息; 正常版本不应包含
- info: 通知用户关键的正常行为,如“主库添加成功”;用简单、明确的语言记录
- warning:不正常或偏离预期的行为; 不会立即影响系统,但具有潜在风险
- critical:未知的不正常行为,超出已知容错;可能会影响程序未来运行
- error: 无法修复的严重错误;必须立即处理并可能需要停止程序。
二、basicConfig
import logging
logging.basicConfig(
filename='app.log', # 日志文件名 不指定文件,默认打印到终端控制台
filemode='w', # 文件模式
format='%(asctime)s - %(name)s - %(pathname)s - %(lineno)d - %(levelname)s - %(message)s',
, # 日志格式
datefmt='%d-%b-%y %H:%M:%S', # 时间格式 format中asctime
level=logging.DEBUG # 日志级别
)
logging.debug("调试日志")
logging.info('消息日志') # 正常日志
logging.warning("告警日志")
logging.error('错误日志')
logging.critical('严重错误日志')
日志格式:
日志字段 | 示例值 | 描述 |
---|---|---|
asctime | 2023-05-19 15:30:45 | 日志事件发生的时间 |
name | my_logger | 记录日志事件的 logger 的名称 |
pathname | /path/to/my_file.py | 产生日志的文件路径 |
lineno | 42 | 产生日志的文件行数 |
levelname | ERROR | 日志等级 |
message | This is an error message | 日志内容 |
文件模式:filemode
模式 | 描述 |
---|---|
‘r’ | 只读模式,文件必须存在。 |
‘w’ | 写入模式,若文件存在则清空内容,若文件不存在则创建新文件。 |
‘x’ | 独占创建模式,仅能用于创建新文件,若文件已存在则引发错误。 |
‘a’ | 追加模式,若文件存在则将内容追加到末尾,若文件不存在则创建新文件。 |
三、日志记录器
在Python的 logging 模块中,我们可以使用字典来进行配置,这比使用 basicConfig() 函数更加灵活。字典配置可以让你更详细地控制日志记录器、处理器、过滤器和格式化器;
可以定义多个日志记录器(logger),并且为每个记录器配置不同的处理器(handler),每个记录器可以独立地设置它的日志级别和处理器
formatters 日志格式化器
filters 日志过滤器
handlers 日志处理器
loggers 日志记录器
formatters 日志格式化器
filters 日志过滤器
loggers、handlers 均配置日志级别,会对其二次筛选
定义了两个日志记录器:console_logger 和 file_logger。console_logger 记录器只将日志消息发送到控制台,file_logger 记录器只将日志消息发送到文件。
import logging
import logging.config
LOGGING_CONFIG = {
'version': 1, # 必填。这是配置字典的版本,必须为1。
'disable_existing_loggers': False, # 可选。默认为True,表示禁用所有已存在的日志记录器。设置为False允许已存在的记录器继续运行。
'formatters': { # 日志格式化器:
'standard': { # 标准格式器 名字可随意改,可随意添加
'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s',
'datefmt': '%d-%b-%y %H:%M:%S'
},
'detailed': { # 更详细的格式器
'format': '%(asctime)s [%(levelname)s] %(name)s %(pathname)s %(lineno)d: %(message)s',
'datefmt': '%d-%b-%y %H:%M:%S'
},
},
'filters': {}, # 日志过滤器:默认即可
'handlers': { # 日志处理器: 此处定义了两种不同的处理器,可自定义
'console': { # 控制台处理器
'class': 'logging.StreamHandler', # 使用的处理器类
'formatter': 'standard', # 使用的格式器
'level': 'DEBUG', # 处理器的日志级别
},
'file': { # 文件处理器
'class': 'logging.FileHandler', # 使用的处理器类
'filename': 'app.log', # 日志文件名
'formatter': 'detailed', # 使用的格式器
'level': 'DEBUG', # 处理器的日志级别
},
'file2': { # 文件处理器
'class': 'logging.FileHandler', # 使用的处理器类
'filename': 'app2.log', # 日志文件名
'formatter': 'detailed', # 使用的格式器
'level': 'DEBUG', # 处理器的日志级别
},
'file3': {
'class': 'logging.handlers.RotatingFileHandler', # 使用RotatingFileHandler
'filename': 'app3.log', # 日志文件名
'maxBytes': 1024*1024*30, # 日志文件的最大字节数
'backupCount': 14, # 备份文件的数量
'formatter': 'standard', # 使用的格式器
'level': 'DEBUG', # 处理器的日志级别
},
},
'loggers': { # 日志记录器
'console_logger': { # 只将日志消息发送到控制台
'handlers': ['console'], # 使用的处理器
'level': 'DEBUG', # 记录器的日志级别
'propagate': False, # 默认True (向更高级别logger传递)
},
'file_logger': { # 只将日志消息发送到文件
'handlers': ['console', 'file'], # 使用的处理器及输入终端也卸乳文件
'level': 'INFO', # 记录器的日志级别
},
'': { # 只将日志消息发送到文件
'handlers': ['console', 'file2'], # 使用的处理器及输入终端也卸乳文件
'level': 'INFO', # 记录器的日志级别
},
},
}
logging.config.dictConfig(LOGGING_CONFIG)
# 使用记录器记录日志
console_logger = logging.getLogger('console_logger')
console_logger.debug("调试日志")
console_logger.info('消息日志') # 正常日志
console_logger.warning("告警日志")
console_logger.error('错误日志')
console_logger.critical('严重错误日志')
file_logger = logging.getLogger('file_logger')
file_logger.debug("调试日志")
file_logger.info('消息日志') # 正常日志
file_logger.warning("告警日志")
file_logger.error('错误日志')
file_logger.critical('严重错误日志')
# 如果用户登录、用户订单 没有配置对应的logger,
找不到会默认找没有名字的'' logger
file_logger = logging.getLogger('login')
file_logger.info("用户登录")
file_logger = logging.getLogger('order')
file_logger.info("用户订单")
import uvicorn
from uvicorn.config import LOGGING_CONFIG
if __name__ == "__main__":
# 修改默认日志配置
LOGGING_CONFIG["formatters"]["default"]["fmt"] = "%(asctime)s - %(levelname)s - %(message)s"
LOGGING_CONFIG["formatters"]["default"]["datefmt"] = "%Y-%m-%d %H:%M:%S"
LOGGING_CONFIG["formatters"]["access"][
"fmt"
] = '%(asctime)s - %(levelname)s - %(client_addr)s - "%(request_line)s" %(status_code)s'
LOGGING_CONFIG["formatters"]["access"]["datefmt"] = "%Y-%m-%d %H:%M:%S"
uvicorn.run("app:app", host="0.0.0.0", port=9999, reload=True, log_config=LOGGING_CONFIG)
import sys
from datetime import datetime, date
from loguru import logger as _logger
from config.config import settings
def define_log_level(print_level="INFO", logfile_level="DEBUG", name: str = None):
"""Adjust the log level to above level"""
_print_level = print_level
formatted_date = date.today().strftime("%Y%m%d")
log_name = (f"{name}_{formatted_date}" if name else formatted_date)
_logger.remove()
_logger.add(
sys.stdout,
level=_print_level,
format=(
"<green>{time:YYYYMMDD HH:mm:ss}</green> | " # 颜色>时间
"<cyan>{module}</cyan>.<cyan>{function}</cyan>" # 模块名.方法名
":<cyan>{line}</cyan> | " # 行号
"<level>{level}</level>: " # 等级
"<level>{message}</level>" # 日志内容
),
)
_logger.add(f"{settings.log_path}/{log_name}.log",
format=(
"{time:YYYYMMDD HH:mm:ss} - " # 时间
"{function}:{line} - {level} - {message}" # 模块名.方法名:行号 "{module}.{function}:{line} - {level} - {message}"
),
encoding='utf-8',
level="DEBUG",
retention='14 days', # 设置历史保留时长
backtrace=True, # 回溯
diagnose=True, # 诊断
enqueue=True, # 异步写入
rotation="00:00", # 每日更新时间
# rotation="5kb", # 切割,设置文件大小,rotation="12:00",rotation="1 week"
# filter="my_module" # 过滤模块
# compression="zip" # 文件压缩
)
return _logger
logger = define_log_level()
if __name__ == "__main__":
logger.info("Starting application")
logger.debug("Debug message")
logger.warning("Warning message")
logger.error("Error message")
logger.critical("Critical message")