当前位置: 首页 > news >正文

Python日志系统详解

Python日志系统详解

一、为什么需要日志

日志是软件开发中的重要工具:
- 记录程序运行状态
- 调试和排查问题
- 监控系统健康
- 审计和合规
- 性能分析

二、logging模块基础

Python的logging模块提供了灵活的日志记录功能。

2.1 基本使用

import logging

# 配置日志
logging.basicConfig(level=logging.DEBUG)

# 记录日志
logging.debug('调试信息')
logging.info('一般信息')
logging.warning('警告信息')
logging.error('错误信息')
logging.critical('严重错误')

2.2 日志级别

日志级别从低到高:
- DEBUG (10): 详细的调试信息
- INFO (20): 一般信息
- WARNING (30): 警告信息
- ERROR (40): 错误信息
- CRITICAL (50): 严重错误

三、日志配置

3.1 basicConfig配置

import logging

logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
filename='app.log',
filemode='a'
)

3.2 格式化选项

常用的格式化字段:
- %(asctime)s: 时间
- %(name)s: 日志器名称
- %(levelname)s: 日志级别
- %(message)s: 日志消息
- %(filename)s: 文件名
- %(lineno)d: 行号
- %(funcName)s: 函数名
- %(process)d: 进程ID
- %(thread)d: 线程ID

四、Logger对象

4.1 创建Logger

import logging

# 创建logger
logger = logging.getLogger('myapp')
logger.setLevel(logging.DEBUG)

# 创建handler
console_handler = logging.StreamHandler()
file_handler = logging.FileHandler('app.log')

# 设置级别
console_handler.setLevel(logging.INFO)
file_handler.setLevel(logging.DEBUG)

# 创建formatter
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)

# 添加formatter到handler
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)

# 添加handler到logger
logger.addHandler(console_handler)
logger.addHandler(file_handler)

# 使用logger
logger.debug('这是调试信息')
logger.info('这是一般信息')

4.2 Logger层次结构

import logging

# 父logger
parent_logger = logging.getLogger('myapp')

# 子logger(自动继承父logger的配置)
child_logger = logging.getLogger('myapp.module1')
grandchild_logger = logging.getLogger('myapp.module1.submodule')

五、Handler类型

5.1 StreamHandler

# 输出到控制台
console_handler = logging.StreamHandler()

5.2 FileHandler

# 输出到文件
file_handler = logging.FileHandler('app.log')

5.3 RotatingFileHandler

# 按文件大小轮转
from logging.handlers import RotatingFileHandler

handler = RotatingFileHandler(
'app.log',
maxBytes=10*1024*1024, # 10MB
backupCount=5 # 保留5个备份
)

5.4 TimedRotatingFileHandler

# 按时间轮转
from logging.handlers import TimedRotatingFileHandler

handler = TimedRotatingFileHandler(
'app.log',
when='midnight', # 每天午夜轮转
interval=1,
backupCount=7 # 保留7天
)

# when参数选项:
# 'S': 秒
# 'M': 分钟
# 'H': 小时
# 'D': 天
# 'midnight': 午夜
# 'W0'-'W6': 星期几(0=星期一)

5.5 SMTPHandler

# 发送邮件
from logging.handlers import SMTPHandler

mail_handler = SMTPHandler(
mailhost=('smtp.example.com', 587),
fromaddr='app@example.com',
toaddrs=['admin@example.com'],
subject='应用错误',
credentials=('username', 'password'),
secure=()
)
mail_handler.setLevel(logging.ERROR)

六、Filter过滤器

6.1 自定义Filter

class ContextFilter(logging.Filter):
def filter(self, record):
# 添加自定义字段
record.user = 'Alice'
record.ip = '192.168.1.1'
return True

logger = logging.getLogger('myapp')
logger.addFilter(ContextFilter())

formatter = logging.Formatter(
'%(asctime)s - %(user)s - %(ip)s - %(message)s'
)

6.2 条件过滤

class LevelFilter(logging.Filter):
def __init__(self, level):
self.level = level

def filter(self, record):
return record.levelno == self.level

# 只记录ERROR级别
error_filter = LevelFilter(logging.ERROR)
handler.addFilter(error_filter)

七、配置文件方式

7.1 使用字典配置

import logging.config

LOGGING_CONFIG = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'level': 'INFO',
'formatter': 'standard',
'stream': 'ext://sys.stdout'
},
'file': {
'class': 'logging.handlers.RotatingFileHandler',
'level': 'DEBUG',
'formatter': 'standard',
'filename': 'app.log',
'maxBytes': 10485760,
'backupCount': 5
}
},
'loggers': {
'myapp': {
'level': 'DEBUG',
'handlers': ['console', 'file'],
'propagate': False
}
},
'root': {
'level': 'INFO',
'handlers': ['console']
}
}

logging.config.dictConfig(LOGGING_CONFIG)

7.2 使用INI文件配置

# logging.ini
[loggers]
keys=root,myapp

[handlers]
keys=console,file

[formatters]
keys=standard

[logger_root]
level=INFO
handlers=console

[logger_myapp]
level=DEBUG
handlers=console,file
qualname=myapp
propagate=0

[handler_console]
class=StreamHandler
level=INFO
formatter=standard
args=(sys.stdout,)

[handler_file]
class=handlers.RotatingFileHandler
level=DEBUG
formatter=standard
args=('app.log', 'a', 10485760, 5)

[formatter_standard]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s

# 加载配置
import logging.config
logging.config.fileConfig('logging.ini')

八、结构化日志

8.1 使用structlog

# 安装: pip install structlog

import structlog

structlog.configure(
processors=[
structlog.processors.TimeStamper(fmt="iso"),
structlog.processors.JSONRenderer()
]
)

logger = structlog.get_logger()

logger.info("user_login", user_id=123, ip="192.168.1.1")
# 输出: {"event": "user_login", "user_id": 123, "ip": "192.168.1.1", "timestamp": "2024-05-14T10:30:00"}

8.2 JSON格式日志

import json
import logging

class JsonFormatter(logging.Formatter):
def format(self, record):
log_data = {
'timestamp': self.formatTime(record),
'level': record.levelname,
'logger': record.name,
'message': record.getMessage(),
'module': record.module,
'function': record.funcName,
'line': record.lineno
}

if record.exc_info:
log_data['exception'] = self.formatException(record.exc_info)

return json.dumps(log_data)

handler = logging.StreamHandler()
handler.setFormatter(JsonFormatter())

九、上下文信息

9.1 使用extra参数

logger = logging.getLogger('myapp')

logger.info('用户登录', extra={
'user_id': 123,
'ip': '192.168.1.1',
'action': 'login'
})

9.2 使用LoggerAdapter

class UserAdapter(logging.LoggerAdapter):
def process(self, msg, kwargs):
return f"[User {self.extra['user_id']}] {msg}", kwargs

logger = logging.getLogger('myapp')
user_logger = UserAdapter(logger, {'user_id': 123})

user_logger.info('执行操作')
# 输出: [User 123] 执行操作

十、异常日志

10.1 记录异常

try:
result = 10 / 0
except Exception as e:
logger.exception('发生异常') # 自动包含堆栈跟踪
# 或
logger.error('发生异常', exc_info=True)

10.2 自定义异常处理

import sys

def handle_exception(exc_type, exc_value, exc_traceback):
if issubclass(exc_type, KeyboardInterrupt):
sys.__excepthook__(exc_type, exc_value, exc_traceback)
return

logger.critical(
"未捕获的异常",
exc_info=(exc_type, exc_value, exc_traceback)
)

sys.excepthook = handle_exception

十一、性能考虑

11.1 延迟格式化

# 低效
logger.debug('值为: ' + str(expensive_operation()))

# 高效(只在DEBUG级别启用时才执行)
logger.debug('值为: %s', expensive_operation())

11.2 条件日志

# 避免不必要的计算
if logger.isEnabledFor(logging.DEBUG):
logger.debug('复杂数据: %s', compute_expensive_data())

十二、实战案例:Web应用日志

from flask import Flask, request
import logging
from logging.handlers import RotatingFileHandler

app = Flask(__name__)

# 配置日志
handler = RotatingFileHandler('app.log', maxBytes=10000000, backupCount=3)
handler.setFormatter(logging.Formatter(
'%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
))
handler.setLevel(logging.INFO)
app.logger.addHandler(handler)
app.logger.setLevel(logging.INFO)

@app.before_request
def log_request():
app.logger.info(
'Request: %s %s from %s',
request.method,
request.path,
request.remote_addr
)

@app.after_request
def log_response(response):
app.logger.info(
'Response: %s %s - %d',
request.method,
request.path,
response.status_code
)
return response

@app.errorhandler(Exception)
def handle_error(error):
app.logger.exception('发生错误')
return '服务器错误', 500

十三、实战案例:多进程日志

from multiprocessing import Process, Queue
import logging
from logging.handlers import QueueHandler, QueueListener

def worker_process(queue):
# 配置worker使用QueueHandler
handler = QueueHandler(queue)
logger = logging.getLogger()
logger.addHandler(handler)
logger.setLevel(logging.INFO)

logger.info('Worker进程开始')

def main():
# 创建队列
queue = Queue()

# 配置监听器
handler = logging.StreamHandler()
listener = QueueListener(queue, handler)
listener.start()

# 启动worker进程
processes = [Process(target=worker_process, args=(queue,)) for _ in range(4)]
for p in processes:
p.start()
for p in processes:
p.join()

listener.stop()

十四、日志最佳实践

1. 使用合适的日志级别
2. 记录有意义的信息
3. 避免记录敏感信息(密码、密钥等)
4. 使用结构化日志便于分析
5. 配置日志轮转避免磁盘满
6. 在生产环境使用INFO或WARNING级别
7. 为不同模块使用不同的logger
8. 记录异常时包含堆栈跟踪
9. 使用上下文信息丰富日志
10. 定期审查和清理日志

十五、日志分析工具

1. ELK Stack (Elasticsearch, Logstash, Kibana)
2. Splunk
3. Graylog
4. Fluentd
5. Loki

十六、总结

Python的logging模块提供了强大而灵活的日志记录功能。通过合理配置logger、handler、formatter和filter,可以构建适合不同场景的日志系统。结合日志轮转、结构化日志和日志分析工具,可以有效地监控和调试应用程序。

http://www.rkmt.cn/news/1417096.html

相关文章:

  • ATtiny85软件PWM驱动RGB氛围灯:中断、防抖与电源设计全解析
  • 从PID控制到反应轮:自制自平衡立方体的完整工程实践
  • 别再纠结了!gtsummary vs compareGroups:R语言画基线表到底该选谁?
  • 大型项目弯头厂家选型参考:五个决策步骤与案例解析 - 速递信息
  • 6G智能超表面优化:从信道可编程到能效与安全性能提升
  • 别再死记ResNet结构了!用PyTorch手搓一个ResNet-18,带你彻底搞懂残差连接
  • 基于Arduino与NRF24L01的无线遥控车DIY全攻略:从电路设计到代码实现
  • 2026年5月电磁流量计生产厂家推荐——污水测量哪款能真正获得市场认可?
  • 从‘像素对错’到‘结构好坏’:一个迭代细化技巧,让你的模型预测自己纠错(Topology Loss实战)
  • SAP PS项目模板搭建保姆级教程:从CJ91到CN13,手把手教你构建企业核心资产
  • 创客教育实战:从电路设计到生活应用的跨学科项目指南
  • 移动端电声乐器音频处理:从DSP算法到硬件接口的完整实现
  • Arduino红外传感器触发OLED显示系统:实现智能感应与节能显示
  • Oracle 11g静默安装后,别忘了这几步:从创建用户到优化Redo Log的实战配置
  • IDEA生成UML类图保姆级教程:从快捷键到高级配置,看完就能用
  • 不只是安装:用 Geant4 B1 示例快速上手粒子物理模拟(Ubuntu 20.04 环境)
  • 3步搞定ADB驱动安装的终极方案:告别Windows下的Android调试噩梦
  • 2026乌鲁木齐公司注册,认准疆诚之家财税!专业靠谱,创业首选 - 小柏云
  • 理财最容易犯的四个错误
  • 十分钟构建AI智能体:自动化脚本实现稳定USDC收益
  • 保姆级教程:用Vue3全家桶+ElementPlus从零搭建一个仿微信网页聊天室(附完整源码)
  • 从实验室到车间:用ROS Melodic + AprilTag3实现工业AGV的二维码导航(附真实场景调参心得)
  • 宁波外墙干挂石材怎么选?幕墙工程选材与施工要点 - 速递信息
  • 别让米勒效应拖慢你的MOSFET!手把手教你用示波器实测开关波形与损耗
  • 支付审计追踪系统架构设计:从事件定义到防篡改的完整实践指南
  • 不只是数字签名!用Procmon深挖Win10文件属性选项卡消失的幕后元凶
  • 为ubuntu上的nodejs后端服务接入taotoken多模型聚合能力
  • 判断朋友可交性的八个观察维度
  • 从零设计智能植物浇水器:电路设计实战全流程解析
  • 从手机屏幕到汽车大灯:拆解‘光通量’在LED选型与照明设计中的实战指南