加载中...

关于打印日志的建议


引言

平常自己try-catch异常的时候,经常为了方便就写一个e.printStackTrace,如果出现bug,虽然经过一段翻找也能定位到问题产生的位置,但是这其实只是因为自己平常练习的项目就是一个小demo,甚至是玩具级别的东西,直接e.printStackTrace也不会出现什么太大的问题。最近在学log4j2和slf4j的区别时,偶然看到e.printStackTrace是有缺陷的:

1、占用内存太多,容易造成死锁

  • 因为e.printStackTrace是直接打印到控制台上,产生的字符串要存放在字符串常量池中,而字符串常量池在JDK1.8之后存放在堆中,此时字符串常量池的大小受限于堆的大小,而如果e.printStackTrace产生的堆栈字符串信息如果太多,会导致内存空间严重不足,后续的请求就会因此被阻塞住了

2、日志交错混合,不易读

  • e.printStackTrace默认使用了System.err输出流进行输出,与System.out是两个不同的输出流,在打印时自然就形成了交叉。由于输出流是有缓冲区的,交叉的两个流会导致输出随机化

因而打印日志的时候,最好还是使用日志框架slf4j。以下是几个常见的日志打印建议,这里进行一个记录以备后续查找

日志打印的一些建议

1、日志打印要打印入参、出参关键信息

方法进来时,打印关键的入参信息,比如userId等,方法返回的时候,打印出参,例如:

public String getTestCaseInfo(Case case){
    log.debug("Case name:{}",case.name);
    String message = "2333";
    log.debug("return value:{}",message);
    return message;
}

2、配置合适的日志格式

参考的logback配置:

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <pattern>%d{HH:mm:ss.SSS} %-5level [%thread][%logger{0}] %m%n</pattern>
    </encoder>
</appender> 

日志应该包含诸如当前时间、线程名、日志级别等信息

3、日志级别较低时,利用开关判断是否打印

User user = new User(666L, "DestiNation");
if (log.isDebugEnabled()) {
    log.debug("userName: {}", user.getId());
}

4、使用slf4j日志框架API

slf4j是一个统一的门面式的日志框架,底层日志系统(log4j、log4j2、logback等)可以更换,一般而言,日志系统的接口都是有一定差别的,而使用slf4j可以在不更改代码的情况下,统一对外的调用接口

//方法一,注解
@slf4j

//方法二
private static final Logger logger = LoggerFactory.getLogger(Use.class);

5、使用占位符

这个不用多说,如果直接使用+号进行字符串拼接会造成性能损失(拼接字符串一般也是用StringBuffer或者StringBuilder),而使用占位符{}仅是替换操作,有效提升性能

logger.info("User id: {}, name : {} ", id, name); 

6、要输出全部的错误信息

不要用e.getMessage(),这个方法只会记录基本的错误描述,没有具体的堆栈信息,有可能不利于问题的排查,正确做法是直接输出e

try {
    //执行的业务代码
} catch (Exception e) {
    logger.error("catch exception: ", e);
}

7、日志文件分离

  • 根据不同的类型分离,如error、warn不同等级
  • 根据不同的业务分离

8、可以使用异步方式输出日志

日志输出要用到输出流,异步可以提升IO性能

logback参考配置:

<appender name="FILE_ASYNC" class="ch.qos.logback.classic.AsyncAppender">
    <appender-ref ref="ASYNC"/>
</appender>

文章作者: DestiNation
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 DestiNation !
  目录