使用slf4j

  1. 使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。

  2. 实现方式统一使用: Logback框架

打日志的正确方式

什么时候应该打日志

  1. 当你遇到问题的时候,只能通过debug功能来确定问题,你应该考虑打日志,良好的系统,是可以通过日志进行问题定为的。

  2. 当你碰到if…else 或者 switch这样的分支时,要在分支的首行打印日志,用来确定进入了哪个分支

  3. 经常以功能为核心进行开发,你应该在提交代码前,可以确定通过日志可以看到整个流程

基本格式

必须使用参数化信息的方式:

logger.debug("Processing trade with id:[{}] and symbol : [{}] ", id, symbol);

 

对于debug日志,必须判断是否为debug级别后,才进行使用:

if (logger.isDebugEnabled()) {
    logger.debug("Processing trade with id: " +id + " symbol: " + symbol);
}
不要进行字符串拼接,那样会产生很多String对象,占用空间,影响性能。

反例(不要这么做):

logger.debug("Processing trade with id: " + id + " symbol: " + symbol);

使用[]进行参数变量隔离

如有参数变量,应该写成如下写法:

logger.debug("Processing trade with id:[{}] and symbol : [{}] ", id, symbol);

这样的格式写法,可读性更好,对于排查问题更有帮助。

不同级别的使用

ERROR:

基本概念

影响到程序正常运行、当前请求正常运行的异常情况:

  1. 打开配置文件失败

  2. 所有第三方对接的异常(包括第三方返回错误码)

  3. 所有影响功能使用的异常,包括:SQLException和除了业务异常之外的所有异常(RuntimeException和Exception)

不应该出现的情况:

  1. 比如要使用Azure传图片,但是Azure未响应

如果有Throwable信息,需要记录完成的堆栈信息:

 
log.error("获取用户[{}]的用户信息时出错",userName,e);

说明

  1. 如果进行了抛出异常操作,请不要记录error日志,由最终处理方进行处理:

反例(不要这么做):

try{
    ....
}catch(Exception ex){
  String errorMessage=String.format("Error while reading information of user [%s]",userName);
  logger.error(errorMessage,ex);
  throw new UserServiceException(errorMessage,ex);
}
WARN

基本概念

不应该出现但是不影响程序、当前请求正常运行的异常情况:

  1. 有容错机制的时候出现的错误情况

  2. 找不到配置文件,但是系统能自动创建配置文件

即将接近临界值的时候,例如:

  1. 缓存池占用达到警告线

业务异常的记录,比如:

  1. 当接口抛出业务异常时,应该记录此异常

INFO:

基本概念

系统运行信息

  1. Service方法中对于系统/业务状态的变更

  2. 主要逻辑中的分步骤

外部接口部分

  1. 客户端请求参数(REST/WS)

  2. 调用第三方时的调用参数和调用结果

说明

  1. 并不是所有的service都进行出入口打点记录,单一、简单service是没有意义的(job除外,job需要记录开始和结束,)。
    反例(不要这么做):

    public List listByBaseType(Integer baseTypeId) {
    
       log.info("开始查询基地");
    BaseExample ex=new BaseExample();
    BaseExample.Criteria ctr = ex.createCriteria();
    ctr.andIsDeleteEqualTo(IsDelete.USE.getValue());
    Optionals.doIfPresent(baseTypeId, ctr::andBaseTypeIdEqualTo);
       log.info("查询基地结束");
    return baseRepository.selectByExample(ex); }
    对于复杂的业务逻辑,需要进行日志打点,以及埋点记录,比如电商系统中的下订单逻辑,以及OrderAction操作(业务状态变更)。
  2. 对于整个系统的提供出的接口(REST/WS),使用info记录入参

  3. 如果所有的service为SOA架构,那么可以看成是一个外部接口提供方,那么必须记录入参。

  4. 调用其他第三方服务时,所有的出参和入参是必须要记录的(因为你很难追溯第三方模块发生的问题)

DEBUG

基本概念

  1. 可以填写所有的想知道的相关信息(但不代表可以随便写,debug信息要有意义,最好有相关参数)

  2. 生产环境需要关闭DEBUG信息

  3. 如果在生产情况下需要开启DEBUG,需要使用开关进行管理,不能一直开启。

说明

如果代码中出现以下代码,可以进行优化:

//1. 获取用户基本薪资

//2. 获取用户休假情况

//3. 计算用户应得薪资
优化后的代码:
logger.debug("开始获取员工[{}] [{}]年基本薪资",employee,year);

logger.debug("获取员工[{}] [{}]年的基本薪资为[{}]",employee,year,basicSalary);
logger.debug("开始获取员工[{}] [{}]年[{}]月休假情况",employee,year,month); logger.debug("员工[{}][{}]年[{}]月年假/病假/事假为[{}]/[{}]/[{}]",employee,year,month,annualLeaveDays,sickLeaveDays,noPayLeaveDays);
logger.debug("开始计算员工[{}][{}]年[{}]月应得薪资",employee,year,month); logger.debug("员工[{}] [{}]年[{}]月应得薪资为[{}]",employee,year,month,actualSalary);
TRACE

基本概念

特别详细的系统运行完成信息,业务代码中,不要使用.(除非有特殊用意,否则请使用DEBUG级别替代)

规范示例说明

@Override
@Transactional
public void createUserAndBindMobile(@NotBlank String mobile, @NotNull User user) throws CreateConflictException{
    boolean debug = log.isDebugEnabled();
    if(debug){
        log.debug("开始创建用户并绑定手机号. args[mobile=[{}],user=[{}]]", mobile, LogObjects.toString(user));
    }
    try {
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        userRepository.insertSelective(user);
        if(debug){
            log.debug("创建用户信息成功. insertedUser=[{}]",LogObjects.toString(user));
        }
        UserMobileRelationship relationship = new UserMobileRelationship();
        relationship.setMobile(mobile);
        relationship.setOpenId(user.getOpenId());
        relationship.setCreateTime(new Date());
        relationship.setUpdateTime(new Date());
        userMobileRelationshipRepository.insertOnDuplicateKey(relationship);
        if(debug){
            log.debug("绑定手机成功. relationship=[{}]",LogObjects.toString(relationship));
        }
        log.info("创建用户并绑定手机号. userId=[{}],openId=[{}],mobile=[{}]",user.getId(),user.getOpenId(),mobile); // 如果考虑安全,手机号记得脱敏
    }catch(DuplicateKeyException e){
        log.info("创建用户并绑定手机号失败,已存在相同的用户. openId=[{}],mobile=[{}]",user.getOpenId(),mobile);
        throw new CreateConflictException("创建用户发生冲突, openid=[%s]",user.getOpenId());
    }
}

Java 代码里乱打日志了,这才是正确的打日志姿势的更多相关文章

  1. Java代码里利用Fiddler抓包调试设置

    Fiddler启动时已经将自己注册为系统的默认代理服务器,应用程序在访问网络时会去获取系统的默认代理,如果需要捕获java访问网络时的数据,只需要在启动java程序时设置代理服务器为Fiddler即可 ...

  2. spring mvc中,如何在 Java 代码里,获取 国际化 内容

    首先,在Spring的application.xml中定义 <bean id="messageSource" class="org.springframework. ...

  3. Java web开发,在一个jsp里放太多java代码的后果,摘自 java web轻量级开发面试教程

    现要做一个简单的登录页面,如果用户通过验证,会显示Welcome用户名的欢迎词,反之则返回登录页面让用户再次输入 这部分的完整代码是JSPDemo项目里的login.jsp,下面来分析一下关键代码. ...

  4. Android如何在java代码中设置margin

    习惯了直接在xml里设置margin(距离上下左右都是10dip),如: <ImageView android:layout_margin="10dip" android:s ...

  5. 转--Android如何在java代码中设置margin

    ========  3 在Java代码里设置button的margin(外边距)? 1.获取按钮的LayoutParams LinearLayout.LayoutParams layoutParams ...

  6. Android在java代码中设置margin

    我们平常可以直接在xml里设置margin,如: <ImageView android:layout_margin="5dip" android:src="@dra ...

  7. 在java代码中显示json字符串(怎么避免json字符串中双引号在java代码中显示)

    String log = "eyJvcmRlckluZm8iOnsiaWQiOjEwNzQwNCwib3JkZXJJZCI6MjczNjQyMSwicHJvZHVjdENvZGUiOjQ1N ...

  8. 使用非java代码编程

    使用非JAVA代码     JAVA语言及其标准API(应用程序编程接口)应付应用程序的编写已绰绰有余.但在某些情况下,还是必须使用非JAVA编码.例如,我们有时要访问操作系统的专用特性,与特殊的硬件 ...

  9. JAVA代码规范笔记(上)

    本文为<code conventions-150003>(JAVA代码规范)笔记. 文件组织 1.超过2000行代码的源文件将会比较难以阅读,应该避免. 2.每个Java源文件都包含单一的 ...

随机推荐

  1. OSI协议与TCP\IP协议之间的关系

    OSI协议 TCP\IP协议 五层协议(学习参考) 应用层 应用层 应用层 表示层 会话层 运输层 运输层 运输层 网络层 网络层 网络层 数据链路层 网络接口层 数据链路层 物理层 物理层 基于五层 ...

  2. iOS CALayer总结——图层几何

    最近看了一下关于图层和动画的内容,所以写了一份总结,算是对这些内容的汇总吧,都是一些简单的基础知识,不知道大家都了不了解. 除了和用户的交互之外,图层的很多属性和视图基本上都是一样的,今天就先从CAL ...

  3. 使用SAP Cloud Platform Leonardo机器学习的测试控制台

    选中一个需要进行测试的Leonardo机器学习服务,点击Configure Environments: 因为我不想使用sandbox环境,所以我选择了eu10这个region: 维护clientid和 ...

  4. 【前端适配】vw单位移动端适配方案

    近些年移动端的强势崛起,导致移动端适配越来越重要,个人之前一直使用的是rem进行适配,但是发现并不是非常完美,给力的是大漠老师写了一篇<如何在Vue项目中使用vw实现移动端适配>,比较完美 ...

  5. 安装xshell、xftp

    1.Xshell的软件的下载.安装 xshell是一个终端模拟软件,而且是远程近程都可以. 就是模拟服务器所在的linux,在xshell中可以输入命令, 就像在服务器的linux中输入命令一样.一般 ...

  6. spark 机器学习 ALS原理(一)

    1.线性回归模型线性回归是统计学中最常用的算法,当你想表示两个变量间的数学关系时,就可以用线性回归.当你使用它时,你首先假设输出变量(相应变量.因变量.标签)和预测变量(自变量.解释变量.特征)之间存 ...

  7. testlink关联redmine设置

    Testlink关联Redmine 公司用testlink对测试用例进行维护,redmine关系项目及bug,所以为了方便期间,将Testlink关联Redmine,方便测试用例执行后,在redmin ...

  8. 国内首本免费深度学习书籍!还有人没Get么?

    这本书的作者很有趣鸭. 一开篇别的不说,先跟大家讲哲学,讨论人工智能实现的可能性.摘录一些他的结论: 人工智能可以实现 自由意志并不存在 量子力学并不能证明自由意志的存在 幸福感和物质水平提高并没有绝 ...

  9. openwrt 切换overlay文件系统为根文件系统

    http://blog.chinaunix.net/uid-27057175-id-4584360 openwrt的overlayfs 通过/etc/preinit调用 /sbin/mount_roo ...

  10. Linux动态连接器

    转自:Chapter 9. Dynamic Linking 参考:Linux动态链接器 Linux加载启动可执行程序的过程(一)内核空间加载ELF的过程 Linux加载启动可执行程序的过程(二)解释器 ...