写好代码很重要,日记记录也非常重要。
通过查看日志,能帮我们解决很多问题,以下是我们开发过程中经常会碰到的一些问题:
我们可以通过日志记录代码的执行流程、运行状态、关键指标。
1.2 帮助定位bug在关键代码处打印日志可以迅速定位问题原因。
1.3 记录用户操作行为通过对这些日志的分析我们可以得到用户的操作行为数据。
2.记录时机 2.1 程序流程需要关注程序流传逻辑,在关键代码逻辑的执行前后进行相应的日志输出,有助于代码调试。(但要避免不必要的日志输出,比如一般只在循环体前后记录日志,而不在循环体内重复记录,过多的日志反而会影响阅读。)
2.2 远程调用虽然远程调用也属于程序流程的一部分,但是应该和一般的程序流程日志区别对待,因为它涉及到和外部系统的交互,在出入口处记录请求入参和响应的信息,很有必要。
2.3 核心业务操作系统用户进行核心业务操作的行为,也应该进行记录,便于进行操作审计。
2.4 可预期的异常这类异常应该有效记录起来,通过警告方式反馈给相关人员加以关注,避免频繁发生,最终演化为不可控的问题。
2.5 预期外的错误这类异常发生时,要有详尽记录,并通知相关人员介入处理,第一时间作出响应,因为这种错误已经影响系统的正常使用。
3.日志要素 3.1日志时间日志产生的时间一定要有并且应该精确,推荐的格式是:
yyyy-MM-dd HH:mm:ss.SSS
3.2日志级别应该根据日志的重要性或严重程度划分等级,最常用的日志级别有:
DEBUG:在开发、测试阶段使用,记录调试性质的内容。
INFO:记录系统正常运行期间的关键信息。主要针对程序流转逻辑、核心业务操作。
WARN:记录可预期的异常。比如请求参数不合法。
ERROR:记录预期外的程序异常。比如数据异常、代码逻辑没有按预期执行。
一次同步请求对应一个处理线程,输出线程名称可以区分一次具体的请求上下文。
3.4 业务标识用来区分日志属于哪块业务,因为日志都是跟业务相关联的,通过该部分内容便于按业务进行日志归类聚合。
3.5 记录器名称日志的记录器名称一般是声明日志记录器实例的类名,通过记录器名称可以快速定位到日志输出的类是哪个。
3.6 日志内容根据不同的日志等级,在日志内容上会有不同的侧重点,但在内容输出上,有一些点是需要注意的:
[详细时间] [线程名] [日志级别] [类名] [日志信息]
%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
4.执行规范
4.1 选择恰当的日志级别常见的日志级别有 4 种,分别是error、warn、info、debug。
我们并不需要打印很多很多日志,只需要打印可以快速定位问题的有效日志。
哪些算得的上有效关键的日志呢?比如说,方法进来的时候,打印入参。再然后呢,在方法返回的时候,就是打印出参(需考虑数据量和必要性,慎重),返回值。正例如下:
public String testLogMethod(Document doc, Mode mode){log.debug(“method enter param:{}”,userId);
String id = "9527";
log.debug(“method exit param:{}”,id);
return id;
}
4.3 遇到if…else…等条件时,每个分支首行都尽量打印日志当你碰到if…else…或者switch这样的条件时,可以在分支的首行就打印日志,这样排查问题时,就可以通过日志,确定进入了哪个分支,代码逻辑更清晰,也更方便排查问题了。
正例:
if(user.isVip()){log.info("该用户是vip,Id:{},开始处理逻辑",user,getUserId());
//会员逻辑
}else{log.info("该用户不是vip,Id:{},开始处理逻辑",user,getUserId())
//非会员逻辑
}
4.4 建议使用参数占位{},而不是用+拼接。反例:
logger.info("Processing trade with id: " + id + " and symbol: " + symbol);
上面的例子中,使用+操作符进行字符串的拼接,有一定的性能损耗。
正例如下:
logger.info("Processing trade with id: {} and symbol : {} ", id, symbol);
我们使用了大括号{}来作为日志中的占位符,比于使用+操作符,更加优雅简洁。并且,相对于反例,使用占位符仅是替换动作,可以有效提升性能。
4.5 不要使用e.printStackTrace()反例:
try{// 业务代码处理
}catch(Exception e){e.printStackTrace();
}
正例:
try{// 业务代码处理
}catch(Exception e){log.error("你的程序有异常啦",e);
}
理由:
反例1:
try {//业务代码处理
} catch (Exception e) {// 错误
LOG.error('你的程序有异常啦');
}
反例2:
try {//业务代码处理
} catch (Exception e) {// 错误
LOG.error('你的程序有异常啦', e.getMessage());
}
正例:
try {//业务代码处理
} catch (Exception e) {// 错误
LOG.error('你的程序有异常啦', e);
}
4.7 禁止在线上环境开启 debug禁止在线上环境开启debug,这一点非常重要。
因为一般系统的debug日志会很多,并且各种框架中也大量使用 debug的日志,线上开启debug不久可能会打满磁盘,影响业务系统的正常运行。
反例如下:
log.error("IO exception", e);
throw new MyException(e);
避免重复打印日志,酱紫会浪费磁盘空间。如果你已经有一行日志清楚表达了意思,避免再冗余打印,反例如下:
if(user.isVip()){log.info("该用户是vip,Id:{}",user,getUserId());
//冗余,可以跟前面的日志合并一起
log.info("开始处理vop逻辑,id:{}",user,getUserId());
//vip逻辑
}else{//非vip逻辑
}
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧