什么是好的日志系统?
一个好的日志系统应该满足哪些要求? 作为一个工作一年多的菜鸟,我希望它能满足以下要求
- 可拓展: 为了尽可能简单,目前使用log4j,但是以后出于性能或其他原因考虑,我希望能够在对代码进行尽可能少的改动下替换为logback/log4j2等.
- 输出信息精炼完整: 我期望通过这条日志获取尽可能多的信息,最好情况是只看到这条日志而不需要再去翻阅代码就能找到问题所在.
可拓展的需求分析
- 门面模式
为一组子系统提供一个统一的接口,client仅操作这个高层次的接口,不会和顶层子系统接触
对可拓展的描述很符合一种设计模式的定义—门面模式,在日志系统这个场景中,log4j,logback,log4j2都是子系统,幸运的是Java已经有slf4j这套优秀的框架实现了这个功能.
- 要替换时尽可能少的改动代码
如果以这样的方式为每个类都定义一个Logger,会有如下问题
//最简化的情况
org.slf4j.Logger logger=new Log4jLoggerFactory().getLogger(XXX.class)
- 在项目很大的情况下,就会很有很多Logger,定义这么多logger又没有实际的作用,还会略微影响系统性能
- 如果进行日志系统的替换,所有定义Logger的地方都要改动,不符合我的预期
因此预期是封装一个静态方法提供org.slf4j.Logger,之后要换直接改动这个静态方法即可.
public static Logger getLogger() {
return log4jLogFactory.getLogger("logger");
}
输出信息精炼完整
- 获取尽可能多的信息
通过一条日志,我需要得知什么信息
- 时间: 必不可少
- 线程: 如果你对每个线程设置了有意义的线程名,那么通过线程名就可以缩小问题可能原因的范围
- 日志等级: 便于筛选重要的日志
- 代码位置: 输出这条日志的代码所在文件,方法,行号. 如果系统中相似日志很多,这些信息可以帮你快速找到问题位置
为了以上要求,设置了如下输出格式
# eg. 2019-07-22 19:45:23,274 [main] [logger] [INFO] [LoggerManager.main(LoggerManager.java:14)]- test log
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c] [%p] [%C{1}.%M(%F:%L)]- %m%n
- 信息精炼完整
每条日志都需要有意义,通过这条信息我可以了解
- 系统的初始化信息 eg. 数据库初始化状态,服务连接状态
- 运行过程中出现的预期/非预期流程 eg. 非法参数,并发调用
- 重要业务的执行流程 eg. 支付流程
以上就要求在编写日志时就要系统化,规范化,对于这块我也在慢慢探索,推荐阅读如何使错误日志更加方便排查问题
放码
pom依赖
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
log4j.properties(输出格式参见Log4j输出格式控制,log4j参见Log4j探秘)
log4j.rootCategory=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# eg. 2019-07-22 19:45:23,274 [main] [logger] [INFO] [LoggerManager.main(LoggerManager.java:14)]- test log
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c] [%p] [%C{1}.%M(%F:%L)]- %m%n
LoggerManager
import org.slf4j.Logger;
import org.slf4j.impl.Log4jLoggerFactory;
public class LoggerManager {
private static final Log4jLoggerFactory log4jLogFactory = new Log4jLoggerFactory();
public static Logger getLogger() {
return log4jLogFactory.getLogger("logger");
}
public static void main(String[] args) {
getLogger().info("test log");
}
}
具体代码我的github
网友评论