Java编码常见的Log日志打印问题
前言
本文总结了作者在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日志打印问题的更多相关文章
- android的Log日志打印管理工具类(一)
android的Log日志的打印管理工具类: package com.gzcivil.utils; import android.util.Log; /** * 日志打印管理 * * @author ...
- 超高逼格Log日志打印
代码地址如下:http://www.demodashi.com/demo/12646.html 前言 Log日志的打印一直是一个比较头疼的事,怎样才能让自己的log显示更多信息,怎样才能让自己的log ...
- Javascript 将 console.log 日志打印到 html 页面中
如何将 console.log() 打印的日志输出到 html 页面中 (function () { var old = console.log; var logger = document.getE ...
- 树莓派 log 日志 打印到 TXT
#include<stdio.h> #include <stdarg.h> #include <unistd.h> #include <stdint.h> ...
- java最简单实现Log打印和生成日志文件
导包 1.commons-logging.jar包 下载 2.log4j.jar包 下载 配置log4j 1.在src根目录下创建一个log4j.properties文件. 文件全部内容如下: log ...
- 大数据项目中js中代码和java中代码(解决Tomcat打印日志中文乱码)
Idea2018中集成Tomcat9导致OutPut乱码找到tomcat的安装目录,打开logging.properties文件,增加一行代码,覆盖默认设置,将日志编码格式修改为GBK.java.ut ...
- Xposed框架Hook Android应用的所有类方法打印Log日志
本文博客地址:https://blog.csdn.net/QQ1084283172/article/details/80954759 在进行Android程序的逆向分析的时候,经常需要Android程 ...
- java log日志的输出。
在Spring框架中添加日志功能: pom.xml <dependency> <groupId>log4j</groupId> <artifactId> ...
- java中关于log日志
博:http://zhw2527.iteye.com/blog/1006302 http://zhw2527.iteye.com/blog/1099658 在项目开发中,记录错误日志是一个很有必要功能 ...
随机推荐
- MySQL解压版的安装与配置
1.解压mysql-5.7.15-winx64.zip到D:\MySQL Server 5.7(你想安装的位置) 2.如果机器上安装过其他版本的mysql先删除环境变量PATH中的mysql路径,然后 ...
- Charles抓包(未完待续)
Charles是在 Mac 下常用的网络封包截取工具,在做移动开发时,我们为了调试与服务器端的网络通讯协议,常常需要截取网络封包来分析. Charles 通过将自己设置成系统的网络访问代理服务器,使得 ...
- IO流(2)—知识结构
结构: 注:此IO包下主要介绍: 节点流:(字节流)FileInputStream.FileOutputStream.(字符流)Filereader.FileWriter 处理流(缓冲流):(字节流) ...
- #define LT(a,b) ((a)<(b))
就是带参数的宏定义 LT是函数名 (a,b )是参数表((a)<(b))是表达式返回一个布尔类型的值
- seq_file学习(1)—— single_open
span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }.CodeMirror ...
- adb devices 找不到设备的解决方法
1.开启adb 2.查看设备时的报错 问题1:cannot connect to daemon 解决方法:找到占据5037端口的进城,并在“任务管理器”中依据“PID”查找到,解决进程 问题2:手机 ...
- Java8 利用Lambda处理List集合
List<User> list = new ArrayList<User>(); User user1 = new User("第一位","用户1 ...
- Thymeleaf-语法整理
Thymeleaf其他案例看其他网站 http://www.cnblogs.com/hjwublog/p/5051732.html http://blog.csdn.net/u012706811/ar ...
- Initialize a vector in C++ (5 different ways)
https://www.geeksforgeeks.org/initialize-a-vector-in-cpp-different-ways/ Following are different way ...
- Numba加速Python程序
众所周知,Python和Java一样是基于虚拟机的语言,并不是像C/C++那样将程序代码编译成机器语言再运行,而是解释一行执行一行,速度比较慢.使用Numba库的JIT技术编译以后,可以明显提高程序的 ...