1. Odoo日志系统架构解析
在Odoo企业级ERP系统中,日志模块作为系统监控和故障排查的核心组件,其设计采用了Python标准库logging模块的扩展实现。logger组件作为日志系统的中枢神经,承担着日志记录、过滤和分发的关键职责。
1.1 核心日志组件构成
Odoo的日志系统主要由三个层级构成:
- Logger(记录器):负责捕获代码中的日志事件,每个模块拥有独立的logger实例
- Handler(处理器):决定日志的输出目的地(控制台/文件/网络等)
- Filter(过滤器):提供额外的日志过滤控制
典型配置示例:
python复制import logging
_logger = logging.getLogger(__name__)
def some_method(self):
_logger.debug("调试信息:%s", variable)
_logger.info("业务操作记录")
_logger.warning("异常情况提示")
_logger.error("严重错误信息")
1.2 日志级别深度剖析
Odoo支持标准的五级日志体系,但在实际企业应用中需要特别注意各级别的使用场景:
| 级别 | 数值 | 使用场景 |
|---|---|---|
| DEBUG | 10 | 开发调试时使用,记录变量状态、方法调用栈等详细信息 |
| INFO | 20 | 业务操作流水记录,如订单创建、用户登录等关键业务流程 |
| WARNING | 30 | 非预期但可处理的异常情况,如API调用超时后重试成功 |
| ERROR | 40 | 需要人工干预的系统错误,如数据库连接失败、支付接口验证失败等 |
| CRITICAL | 50 | 系统级严重故障,通常会导致服务不可用,如内存溢出、关键进程崩溃等 |
重要提示:生产环境建议将全局级别设为WARNING以上,DEBUG级别日志可能包含敏感业务数据
2. 日志配置实战指南
2.1 配置文件详解
Odoo的日志配置主要通过openerp-server.conf文件实现,核心参数包括:
ini复制[options]
; 全局默认日志级别(小写)
log_level = info
; 细粒度日志控制(logger_name:LEVEL)
log_handler = :INFO,odoo.addons:DEBUG,werkzeug:WARNING
; 模块级特殊配置(小写级别)
logger_my_module = debug
logger_sale = warning
2.1.1 参数优先级规则
logger_<module_name>配置具有最高优先级log_handler中特定logger配置次之- 全局
log_level作为默认配置
典型冲突场景分析:
ini复制log_level = error
log_handler = :INFO
logger_my_module = debug
实际效果:
- my_module模块:输出DEBUG及以上日志(遵循logger_配置)
- 其他模块:仅输出ERROR日志(因log_level限制)
2.2 多环境配置策略
根据不同的部署环境,推荐采用以下配置方案:
开发环境配置:
ini复制log_level = debug
log_handler = :DEBUG
logfile = /var/log/odoo/odoo_dev.log
测试环境配置:
ini复制log_level = info
log_handler = :INFO,odoo.addons:DEBUG
logfile = /var/log/odoo/odoo_test.log
生产环境配置:
ini复制log_level = warning
log_handler = :ERROR,odoo.addons:WARNING
syslog = True # 启用系统日志集成
log_db = True # 启用数据库日志存储
3. 高级日志管理技巧
3.1 日志上下文增强
在Odoo 14+版本中,可以通过自定义日志过滤器添加上下文信息:
python复制class ContextFilter(logging.Filter):
def filter(self, record):
record.dbname = getattr(threading.current_thread(), 'dbname', '?')
record.uid = getattr(threading.current_thread(), 'uid', '?')
return True
_logger.addFilter(ContextFilter())
配置日志格式显示额外信息:
ini复制log_format = %(asctime)s %(dbname)s %(uid)s %(levelname)s %(message)s
3.2 性能敏感场景优化
对于高频调用的方法,建议采用以下优化模式:
python复制# 不推荐写法(即使不输出也会执行字符串拼接)
_logger.debug("处理订单 %s 耗时 %.2fms" % (order_id, duration))
# 推荐写法(先检查日志级别)
if _logger.isEnabledFor(logging.DEBUG):
_logger.debug("处理订单 %s 耗时 %.2fms", order_id, duration)
3.3 日志文件轮转配置
对于长期运行的生产系统,必须配置日志轮转防止磁盘爆满:
ini复制logrotate = True
logrotate_count = 30 # 保留30个历史日志文件
logrotate_size = 104857600 # 单个文件最大100MB
4. 常见问题排查手册
4.1 日志不输出问题排查流程
- 确认当前生效配置:
bash复制
ps aux | grep odoo | grep conf - 检查logger层级关系:
python复制import logging logging.getLogger('odoo').getEffectiveLevel() - 验证handler配置:
python复制logger = logging.getLogger('odoo.addons') for h in logger.handlers: print(h, h.level)
4.2 典型配置误区
误区1:同时设置log_level=error和log_handler=:INFO
- 现象:仅ERROR级别日志可见
- 原因:logger级别优先于handler级别过滤
- 解决方案:保持logger级别≤handler级别
误区2:模块配置未生效
- 检查点:
- 模块名拼写是否正确(区分大小写)
- 配置是否放在正确的[options]段落
- 是否有多份配置文件冲突
4.3 性能监控指标
建议对日志系统本身进行监控:
| 指标 | 预警阈值 | 监控工具示例 |
|---|---|---|
| 日志写入延迟 | >100ms/条 | NewRelic自定义指标 |
| ERROR日志频率 | >10条/分钟 | ELK聚合查询 |
| 日志文件增长速率 | >50MB/小时 | Zabbix文件监控 |
| 日志处理线程CPU占用 | >30%持续5分钟 | Prometheus+Grafana |
5. 企业级日志方案集成
5.1 与ELK栈集成方案
- 安装Filebeat收集日志:
yaml复制filebeat.inputs:
- type: log
paths:
- /var/log/odoo/*.log
fields:
app: odoo
env: production
- Logstash解析配置:
ruby复制filter {
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{WORD:dbname} %{NUMBER:uid} %{LOGLEVEL:loglevel} %{GREEDYDATA:message}" }
}
date {
match => [ "timestamp", "ISO8601" ]
}
}
5.2 数据库日志存储优化
启用log_db后需注意:
sql复制-- 定期清理旧日志
CREATE EVENT purge_odoo_logs
ON SCHEDULE EVERY 1 DAY
DO
DELETE FROM ir_logging WHERE create_date < NOW() - INTERVAL 30 DAY;
-- 添加索引提高查询效率
CREATE INDEX ir_logging_level_idx ON ir_logging(level);
CREATE INDEX ir_logging_create_date_idx ON ir_logging(create_date);
5.3 安全审计日志规范
对于需要审计的关键操作,建议单独建立审计日志流:
python复制audit_logger = logging.getLogger('odoo.audit')
audit_handler = logging.FileHandler('/var/log/odoo/audit.log')
audit_handler.setFormatter(logging.Formatter('%(asctime)s %(message)s'))
audit_logger.addHandler(audit_handler)
audit_logger.propagate = False # 避免重复记录
def log_audit_trail(user_id, action, model, record_id):
audit_logger.info(
"用户 %s 执行 %s 操作 %s#%s",
user_id, action, model, record_id
)
