最近开发中遇到一个问题,有一个新增接口,请求该接口时响应200但查询相关数据未有预期的数据,且日志中没有任何报错或警告;一般来说响应200认为是成功,但是结果却不符合事实;此时无外乎几种情况:
1、异常日志查找错误
2、代码存在逻辑问题
3、代码中的异常被吃掉了
4、某些api在某些情况不会出现异常会直接跳过逻辑
针对情况具体分析解决:
第一种情况要看出现问题的请求是否记录在当前的日志文件中,比如一天的日志文件拆分了多个、拆分了info、warn、error等日志文件;分布式系统里面可能这个错误不是当前模块提示的等等,所以先确定这个错误如果有记录是在哪个日志文件中。
第二种情况只能通过检验代码逻辑、日志、debug等方式排查代码逻辑问题,很多时候是某些特殊的数据情况没有兼容对应逻辑导致的,当然还有部分是在高并发、集群等情况下才会出现问题,这种需要对相关逻辑做高并发集群的特殊处理。
第三种情况可能是代码中避免某些报错,所以进行了捕获,但在捕获之后没有做出相关处理直接忽略了错误信息,这导致请求成功实际上有错误但错误未被记录下来,那么这种情况可以将catch里面进行日志打印或debug排查。
第四种情况因为不同的组件由不同的厂商提供,这些厂商在设计api时出发点不同,有些认为数据为空不合法直接抛出异常,有些认为数据为空是合法的,但不做任何处理,直接跳过处理逻辑;所以这种情况同样可以通过日志、debug等方式结合数据及使用的api对相应数据的处理逻辑进行分析,着重观察使用三方api的部分;这个情况和第二种情况可以归为一类,既然三方组件这种处理方式,那么我们只能调整我们自己的代码逻辑来兼容这种情况。
我这里遇到的情况属于第二种情况,因为特殊的数据,导致查询出来的关联数据为空,后续for循环处理关联数据的逻辑不执行,最终需要insert的数据为空不插入数据,所以最终结果是成功,也没有错误日志但没有预期数据;最终通过修改逻辑避免关联数据为空的情况,避免不新增数据。
测试for循环:
package com.database.pool.testpool.test;
import java.util.ArrayList;
import java.util.List;
/**
* 循环测试
*/
public class TestFor {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
fori(list);
forIn(list);
forEach(list);
}
/**
* 传统for循环
* @param list
*/
public static void fori(List<Integer> list){
for (int i = 0; i < list.size(); i++) {
System.out.println("传统for当前数据:"+list.get(i));
}
}
/**
* for in方式循环
* @param list
*/
public static void forIn(List<Integer> list){
for (Integer integer : list) {
System.out.println("for in当前数据:"+integer);
}
}
/**
* forEach方式循环
* @param list
*/
public static void forEach(List<Integer> list){
list.forEach(integer -> System.out.println("forEach当前数据:"+integer));
}
}
参数不是null且有元素的情况—都能正常执行循环里面的逻辑:
参数不是null但没有元素的情况—都能正常执行不报错:
参数是null的情况—都会报错:
通过针对for循环测试,入参只要不为null,都不会报错,如果入参没有元素则循环中的逻辑不会执行。
因此如果代码中有for循环处理逻辑,却没有预期数据也没有报错此时应当想到for循环的参数为空(不是null),从而排查这个入参为什么会为空,为空是否正常,进行相关处理。
题外:
1、如果代码中某些日志未打印,在排查了日志不生效,日志文件未找错的情况下,毫无疑问肯定是这块日志打印未执行;此时可能会因为以前都是正常执行的原因从而直接忽略某些内容,导致很难定位原因;此时正确的做法应当是从头分析这个日志打印什么情况下会执行,什么情况下不执行,甚至需要结合具体的入参进行分析;很可能的原因就是修改了代码逻辑或修改了某些配置导致的不执行(这个配置的来源可能是配置文件、可能是数据库中的字典配置等信息)。
2、可能系统的日志统一处理记录不完善,导致记录了报错,但报错日志信息比较简略(比如只记录了异常的message信息),这时虽然知道有问题,但要定位具体原因还是很难;此时要么将统一日志处理记录得非常详细,要么就在报错的逻辑部分记录非常详细的日志来排查问题;具体做法可以 将错误的代码try/catch,然后在catch中捕获比较顶级的异常(如:Exception e),并作 log.error(“错误信息:”,e) 处理,此时日志系统会将完整的错误记录在日志中,而非简单的message信息记录,可以方便排查问题(主要还是日志处理不完善导致的,建议还是将日志处理做完善)。