java中log占位符,使用 log 占位符便利日志输出

在开发活动中, 记日志是一个很常见的操作. 记日志经常涉及到拼接字符串, 因为我们常常需要把参数的值输出出来, 同时拼上字样的提示, 这样后续查看时才好知道发生了什么.

比如这样:

package net.xiaogd.sample.mybatis.controller;

import lombok.extern.slf4j.Slf4j;

import net.xiaogd.sample.mybatis.entity.User;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.ModelAttribute;

import org.springframework.web.bind.annotation.RestController;

@Slf4j

@RestController

public class LogController {

@GetMapping("/hello")

public String hello(@ModelAttribute User user) {

log.info("username: " + user.getUsername() + " , age: " + user.getAge());

return "hello there";

}

}

这样的方式一旦参数多了, 就会显得很凌乱, 写起来也不方便, 看上去也是支离破碎的.

很多人可能因此就不去记日志了, 或者只记很少的变量的值, 给后续的排查问题就带来了麻烦.

在前面的一篇 利用 String format 方法及占位符优雅拼接字符串 里, 提到了可以使用 format 方法结合 %X 占位符的方式, 那种方式自然也是可以用在日志里面的:

@GetMapping("/hello")

public String hello(@ModelAttribute User user) {

log.info(String.format("username: %s, age: %d"), user.getUsername(), user.getAge());

return "hello there";

}

这种比前一种方式要优雅一点, 不过呢, 却还是要用到 String.format 方法, 并且需要注意变量的类型, 而现在基本上很多的日志框架都直接支持一种占位符的写法, 与 String.format 中的不同, 可能相对来说还更简单一点, 只是它必须依赖于日志框架相关代码, 且只能用于日志输出中, 这样的方式就是利用大括号 {} 这种占位符(也称为 格式化锚点(formatting anchor))的写法:

@GetMapping("/hello")

public String hello(@ModelAttribute User user) {

log.info("username: {}, age: {}", user.getUsername(), user.getAge());

return "hello there";

}

这种写法用户也不需要关注变量的类型, 如果有三个或更多的变量值要输出, 就相应多写几个 {}, 以及多传几个对应变量即可:

注: 方法的第二个参数是可变长参数, 因此可以传多个.

有了这种写法的支持, 就可以一口气写完要输出的日志信息, 而要拼接的变量就用 {} 暂时代替, 避免了用 + 号拼接的繁琐.

这样的使用占位符的写法还有一个潜在的好处, 就是性能的提升. 如果配置的日志级别是不输出 info 级别的日志, 那么相应的字符串的拼接与替换就不会发生, 可变长参数数组也不会生成.

而如果使用 + 号式之类的写法, 就不能得到这个好处了, 字符串传入之前就已经被拼接了, 最后因为日志级别的原因又没有输出的话, 无疑是一种浪费.

最后, 如果是 error 日志, 还支持一种特别的写法, 可以把异常传给最后一个参数, 除了替换占位符输出你的异常信息外, 它还会把异常栈整个打印出来, 避免了你自己去调用 e.printStackTrace:

package net.xiaogd.sample.mybatis.service;

import lombok.extern.slf4j.Slf4j;

import net.xiaogd.sample.mybatis.entity.User;

import java.io.IOException;

import java.io.InputStreamReader;

import java.nio.charset.StandardCharsets;

import java.util.List;

@Slf4j

public class UserServiceImpl implements UserService {

@Override

public List fetchUserList() {

String fileName = "user-list.txt";

InputStreamReader reader = new InputStreamReader(getClass().getResourceAsStream(fileName), StandardCharsets.UTF_8);

try {

int c = reader.read();

} catch (IOException e) {

log.error("error while reading {}", fileName, e);

}

// todo

return null;

}

}

注意以上, 错误信息只有一个占位符, 但后面跟了两个变量, 其中最后的变量是 Throwable 类型的, 只有第一个变量值才参与字符串的拼接.

当最后的变量是 Throwable 类型时, log 框架会将其当作异常栈输出, 类似于这个调用 public void error(String msg, Throwable t);, 异常变量需置于最后.

另注: 此用法需要相应的日志版本的支持, 参见这里: http://www.slf4j.org/faq.html#paramException, 适用 1.6.0 版本及以上, 相应的日志实现也需支持.

以上例子说明了在 log 异常时, 同样可以使用占位符的写法, 同时兼容原有的打印异常栈的写法, 这些都算是方便我们输出异常日志的一些技巧, 关于使用 {} 占位符输出日志的介绍就到这里.

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值