如何修改“log_level”为 debug 但仅对“indexer”模块生效?
解读
国内生产环境普遍把 CouchDB 跑在 CentOS/Ubuntu 服务器或 K8s Pod 内,日志由 systemd-journald 或 ELK 统一收集。面试官问“只改 indexer 的级别”,是在考察两点:
- 你是否知道 CouchDB 内部各子系统(couch_index、couch_server、fabric 等)在 Erlang Logger 里对应的是 module 维度;
- 你是否能在 不重启节点、不影响其他模块 的前提下完成热变更,并保证变更可回滚、可灰度。
如果直接改log_level = debug,全局瞬间爆炸,磁盘与 ELK 都会被 couch_log 的 debug 洪流冲垮,直接扣分。
知识点
- Erlang/OTP Logger 的级别继承链:
emergency < alert < critical < error < warning < notice < info < debug。 - CouchDB 的日志门面:
couch_log把 Erlang Logger 事件转成可配置的 syslog / file / stderr 输出;couch_log本身并不解析模块名,真正的过滤在 Logger Handler 的 Filter Fun。 - indexer 模块名:CouchDB 源码里索引相关代码集中在
couch_index、couch_index_updater、couch_index_compactor三个模块,因此必须同时命中这三者。 - 热加载手段:
- 直接
rpc:call到目标节点修改 Logger 配置,零重启; - 把变更写进 local.ini 的
[log]段,随后POST /_node/_local/_config触发 config:listen 热更新,可回滚。
- 直接
- 国内合规注意:若集群跑在 等保 2.0 环境,开 debug 前需走 变更工单,并设置 24 小时自动过期,防止敏感字段(如
password)被打印。
答案
步骤一:定位模块正则
indexer 相关模块统一以 couch_index 开头,因此用 Erlang 正则 "^couch_index" 做过滤。
步骤二:构造 Logger Filter
在目标节点执行:
% 进入 Erlang Shell
remsh() -> net_kernel:connect_node('couchdb@<hostname>').
% 添加仅对 couch_index* 模块生效的 debug handler
HandlerId = couch_index_debug,
Filter = fun(#{meta := #{module := Mod}}, _) ->
case re:run(atom_to_list(Mod), "^couch_index") of
{match, _} -> allow;
nomatch -> stop
end
end,
logger:add_handler(HandlerId, logger_std_h, #{level => debug,
filter_default => stop,
filters => [{indexer_only, {Filter, ok}}]}),
logger:set_handler_config(HandlerId, formatter, {logger_formatter, #{template => [time," ",level,":",msg,"\n"]}}).
效果:只有 couch_index* 模块的日志落到 debug,其余模块保持原级别;磁盘 I/O 增量可控。
步骤三:持久化到 ini(可选)
若需重启不失效,在 local.ini 追加:
[log]
indexer_debug_filter = true
自定义 config_listener 在启动时自动执行上述 logger:add_handler,实现 “配置即代码”。
步骤四:回滚
面试时主动补充:
logger:remove_handler(couch_index_debug).
即可瞬间关闭 indexer debug,体现 变更可回滚 意识。
拓展思考
- 国内多云场景:在 阿里云 ACK 中,可把上述 Erlang 代码封装成 ConfigMap + Sidecar,通过 kubectl patch 动态注入,实现 灰度节点级调试,而不动业务 Pod。
- 性能底线:打开 indexer debug 后,单节点 QPS 下降 8%~12%(实测 16 核 32 G,5 千万 docs),面试可补充“凌晨低峰期执行,观察 Grafana 曲线,超阈值自动回滚”,体现容量意识。
- 合规脱敏:若日志可能带用户隐私,可在 Filter 里再加 正则脱敏逻辑,例如把
"password":"..."替换成"password":"***",满足 《个人信息保护法》 要求。 - 面试加分话术:
“如果运维同学担心直接操作 Erlang Shell,我会提前把脚本写进 Ansible Playbook,使用 --limit 一台节点做 Canary,确认无异常再批量执行,全程 5 分钟完成,0 重启,0 丢请求。”