在开发过程中,打印日志是必不可少的,因为日志关乎于应用的问题排查、应用监控等。现在打印日志一般都是使用 slf4j,因为使用日志门面,有助于打印方式统一,即使后面更换日志框架,也非常方便。在 《Java 开发手册》中也有相关的规约。

所以在开发中,一般使用下面这种方式来打印日志。

LOGGER.info("print: {}", "this is the log");

不过有的应用会将 LOGGER 再封装一下,最终写成:

LoggerUtil.info(LOGGER, "print: {}", "this is the log");

本文的主要内容是讨论为什么要封装,有没有必要封装,以及怎样封装,如果小伙伴有更好的建议,可以提出,进行互相学习。

为什么要封装

很多人觉得 slf4j 本来就是日志门面,已经封装的很好了,为什么要多此一举,再额外封装一个 LoggerUtil 呢?

其实这块也是在开发规范中有说明的:

如果不进行封装,则会写成下面这种:

if (LOGGER.isInfoEnabled()) {
LOGGER.info("print: {}", "this is the log");
}

所以,一般封装是将 if 判断这块逻辑统一封装为一个工具类。

可能到这里还有小伙伴不是很理解为什么要加 if 判断,可以看下下面这段代码:

可以看出转换逻辑这块相对比较复杂、耗时,在这里只是模拟的场景,实际使用可能会有其他情况,比如打印方法的出参入参、计算耗时等:

LOGGER.info("xxx 方法请求参数为:{}", JSON.toJSONString(req));
LOGGER.info("xxx 执行耗时:{}ms", System.currentTimeMillis() - startTime);

在某些场景下为了提高性能,需要关闭日志,比如大促,秒杀等等。

说到这里相信小伙伴已经看出问题了,因为这样写的话,当我关闭日志打印时,只是关闭了磁盘输出,但是耗时逻辑依然会继续执行。

# 日志级别调整到 error
logging.level.com.liuzhihang=error

这也是为什么在开发规范中建议大家手写判断,虽然日志框架中帮我们进行了判断,那只是避免了打印输出日志,实际上像组装日志,序列化实例对象等等还是会被执行的。

当然如果当前应用只有个位数的 tps 或者 tpm 那完全没必要考虑这些,也没必要因噎废食,正常使用就行。

该怎样封装

为了避免每次都要 if 判断的问题,会将 if 模块封装为工具类:

上面的封装,有效避免了每次都需要进行判断,只需要将代码中的打印日志换成 LogUtil 即可:

但是这种情况只能避免打印既有参数时的 if 判断,对方法类型的没有作用,这里就需要使用 Supplier

实际使用效果:

以上仅为一种封装方式,其他的封装可以自行考虑,比如整个日志框架都封装。

其他使用

这部分封装在 log4j-api-2.17.2.jar 中也有所体现,只不过 slf4j 里面并没有封装 Supplier 支持,详细实现可以自行阅读源码。

那为什么 slf4j 不支持,其实也是有讨论的,可以看 issue #70,里面进行了一系列讨论。

最终结果是在 2.0 支持了 Fluent Logging API 语法。

slf4j 2.0 使用

<!-- slf4j 2.0 依赖 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.0</version>
</dependency>

按照官方文档的使用案例直接使用即可:

logger.atDebug()
.setMessage("Temperature set to {}. Old value was {}.")
.addArgument(() -> t16()).addArgument(oldT)
.log();

为什么要这样写,只能说是人家的 API 设计就是如此,当然也有其他的考虑,可以看看 github issue。具体使用哪种,用不用封装等等,这些都是根据自己的实际情况来使用。

打印 Logger 日志时,需不需要再封装一下工具类?的更多相关文章

  1. Springboot + SLF4j + Log4j2 打印异常日志时,耗时要5-6秒

    1.使用jps -l 查看springboot项目的进程ID 2.使用命令jstack -l 进程ID > log.txt 打印堆栈信息到文件,内容如下: "http-nio-8065 ...

  2. Log4j2打印一行日志时返回本行日志的字符串

    import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.impl.Log4jLogEvent; impo ...

  3. Aop 打印参数日志时,出现参数序列化异常。It is illegal to call this method if the current request is not in asynchron

    错误信息: nested exception is java.lang.IllegalStateException: It is illegal to call this method if the ...

  4. 【Android工具类】用户输入非法内容时的震动与动画提示——EditTextShakeHelper工具类介绍

    转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 当用户在EditText中输入为空或者是数据异常的时候,我们能够使用Toast来提醒用户,除此之外,我们还能 ...

  5. Logger日志打印规范

    首先来看一下比较常用的Logger日志级别(部分未列出): error - 运行期错误日志记录,应该有专门的error日志文件.: warn - 警告信息,如程序调用了一个即将作废的接口,接口的不当使 ...

  6. 深入理解Logger日志——框架绑定原理

    深入理解Logger日志--框架绑定原理 说到Logger日志的动态绑定,主要归功与Slf4j,在之前的文章也说过,Slf4j是类似于Apache Common-Logging,英文为Simple L ...

  7. java.util.logging.Logger日志生成过程浅析 (转)

    http://www.tuicool.com/articles/vy6Zrye ****************************************** java.util.logging ...

  8. Android Logger日志系统

    文件夹 文件夹 前言 执行时库层日志库liblog 源代码分析 CC日志写入接口 Java日志写入接口 logcat工具分析 基础数据结构 初始化过程 日志记录的读取过程 前言 该篇文章是我的读书和实 ...

  9. python logger日志通用配置文件

    阅读须知⚠️ 1.示例代码可直接放在项目py文件中即可使用 2.project_name,logfile_name变量需根据你的项目进行修改 3.日志输出格式format选择(可根据你的需要替换或修改 ...

随机推荐

  1. surging作者出具压测结果

    前言 首先回应下@wen-wen 所贴的压测报告,我也把我和客户压测碰到的问题,和压测结果贴出来,这个结果是由客户提供的.不会有任何的舞弊手脚问题 问题一:Task.Run慎用 首先在最新的社区版本已 ...

  2. day07 聊天室-1_集合

    聊天室(续) 实现服务端发送消息给客户端 在服务端通过Socket获取输出流,客户端获取输入流,实现服务端将消息发送给客户端. 这里让服务端直接将客户端发送过来的消息再回复给客户端来进行测试. 服务端 ...

  3. osi七层与TCP\IP协议

    层次划分的方法 1.网络的每层应当具有相对独立的功能(便于排错)这个功能用不了必然是你这层处理问题 2.梳理功能之间的关系,使上一个功能可以实现为另一个功能提供必要的服务,从而形成系统的层次结构.为提 ...

  4. SkyWalking分布式系统应用程序性能监控工具-上

    概述 微服务系统监控三要素 现在系统基本都是微服务架构,对于复杂微服务链路调用如下问题如何解决? 一个请求经过了这些服务后其中出现了一个调用失败的问题,如何定位问题发生的地方? 如何计算每个节点访问流 ...

  5. 金玉良缘易配而木石前盟难得|M1 Mac os(Apple Silicon)天生一对Python3开发环境搭建(集成深度学习框架Tensorflow/Pytorch)

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_189 笔者投入M1的怀抱已经有一段时间了,俗话说得好,但闻新人笑,不见旧人哭,Intel mac早已被束之高阁,而M1 mac已经 ...

  6. WindTerm:新一代开源免费的终端工具,GitHub星标6.6k+,太酷了!

    继 Tabby.Warp 后,今天再来给大家推荐一款终端神器--WindTerm,完全开源,在 GitHub 上已经收获 6.6k 的 star. https://github.com/kingToo ...

  7. you need to load the kernel first

    背景:在用第三方软件备份win10系统时,提示you need to load the kernel first 1.进BIOS把硬盘AHCI 模式调整成 SATA. 2.检查硬盘数据线是否插紧.主板 ...

  8. EPLAN 中的符号、元件、部件与设备之间的区别

    符号(Symbol):电气符号是电器设备(Electrical equipment)的一种图形表达,符号存放在符号库中,是广大电气工程师之间的交流语言,用来传递系统控制的设计思维的.将设计思维体现出来 ...

  9. PerfView专题 (第三篇):如何寻找 C# 中的 VirtualAlloc 内存泄漏

    一:背景 上一篇我们聊到了如何用 PerfView 去侦察 NTHeap 的内存泄漏,这种内存泄漏往往是用 C 的 malloc 或者 C++ 的 new 分配而不释放所造成的,这一篇我们来聊一下由 ...

  10. Oracle-视图,约束

    试图:试图是数据库对象之一视图在sql语句中体现的角色与表一致,但它不是一张真是存在的表,只是对应了一个查询语句的结果集当试图对应的子查询中含有函数或者表达式时,那么必须指定别名试图根据对应的子查询分 ...