16 October 2016

Nutz 的日志模块提供统一调用接口,再适配具体输出实现。阅读这层代码,重点是业务代码怎样取得 logger,以及运行时怎样选择可用适配器。以下固定使用 1.b.53,适配器列表与优先级不能跨版本直接推断。

三层职责

类型 职责
Logs 静态工厂与适配器选择
Log 日志级别判断及输出方法
LogAdapter 根据名称返回 Log,接口方法为 getLogger
import org.nutz.log.Log;
import org.nutz.log.Logs;

public class ExampleService {
    private static final Log log = Logs.getLog(ExampleService.class);
    public void run() {
        log.info("task started");
    }
}

显式传入类名比较直观。Logs.get() 还会通过当前调用栈推导名称,不能将它和不存在的 Logs.get(Class) 重载混写。

默认选择有明确版本范围

1.b.53 的 Logs.init 通过 SimplePluginManager 依次尝试 Log4jLogAdapter 和 SystemLogAdapter。可用性检测决定实际使用哪个,而不是看到 classpath 里有某个日志 jar 就认定一定生效。后续版本可能支持其他适配器,应查看对应实现。

Logs.setAdapter 可以显式设置适配器,但已有代码保存的 Log 引用未必会随之后续切换;应在初始化时统一决定。NOP_ADAPTER 提供无输出实现,是空对象策略,不是一个“没有实现完”的异常分支。

日志外观仍有维护成本

业务依赖统一接口,有利于隔离具体实现,但桥接和适配器也可能形成重复输出或循环。排查时确认实际绑定、配置加载及调用路径,避免同时添加多套桥接来碰运气。

日志级别、异常堆栈和上下文决定定位问题的价值。大量日志也会消耗 IO,输出内容还可能包含敏感数据,所以需要与业务观测目标一起设计,而不是只确认能打印一行文字。

参考:Nutz 1.b.53 Logs 源码。





blog comments powered by Disqus
Fork me on GitHub