1. 使用门面模式的日志框架
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger LOGGER = LoggerFactory.getLogger(Abc.class);
2. 日志工具对象logger应声明为private static final
- 声明为private是出于安全性考虑,防止logger对象被其他类非法使用。
- 声明为static是为了防止重复new出logger对象,同时防止logger被序列化,造成安全风险,出于资源利用的考虑,LOGGER的构造方法参数是Class,决定了LOGGER是根据类的结构来进行区分日志,所以一个类只要一个LOGGER就可以了,故static。
- 声明为final是因为在类的生命周期内无需变更logger,只是记录该类的信息。
3. “+”来连接字符串,既不利于阅读,同时消耗了内存(heap memory),应该使用占位符:
if (logger.isDebugEnabled()) {
logger.debug("Processing trade with id: " + id + " and symbol: " + symbol);
}
正例:(占位符)
logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);
4. 日志内容与日志级别相符合
DEBUG
或者TRACE
级别,比如方法调用参数,网络连接具体信息,一般是开发者调试程序使用,线上非特殊情况关闭这些日志
INFO
级别,一般是比较重要却没有风险的信息,如初始化环境、参数,清理环境,定时任务执行,远程调用第一次连接成功
WARN
级别,有可能有风险又不影响系统继续执行的错误,比如系统参数配置不正确,用户请求的参数不正确(要输出具体参数方便排查),或者某些耗性能的场景,比如一次请求执行太久、一条sql执行超过两秒,某些第三方调用失败,不太可能被运行的if分支等
ERROR
级别,用于程序出错打印堆栈信息,不应该用于输出程序问题之外的其他信息。
5. 记录异常日志:
log.error(e);
log.error(e, e);
log.error(""+ e);
log.error(e.toString());
log.error(e.getMessage());
log.error(null, e);
log.error("", e);
log.error("{}", e);
log.error("{}", e.getMessage());
log.error("Error reading configuration file: " + e);
log.error("Error reading configuration file: "+ e.getMessage());
log.error("Error reading configuration file", e); // 推荐使用
必须包含e,不要e.getMessage(),或者e.toString()。不然会损失重要的StackTrace信息,难以定位问题发生地方。
6.不允许记录日志之后又抛出异常,因为有全局异常处理,会二次记录日志:
catch (Exception e) {
logger.error("上传文件异常:\n" + e.getMessage());
throw new ScException(ScErrorCode.CANNOT_SAVE_FILE_EXCEPTION, e);
}
7. 不要出现System print(包括System.out.println和System.error.println)语句。
推荐使用日志的info调试,例如logger.info("hello world!”)。
网友评论