阅读量:77
CentOS环境下Python日志管理技巧
1. 利用Python内置logging模块实现基础日志配置
Python的logging模块是日志管理的核心工具,支持多级别(DEBUG、INFO、WARNING、ERROR、CRITICAL)、多处理器(控制台、文件、系统日志等)和灵活格式化。基础配置可通过basicConfig快速实现,例如:
import logging
logging.basicConfig(
level=logging.INFO, # 设置日志级别(生产环境建议用WARNING/ERROR)
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', # 统一日志格式
handlers=[
logging.FileHandler('app.log'), # 输出到文件
logging.StreamHandler() # 输出到控制台
]
)
logger = logging.getLogger(__name__) # 创建Logger对象
logger.info('Application started') # 记录日志
此配置适用于大多数简单场景,能满足基本的日志记录需求。
2. 实现日志轮转,避免日志文件过大
当日志文件持续增长时,需通过轮转机制分割文件。logging模块提供两种轮转处理器:
RotatingFileHandler:按文件大小轮转(如10MB/个),保留最近5个备份:from logging.handlers import RotatingFileHandler rotating_handler = RotatingFileHandler( 'app.log', maxBytes=10*1024*1024, # 10MB backupCount=5 # 保留5个备份 ) rotating_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) logger.addHandler(rotating_handler)TimedRotatingFileHandler:按时间轮转(如每天午夜),保留最近7天日志:from logging.handlers import TimedRotatingFileHandler timed_handler = TimedRotatingFileHandler( 'app.log', when='midnight', # 每天午夜 interval=1, # 每天 backupCount=7 # 保留7天 ) timed_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) logger.addHandler(timed_handler)
日志轮转能有效控制日志文件大小,防止磁盘空间耗尽。
3. 配置系统级日志工具(rsyslog/syslog)
将Python日志发送到系统级日志(如/var/log/messages或/var/log/syslog),便于统一管理。通过SysLogHandler实现:
from logging.handlers import SysLogHandler
syslog_handler = SysLogHandler(address='/dev/log') # CentOS系统日志地址
syslog_handler.setLevel(logging.WARNING) # 只发送WARNING及以上级别
syslog_formatter = logging.Formatter('%(name)s: %(levelname)s %(message)s')
syslog_handler.setFormatter(syslog_formatter)
logger.addHandler(syslog_handler)
系统级日志工具(如rsyslog)可进一步实现日志转发、存储和告警,适合分布式系统。
4. 使用logrotate工具自动化日志管理
logrotate是CentOS自带的日志轮转工具,可定期(如每天)压缩、删除旧日志。创建/etc/logrotate.d/myapp配置文件:
/var/log/myapp/*.log {
daily # 每天轮转
rotate 7 # 保留7个备份
compress # 压缩旧日志(如.gz格式)
missingok # 文件不存在时不报错
notifempty # 文件为空时不轮转
sharedscripts # 所有日志处理完成后执行脚本
postrotate
systemctl restart myapp.service # 可选:重启应用(如需重新打开日志文件)
endscript
}
logrotate会自动执行,无需手动干预,适合生产环境。
5. 集成第三方日志库提升效率
- Loguru:简化日志记录,支持自动轮转、异步日志和丰富格式化:
Loguru的API更简洁,适合快速开发。from loguru import logger logger.add("app.log", rotation="10 MB", retention="7 days", compression="zip") # 自动轮转+压缩 logger.info("This is a log message from Loguru") - Sentry:错误追踪工具,自动捕获异常并发送到云端:
Sentry能快速定位生产环境中的错误,提升排查效率。import sentry_sdk from sentry_sdk.integrations.logging import LoggingIntegration sentry_logging = LoggingIntegration( level=logging.INFO, # 捕获INFO及以上级别的日志 event_level=logging.ERROR # 发送ERROR及以上级别的事件到Sentry ) sentry_sdk.init(dsn="YOUR_SENTRY_DSN", integrations=[sentry_logging])
6. 结构化日志便于分析与可视化
使用JSON格式记录日志,便于ELK(Elasticsearch+Logstash+Kibana)、Splunk等工具解析和分析:
import json
import logging
from logging.handlers import SysLogHandler
class JSONFormatter(logging.Formatter):
def format(self, record):
log_entry = {
'timestamp': self.formatTime(record),
'level': record.levelname,
'message': record.getMessage(),
'module': record.module,
'function': record.funcName,
'line': record.lineno
}
return json.dumps(log_entry)
logger = logging.getLogger('json_logger')
logger.setLevel(logging.INFO)
syslog_handler = SysLogHandler(address=('localhost', 514)) # 发送到Logstash
syslog_handler.setFormatter(JSONFormatter())
logger.addHandler(syslog_handler)
logger.info('User logged in', extra={'user_id': 123, 'ip': '192.168.1.1'}) # 添加额外字段
结构化日志能提升日志分析的效率,帮助快速定位问题。
7. 合理设置日志级别与环境适配
- 开发环境:使用
DEBUG级别,记录详细信息(如变量值、函数调用),便于调试。 - 生产环境:使用
WARNING或ERROR级别,减少日志量,避免影响性能。
通过环境变量动态设置日志级别:
import os
import logging
log_level = os.getenv('LOG_LEVEL', 'INFO').upper() # 默认INFO
logging.basicConfig(level=log_level)
此方式适合容器化部署(如Docker),无需修改代码即可调整日志级别。
8. 保护日志文件安全
- 设置日志文件权限,仅允许必要用户访问:
chmod 640 /var/log/myapp/*.log # 所有者可读写,组用户可读 chown root:myapp /var/log/myapp/*.log # 归属到应用组 - 避免记录敏感信息(如密码、密钥),可通过
Filter过滤:日志安全是合规性(如GDPR)的要求,需重点关注。class SensitiveInfoFilter(logging.Filter): def filter(self, record): record.message = record.message.replace('password=123', 'password=*****') return True logger.addFilter(SensitiveInfoFilter())