我是 ABin-阿斌:写一生代码,创一世佳话,筑一揽芳华。 如果小伙伴们觉得我的文章有点 feel ,那就点个赞再走哦。

文章目录

  • 前言
    • 1. 选择恰当的日志级别
    • 2. 日志要打印出方法的入参、出参
      • 正例如下:
    • 3. 选择合适的日志格式
    • 4. 遇到if...else...等条件时,每个分支首行都尽量打印日志
      • 正例:
    • 5.日志级别比较低时,进行日志开关判断
      • 正例:
    • 6. 不能直接使用日志系统(Log4j、Logback)中的 API,而是使用日志框架SLF4J中的API。
      • 正例:
    • 7. 建议使用参数占位{},而不是用+拼接
      • 反例:
      • 正例如下:
    • 8. 建议使用异步的方式来输出日志
    • 9. 不要使用e.printStackTrace()
      • 反例:
      • 正例:
    • 10. 异常日志不要只打一半,要输出全部错误信息![](https://img-blog.csdnimg.cn/img_convert/8c862ac7ac917c5bf6c5c5fc298805e9.png)
      • 反例1:
      • 反例2:
      • 正例:
    • 11. 禁止在线上环境开启 debug
    • 12.不要记录了异常,又抛出异常
      • 反例如下:
    • 13.避免重复打印日志
      • 反例如下:
      • 正例:
    • 14.日志文件分离
    • 15. 核心功能模块,建议打印较完整的日志

前言

  • 以下文章来源于:捡田螺的小男孩 ,作者:捡田螺的小男孩

  • 日志是快速定位问题的好帮手,是 撕逼和甩锅 的利器!打印好日志非常重要。今天我们来聊聊 日志打印 的15个好建议~

1. 选择恰当的日志级别

  • 常见的日志级别有 5 种,分别是: error、warn、info、debug、trace。日常开发中,我们需要选择恰当的日志级别,不要反手就是打印 info 哈~

  • error: 错误日志,指比较严重的错误,对正常业务有影响,需要 运维配置监控的

  • warn: 警告日志,一般的错误,对业务影响不大,但是需要 开发关注

  • info: 信息日志,记录排查问题的关键信息,如调用时间、出参入参等等;

  • debug: 用于开发 DEBUG 的,关键逻辑里面的运行时数据;

  • trace: 最详细的信息,一般这些信息只记录到日志文件中。

2. 日志要打印出方法的入参、出参

  • 我们并不需要打印很多很多日志,只需要打印可以 快速定位问题的有效日志。有效的日志,是甩锅的利器!

  • 哪些算得的上 有效关键 的日志呢?比如说,方法进来的时候,打印 入参。再然后呢,在方法返回的时候,就是 打印出参,返回值。入参的话,一般就是 userId或者bizSeq这些关键 信息。

正例如下:

public String testLogMethod(Document doc, Mode mode){log.debug(“method enter param:{}”,userId);String id = "666";log.debug(“method exit param:{}”,id);return id;
}

3. 选择合适的日志格式

  • 理想的日志格式,应当包括这些最基本的信息:如当前时间戳(一般毫秒精确度)、日志级别线程名字等等。
  • 在 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>
  • 如果我们的日志格式,连当前时间都沒有记录,那连请求的时间点都不知道了

4. 遇到if…else…等条件时,每个分支首行都尽量打印日志

  • 当你碰到 if…else…或者switch 这样的条件时,可以在分支的首行就打印日志,这样排查问题时,就可以通过日志,确定进入了哪个分支,代码逻辑更清晰,也更方便排查问题了。

正例:

if(user.isVip()){log.info("该用户是会员,Id:{},开始处理会员逻辑",user,getUserId());//会员逻辑
}else{log.info("该用户是非会员,Id:{},开始处理非会员逻辑",user,getUserId())//非会员逻辑
}

5.日志级别比较低时,进行日志开关判断

  • 对于 trace/debug 这些比较低的日志级别,必须进行日志级别的开关判断

正例:

User user = new User(666L, "公众号", "捡田螺的小男孩");if (log.isDebugEnabled()) {log.debug("userId is: {}", user.getId());
}
  • 因为当前有如下的日志代码:
logger.debug("Processing trade with id: " + id + " and symbol: " + symbol);
  • 如果 配置的日志级别是warn 的话,上述日志不会打印,但是会执行字符串拼接操作。如果 symbol 是对象, 还会执行toString()方法,浪费了系统资源,执行了上述操作。最终日志却没有打印,因此建议 加日志开关判断

6. 不能直接使用日志系统(Log4j、Logback)中的 API,而是使用日志框架SLF4J中的API。

  • SLF4J 是门面模式的日志框架,有利于维护和各个类的日志处理方式统一,并且可以在保证不修改代码的情况下,很方便的实现底层日志框架的更换。

正例:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;private static final Logger logger = LoggerFactory.getLogger(TianLuoBoy.class);

7. 建议使用参数占位{},而不是用+拼接

反例:

logger.info("Processing trade with id: " + id + " and symbol: " + symbol);
  • 上面的例子中,使用 + 操作符进行字符串的拼接,有一定的 性能损耗

正例如下:

logger.info("Processing trade with id: {} and symbol : {} ", id, symbol);
  • 我们使用了大括号 {} 来作为日志中的占位符,比于使用+操作符,更加优雅简洁。并且,相对于反例,使用占位符仅是替换动作,可以有效提升性能。

8. 建议使用异步的方式来输出日志

  • 日志最终会输出到文件或者其它输出流中的,IO性能会有要求的。如果异步,就可以显著提升IO性能。

  • 除非有特殊要求,要不然建议使用异步的方式来输出日志。以logback为例吧,要配置异步很简单,使用AsyncAppender就行

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

9. 不要使用e.printStackTrace()

反例:

try{// 业务代码处理
}catch(Exception e){e.printStackTrace();
}

正例:

try{  // 业务代码处理
}catch(Exception e){  log.error("你的程序有异常啦",e);
}
  • 理由:

    • e.printStackTrace(): 打印出的堆栈日志跟业务代码日志是交错混合在一起的,通常排查异常日志不太方便。
    • e.printStackTrace(): 语句产生的字符串记录的是堆栈信息,如果信息太长太多,字符串常量池所在的内存块没有空间了,即内存满了,那么,用户的请求就卡住啦~

10. 异常日志不要只打一半,要输出全部错误信息

反例1:

try {  //业务代码处理
} catch (Exception e) {  // 错误  LOG.error('你的程序有异常啦');
}
  • 异常e都没有打印出来,所以压根不知道出了什么类型的异常。

反例2:

try {//业务代码处理
} catch (Exception e) {// 错误LOG.error('你的程序有异常啦', e.getMessage());
}
  • e.getMessage() 不会记录详细的堆栈异常信息,只会记录错误基本描述信息,不利于排查问题。

正例:

try {//业务代码处理
} catch (Exception e) {// 错误LOG.error('你的程序有异常啦', e);
}

11. 禁止在线上环境开启 debug

  • 禁止在线上环境开启 debug,这一点非常重要。
  • 因为一般系统的 debug 日志会很多,并且各种框架中也大量使用 debug 的日志,线上开启 debug 不久可能会打满磁盘,影响业务系统的正常运行。

12.不要记录了异常,又抛出异常

反例如下:

log.error("IO exception", e);
throw new MyException(e);
  • 这样实现的话,通常会把栈信息打印两次。这是因为捕获了 MyException 异常的地方,还会再打印一次。

  • 这样的日志记录,或者包装后再抛出去,不要同时使用!否则你的日志看起来会让人很迷惑。

13.避免重复打印日志

  • 避免重复打印日志,酱紫会浪费磁盘空间。如果你已经有一行日志清楚表达了意思,避免再冗余打印

反例如下:

if(user.isVip()){log.info("该用户是会员,Id:{}",user,getUserId());//冗余,可以跟前面的日志合并一起log.info("开始处理会员逻辑,id:{}",user,getUserId());//会员逻辑
}else{//非会员逻辑
}
  • 如果你是使用log4j 日志框架,务必在 log4j.xml 中设置 additivity=false,因为可以避免重复打印日志

正例:

<logger name="com.taobao.dubbo.config" additivity="false">

14.日志文件分离

  • 我们可以把不同类型的日志分离出去,比如 access.log,或者 error 级别 error.log,都可以单独打印到一个文件里面。

  • 当然,也可以根据不同的业务模块,打印到不同的日志文件里,这样我们排查问题和做数据统计的时候,都会比较方便啦。

15. 核心功能模块,建议打印较完整的日志

  • 我们日常开发中,如果核心或者逻辑复杂的代码,建议添加详细的注释,以及较详细的日志。

  • 日志要多详细呢?脑洞一下,如果你的核心程序哪一步出错了,通过日志可以定位到,那就可以啦。

Java:如果优雅地打印出完美日志相关推荐

  1. 打印菱形图案用java如何做_Java打印出菱形图案

    Java打印出菱形图案 题目:打印出如下图案(菱形) * *** ****** ******** ****** *** * 程序分析:先把图形分成两部分来看待,前四行一个规律,后三行一个规律,利用双重 ...

  2. java使用for循环打印出所有的水仙花数

    import java.util.Scanner; class Shuixianhua {public static void main(String[] args) {//使用for循环打印出所有的 ...

  3. java用星星符号打印出一个直角三角形

    1 package debug; 2 3 public class Demo10 { 4 public static void main(String[] args) { 5 //用星星符号打印出一个 ...

  4. java 怎么优雅的写出代码_【Java】基础50:如何让写的代码像诗一样优雅?

    今天是刘小爱自学Java的第50天. 感谢你的观看,谢谢你. 话不多说,开始今天的学习: ‍ 一.Stream流引入 这个流和IO流中的流很容易弄混淆. 但是它们是两个完全不一样的概念,Stream流 ...

  5. 打印表格_Excel表格打印技巧,让你分分钟打印出完美表格!建议收藏!

    平时在工作中经常需要帮忙打印一些文件,但有时候打印出来的东西却并不是我们想要的...... 打印出来为什么没有标题? 不可以自己设置打印区域吗? 怎么把内容打印到一页纸上? 等等...... 如果你遇 ...

  6. java在屏幕上打印出乘法口诀,Java打印乘法口诀

    使用java打印乘法口诀: 1x1=1 1x2=2 2x2=4 1x3=3 2x3=6 3x3=9 1x4=4 2x4=8 3x4=12 4x4=16 1x5=5 2x5=10 3x5=15 4x5= ...

  7. java实心菱形_java打印出实心菱形与空心菱形

    /** * 实心菱形 */ public static void method8() { System.out.print("请输入实心菱形的行数:"); int n = in.n ...

  8. 如何优雅的打印日志?

    目录 一.背景 二.日志目录的设置 三.准备工作 1.建表 2.准备Springboot工程 3.日志目录定义 4.ThreadLocalHolder 5.BaseRequest 6.BaseResu ...

  9. java log.error_Logger.error打印错误异常的详细堆栈信息

    一.问题场景 使用Logger.error方法时只能打印出异常类型,无法打印出详细的堆栈信息,使得定位问题变得困难和不方便. 二.先放出结论 Logger类下有多个不同的error方法,根据传入参数的 ...

最新文章

  1. Visual Paradigm 教程[UML]:如何使用刻板印象和标记值?(下)
  2. 如何使ResNet优于EfficientNet?
  3. Python设计模式-解释器模式
  4. sed用法之批量添加nagios services.cfg监控项
  5. 这件事,阿里爱了10年
  6. lisp标注界址点号_(IP服务年终大盘点第二期)协会理事单位湖北高韬律师事务所完成韩国商标注册优先审查...
  7. 专家票选! 2020 年度 10 篇人工智能经典论文(1-5)
  8. PHPCMS后台框架实现思路
  9. Activity嵌套fragment大全,activity加载单个fragment,TabLayout+ViewPager实现多个fragment滑动效果
  10. 学习Java的相关知识
  11. django-rest-swagger显示接口备注内容
  12. 关于TCHAR和string对象的c.str()一些注意事项
  13. 印江中学2021高考成绩查询,贵州印江中学2021年排名
  14. fastrtext︱R语言使用facebook的fasttext快速文本分类算法
  15. MyEclipse10破解
  16. 年龄估计:Ordinal Regression
  17. electron-vue中调用系统屏幕键盘(linux与windows)
  18. 转福布斯荐75本经商必读
  19. 微信小程序页面跳转方式
  20. 微信服务号如何创建一个带参数的微信二维码?

热门文章

  1. java基于Springboot+vue的校园二手闲置商品交易平台系统 element
  2. 去丹东绿江村观光几月份合适,油菜花什么时候开,花期多久?
  3. 记录项目中git的一些用法
  4. 机械振动信号中的常用指标
  5. 电路分析——学习笔记(1.1)
  6. Resource not found问题
  7. 多媒体在计算机的应用,计算机多媒体在教学中的应用
  8. 11 Confluent_Kafka权威指南 第十一章:流计算
  9. jzoj5983. 【北大2019冬令营模拟2019.1.1】多边形 (组合数学)
  10. 高频通信电子线路—经典七管半导体超外差式调幅(AM)收音机(恒兴HX-6B)电路深度剖析介绍(上)