前言

本文总结了作者在Java代码检视中遇到的一些关于日志打印的问题,并给出修改建议。因能力有限,难免存在错漏,欢迎指正。

. 不规范的异常打印

使用slf4j日志组件时,logger.error(与log.warn)接受Throwable参数,以打印异常名和详细的堆栈信息(可能内部调用e.printStackTrace())。

但书写打印语句时,需要注意格式。例如:

 logger.error("Best print: ", e);
logger.error("Good print: {}", e); //a.
logger.error("Bad print: " + e); //b. 或 + e.toString()
logger.error("Bad print: " + e.getMessage()); //c. 或: {}", e.getMessage())

a句仍可打印异常名和堆栈信息,但多输出一对花括号"{}";b句仅打印异常名;c句打印异常消息字符串。以空指针异常(Runtime异常)为例,b句打印"java.lang.NullPointerException",c句打印"null"(过于简陋)。

可使用如下正则表达式排查Java代码里不规范的异常打印:

^\s*[Ll][Oo][Gg](ger|GER)*\.(error|warn)\("(.+?)"\s*\+\s*(e|ex|e.getMessage\(\))\s*\);.*

该正则表达式可排查出形如上文b、c句的打印缺陷。考虑到实际代码书写风格的差异,会存在少量的漏判和误判。此外应注意,某些异常(如SQL或IO异常)可能泄露敏感信息,打印异常堆栈之前应根据网络安全要求做必要的”加工”。

二. 不规范的变量打印

使用slf4j日志组件打印变量时,建议使用”{}”占位符风格(C风格),而不是”+”拼接符(C++风格)。例如:

 logger.error("Country: {}, Province: {}, City: {}", ctry, prov, city); //占位符
logger.error("Country: "+ctry+", Province:" +prov +", City: "+city); //拼接符

显然,占位符风格更直观,而且不容易出现笔误——上面的拼接符语句有问题,谁能发现?

但最常见的变量打印问题,是打印时未使用占位符或拼接符:

 logger.error("print cannotBePrinted: ", cannotBePrinted);  //Wrong
logger.error("print canBePrinted: " + canBePrinted); //Good
logger.error("print canBePrinted: {}", canBePrinted); //Better

注意,cannotBePrinted或canBePrinted为非Throwable的变量。亦即,异常变量e不适用上述规则,但e.getMessage()适用。

可使用如下正则表达式排查Java代码里不规范的变量打印:

^\s*[Ll][Oo][Gg](ger|GER)*\.[a-zA-Z]{4,5}\("([^({})]+?)"\s*\,\s*([^e\s]|\w{2,})\s*\);.*

考虑到实际代码书写风格的差异,该正则表达式会存在漏判和误判。例如,"logger.error("Best print: ", ex);"会被误判。

. 多余的DEBUG级别判断

使用slf4j日志组件以Debug级别打印时,debug()方法内部会调用isDebugEnabled()判断调试级别。因此,下述代码里的判断没有必要:

if(logger.isDebugEnabled())
{
logger.debug("handleChanges end:{}:{}(ms) ", new Object[] {changes, useTime});
}

四. 日志对象logger的声明

一般建议日志对象logger声明为private static final。声明为private可防止logger对象被其他类非法使用。声明为static可防止重复new出logger对象,造成资源浪费;还可以防止logger被序列化,造成安全风险。声明为final是因为在类的生命周期内无需变更logger。

然而,实际编码中可根据使用场景稍作变通。例如,static final成员变量通常要求大写(如LOGGER),如果觉得大写别扭,可以去除final修饰。又如,期望logger对象可复用时,可如下定义:

protected final Logger logger = LoggerFactory.getLogger(this.getClass());

这样,子类可以直接使用继承来的logger对象打印输出,而无需再次getLogger()获取日志对象。

五. 日志级别应合理

如果日志不分级别或级别不合理,则定位问题时就无法快速有效地屏蔽大量低级别信息,给快速定位带来难度。建议与具体实现有关的日志使用debug级,一般的业务处理日志用info级,不影响业务进行的错误用warn级,而记录异常或重要错误的日志应为error级。

Java编码常见的Log日志打印问题的更多相关文章

  1. android的Log日志打印管理工具类(一)

    android的Log日志的打印管理工具类: package com.gzcivil.utils; import android.util.Log; /** * 日志打印管理 * * @author ...

  2. 超高逼格Log日志打印

    代码地址如下:http://www.demodashi.com/demo/12646.html 前言 Log日志的打印一直是一个比较头疼的事,怎样才能让自己的log显示更多信息,怎样才能让自己的log ...

  3. Javascript 将 console.log 日志打印到 html 页面中

    如何将 console.log() 打印的日志输出到 html 页面中 (function () { var old = console.log; var logger = document.getE ...

  4. 树莓派 log 日志 打印到 TXT

    #include<stdio.h> #include <stdarg.h> #include <unistd.h> #include <stdint.h> ...

  5. java最简单实现Log打印和生成日志文件

    导包 1.commons-logging.jar包 下载 2.log4j.jar包 下载 配置log4j 1.在src根目录下创建一个log4j.properties文件. 文件全部内容如下: log ...

  6. 大数据项目中js中代码和java中代码(解决Tomcat打印日志中文乱码)

    Idea2018中集成Tomcat9导致OutPut乱码找到tomcat的安装目录,打开logging.properties文件,增加一行代码,覆盖默认设置,将日志编码格式修改为GBK.java.ut ...

  7. Xposed框架Hook Android应用的所有类方法打印Log日志

    本文博客地址:https://blog.csdn.net/QQ1084283172/article/details/80954759 在进行Android程序的逆向分析的时候,经常需要Android程 ...

  8. java log日志的输出。

    在Spring框架中添加日志功能: pom.xml <dependency> <groupId>log4j</groupId> <artifactId> ...

  9. java中关于log日志

    博:http://zhw2527.iteye.com/blog/1006302 http://zhw2527.iteye.com/blog/1099658 在项目开发中,记录错误日志是一个很有必要功能 ...

随机推荐

  1. JS自学笔记03

    JS自学笔记03 1.函数练习: 如果函数所需参数为数组,在声明和定义时按照普通变量名书写参数列表,在编写函数体内容时体现其为一个数组即可,再传参时可以直接将具体的数组传进去 即 var max=ge ...

  2. arcgis 获得工具箱工具的个数

    import arcgisscripting import string; gp = arcgisscripting.create(9.3); ##多少个工具箱 toolboxes = gp.list ...

  3. SOFABolt 源码分析

    SOFABolt 是一个轻量级.高性能.易用的远程通信框架,基于netty4.1,由蚂蚁金服开源. 本系列博客会分析 SOFABolt 的使用姿势,设计方案及详细的源码解析.后续还会分析 SOFABo ...

  4. webpack Import 动态文件

    其实React Import scss 是非常简单的,比如一般写法import './PromotionPage.scss';,今天遇到一个样式需要覆盖,那么修改后的代码变成了: import './ ...

  5. hadoop ha 读取 activce状态的活动节点

    方式一 package com.xxx.hadoop; import com.sun.demo.jvmti.hprof.Tracker; import com.sun.xml.bind.util.Wh ...

  6. 解析XML出错,无法创建DOMDocument对象

    [问题] 加载XML配置文件时,创建DOMDocument对象总是失败,创建代码如下: MSXML2::IXMLDOMDocumentPtr pXMLDoc; MSXML2::IXMLDOMEleme ...

  7. Javascript 函数声明、函数表达式与匿名函数自执行表达式

    函数表达式(Function Expression)注:将函数定义为表达式语句(通常是变量赋值)的一部分 //func() 错误 var func = function () { } //func() ...

  8. WPF参考

    web 调用本地exe 程序,传入参数https://www.cnblogs.com/anjou/p/10045177.html WPF常用控件样式https://www.cnblogs.com/s0 ...

  9. uc浏览器视频缓存合并工具

    1.该软件用于将uc浏览器中零散的视频缓存切片处理成完整的视频文件. 开发语言:C#开发工具: Visual Studio 2017 Community 实例图示: 程序代码下载地址 windows ...

  10. 【PMP】易混淆知识点

    一.混淆概念 德尔菲技术 德尔菲技术是组织专家达成一致意见的一种方法.项目专家匿名参与其中.组织者使用调查问卷就重要的项目议题征询意见,然后对专家的答卷进行归纳,并把结果反馈给专家做进一步评论.这个过 ...