使用slf4j使用门面模式的日志框架,有利于维护和统一各个类的日志处理方式。统一使用实现方法:Logback框架的正确登录方式什么时候应该记录日志?遇到问题只能通过调试功能来确定问题所在。你应该考虑记录。一个好的系统可以通过日志集来解决问题。当你遇到if...else或者switch这样的分支时,你应该在该分支的第一行打印日志,以确定你进入了哪个分支。经常以功能为核心进行开发。在提交代码之前,你应该确定你可以通过日志。看到整个流程的基本格式必须使用参数化信息:logger.debug("Processingtradewithid:[{}]andsymbol:[{}]",id,symbol);对于debug日志,判断是否为debug级别后,Onlyuse:if(logger.isDebugEnabled()){logger.debug("Processingtradewithid:"+id+"symbol:"+symbol);}不进行字符串拼接,因为会生成很多String对象,占用空间,影响性能。反例(不要这样做):logger.debug("Processingtradewithid:"+id+"symbol:"+symbol);使用[]来隔离参数变量。如果有参数变量,应该这样写:logger.debug("Processingtradewithid:[{}]andsymbol:[{}]",id,symbol);这种格式更具可读性,有助于故障排除。不同层次的使用ERROR:基本概念影响程序的正常运行和当前请求的异常情况:配置文件打开失败所有第三方对接异常(包括第三方返回错误码)所有影响程序正常运行的异常函数的使用,包括:SQLException以及除业务异常之外的所有异常(RuntimeException和Exception)不应该发生:例如,你想使用Azure上传图片,但Azure没有响应。如果有Throwable信息,需要记录完成的栈信息:log.error("获取用户[{}]的用户信息有错误",userName,e);表示如果抛出异常,请不要记录错误日志,最终处理器会处理:反例(不要这样做):try{....}catch(Exceptionex){StringerrorMessage=String.format("Errorwhilereadinginformationofuser[%s]",userName);logger.error(errorMessage,ex);thrownewUserServiceException(errorMessage,ex);}WARN基本概念不应该出现但不影响程序和当前请求的异常情况正常运行:当有容错机制时,找不到配置文件,但系统可以在接近临界值时自动创建配置文件,例如:缓冲池占用达到警告线,业务异常记录,例如:当一个接口抛出业务异常时,应该记录该异常。INFO:基本概念系统运行信息Service方法中系统/业务状态的变化Step-by-step外部接口部分主逻辑(REST/WS)中客户端请求参数调用第三方时调用参数及调用结果说明1、并不是所有的服务都记录入口和出口,单一的、简单的服务是没有意义的(jobs除外,它需要记录开始和结束)。反例(不要这样做):publicListlistByBaseType(IntegerbaseTypeId){log.info("Startquerybase");BaseExampleex=newBaseExample();BaseExample.Criteriactr=ex.createCriteria();ctr.andIsDeleteEqualTo(IsDelete.USE.getValue());Optionals.doIfP??resent(baseTypeId,ctr::andBaseTypeIdEqualTo);log.info("Endofquerybase");returnbaseRepository.selectByExample(ex);}2.对于复杂的业务逻辑,日志管理和埋点记录都是需要的,比如电商系统中的下单逻辑,OrderAction操作(业务状态变化)。3、对于整个系统提供的接口(REST/WS),使用info来记录输入的参数。4.如果所有的服务都是SOA架构,可以看成是一个对外的接口提供者,必须记录入参。5、调用其他第三方服务时,必须记录所有的输出参数和输入参数(因为第三方模块的问题你很难追溯)。DEBUG的基本概念可以填上所有你想知道的相关信息(但不代表你可以随便写,调试信息要有意义,***有相关参数)生产环境需要转关闭DEBUG信息。如果生产情况下需要开启DEBUG,需要使用开关进行管理,不能一直开启。说明如果代码中出现如下代码,则可以进行优化//1.获取用户底薪//2.获取用户休假状态//3.计算用户应得工资优化代码:logger.debug("开始获取员工[{}][{}]年底薪",employee,year);logger.debug("获取员工[{}][{}]年基本工资为[{}]",employee,year,basicSalary);logger.debug("开始获取员工[{}][{}]年[{}]monthleave",employee,year,month);logger.debug("Employee[{}][{}]year[{}]月年假/病假/事假为[{}]/[{}]/[{}]",雇员,年,月,annualLeaveDays,sickLeaveDays,noPayLeaveDays);logger.debug("开始计算员工[{}][{}]年[{}]月的工资",employee,year,month);logger.debug("员工[{}][{}]年[{}]月工资为[{}]",employee,year,month,actualSalary);TRACE的基本概念是特别详细的系统运行完成信息。不要在业务代码中使用它。(除非你有特殊意图,否则请使用DEBUG级别代替)规范示例说明@Override@TransactionalpublicvoidcreateUserAndBindMobile(@NotBlankStringmobile,@NotNullUseruser)throwsCreateConflictException{booleandebug=log.isDebugEnabled();if(debug){log.debug("Startto创建用户并绑定手机号。args[mobile=[{}],user=[{}]]",mobile,LogObjects.toString(user));}try{user.setCreateTime(newDate());user.setUpdateTime(newDate());userRepository.insertSelective(user);if(debug){log.debug("创建用户信息成功.insertedUser=[{}]",LogObjects.toString(user));}UserMobileRelationshiprelationship=newUserMobileRelationship();relationship.setMobile(mobile);relationship.setOpenId(user.getOpenId());relationship.setCreateTime(newDate());relationship.setUpdateTime(newDate());userMobileRelationshipRepository.insertOnDuplicateKey(relationship);if(debug){log.debug("bindingThe手机成功.relationship=[{}]",LogObjects.toString(relationship));}log.info("创建用户并绑定手机号.userId=[{}],openId=[{}],mobile=[{}]",user.getId(),user.getOpenId(),mobile);//如果考虑安全,记得对手机号进行脱敏}catch(DuplicateKeyExceptione){log.info("Failed创建用户并绑定手机号,同一个用户已经存在.openId=[{}],mobile=[{}]",user.getOpenId(),mobile);thrownewCreateConflictException("冲突创建用户,openid=[%s]",user.getOpenId());}}
