前言

本文总结了作者在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. MySQL解压版的安装与配置

    1.解压mysql-5.7.15-winx64.zip到D:\MySQL Server 5.7(你想安装的位置) 2.如果机器上安装过其他版本的mysql先删除环境变量PATH中的mysql路径,然后 ...

  2. Charles抓包(未完待续)

    Charles是在 Mac 下常用的网络封包截取工具,在做移动开发时,我们为了调试与服务器端的网络通讯协议,常常需要截取网络封包来分析. Charles 通过将自己设置成系统的网络访问代理服务器,使得 ...

  3. IO流(2)—知识结构

    结构: 注:此IO包下主要介绍: 节点流:(字节流)FileInputStream.FileOutputStream.(字符流)Filereader.FileWriter 处理流(缓冲流):(字节流) ...

  4. #define LT(a,b) ((a)<(b))

    就是带参数的宏定义 LT是函数名 (a,b )是参数表((a)<(b))是表达式返回一个布尔类型的值

  5. seq_file学习(1)—— single_open

    span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }.CodeMirror ...

  6. adb devices 找不到设备的解决方法

    1.开启adb 2.查看设备时的报错 问题1:cannot connect  to daemon 解决方法:找到占据5037端口的进城,并在“任务管理器”中依据“PID”查找到,解决进程 问题2:手机 ...

  7. Java8 利用Lambda处理List集合

    List<User> list = new ArrayList<User>(); User user1 = new User("第一位","用户1 ...

  8. Thymeleaf-语法整理

    Thymeleaf其他案例看其他网站 http://www.cnblogs.com/hjwublog/p/5051732.html http://blog.csdn.net/u012706811/ar ...

  9. Initialize a vector in C++ (5 different ways)

    https://www.geeksforgeeks.org/initialize-a-vector-in-cpp-different-ways/ Following are different way ...

  10. Numba加速Python程序

    众所周知,Python和Java一样是基于虚拟机的语言,并不是像C/C++那样将程序代码编译成机器语言再运行,而是解释一行执行一行,速度比较慢.使用Numba库的JIT技术编译以后,可以明显提高程序的 ...