本章主要讲述使用在非 standalone 模式下如何进行录制和回放,以及总结了我在学习过程中的调试的技巧。
系列文章导航:
[jvm-sandbox-repeater 学习笔记][入门使用篇] 1 安装与启动
[jvm-sandbox-repeater 学习笔记][入门使用篇] 2 配置说明
[jvm-sandbox-repeater 学习笔记][入门使用篇] 3 现有接口说明
[jvm-sandbox-repeater 学习笔记][入门使用篇] 4 录制、回放与调试(本文)
当 repeater 启动成功后,就会自动开始录制采集。
在非 standalone 模式下,会将录制的结果上发到 repeater-console 中。
repeater-console 没有提供可以查看录制记录数据的接口。
如果想要知道更加详细的信息,从3 接口文档的篇章中,只有一个供 repeater 调用的获取录制记录的接口。在该接口中打断点,即可看到更加详细的录制记录信息。
@Override
public RepeaterResult<String> get(String appName, String traceId) {
Record record = recordMapper.selectByAppNameAndTraceId(appName, traceId);
// 在此处打断点,然后调试中执行SerializerWrapper.hessianDeserialize(record.getWrapperRecord(), RecordModel.class)即可查看详情
if (record == null) {
return RepeaterResult.builder().success(false).message("data not exits").build();
}
return RepeaterResult.builder().success(true).message("operate success").data(record.getWrapperRecord()).build();
}
参考3 接口文档中,用户可以通过传入录制记录 appName 和 traceId 触发一个录制的回放。
回放成功的要素是:
1、填写正确的 appName、traceId
2、回放时录制回放配置与录制时保持一致。
参考3 接口文档中,用户通过回放任务的 repeatId 获取回放结果。
以下为回放结果的返回结果示例,想要具体字段说明可以参考3 接口文档。
{
"success": true,
"data": {
"repeatId": "192168015073156871042776710028ed",
"finish": true,
"response": "123",
"originResponse": "123",
"diff": [],
"cost": 179,
"traceId": "192168015073156871042791710006ed",
"appName": "redis",
"environment": "local",
"host": "192.168.15.73",
"starTime": "2019-09-17T08:53:47.917+0000",
"endTime": "2019-09-17T08:53:48.096+0000",
"mockInvocations": [
{
"index": 1,
"traceId": "192168015073156871042791710006ed",
"repeatId": "192168015073156871042776710028ed",
"success": true,
"skip": false,
"cost": 11,
"originUri": "mybatis://UPDATE/org.spring.springboot.dao.CityDao.updateCity",
"currentUri": "mybatis://UPDATE/org.spring.springboot.dao.CityDao.updateCity",
"originArgs": [
[
{
"cityName": "温岭市3",
"description": "BYSocket 的家在温岭。",
"id": 1,
"provinceId": 1
}
],
{
"keyProperties": [
"id"
],
"isUseGeneratedKeys": false
}
],
"currentArgs": [
[
{
"cityName": "温岭市3",
"description": "BYSocket 的家在温岭。",
"id": 1,
"provinceId": 1
}
],
{
"keyProperties": [
"id"
],
"isUseGeneratedKeys": false
}
]
},
{
"index": 2,
"traceId": "192168015073156871042791710006ed",
"repeatId": "192168015073156871042776710028ed",
"success": true,
"skip": false,
"cost": 2,
"originUri": "java://redis.clients.jedis.Connection/isConnected~()Z",
"currentUri": "java://redis.clients.jedis.Connection/isConnected~()Z",
"originArgs": [],
"currentArgs": []
}
]
},
"message": "operate success"
}
回放结果中有一个diff
字段,但是官方没有实现,所以使用官方开源版本需要人肉对比。
判断要素可参考以下两点:
response
和originResponse
一致,说明本次回放的接口中,返回的接口和录制时返回的结果一致。success
都为 true,说明执行的每一个 mock 步骤都执行成功。PS:diff 功能可以自行在 repeater-console 实现,主要是字符串对比输出差异。
如果发现不满足上述成功条件可以从三个方向协助定位。
success
是否为true
),如果出现了success
为false
的情况,说明是该步骤 mock 失败导致的失败,可以进一步看看这个 mockInvication 中的currentArgs
和originArgs
是否不一致,如果发现不一致,则需要检查代码逻辑,了解入参如何生成,为啥会不一致。在这里总结一下我是用过的 repeater 的调试技巧,以便后续遇到了问题可以更好地进行定位排查以及解决。
在 repeater 的调研试用过程之初,我对 repeater 一窍不通。过程中由于配置出错、使用姿势不对等原因,经常遇到 repeater 没有按照我预期运行的情况。
那时我还不是很懂调试手段,主要是通过看日志、看源码,在源码报错行的上下文加日志来辅助我定位问题。
添加日志的技巧有四:
JSONObject.toJSONString(object, SerializerFeature.IgnoreNonFieldGetter)
来进行打印,这样可以以 json 格式输出对象中的详细信息,以及通过SerializerFeature.IgnoreNonFieldGetter
参数规避一下序列化失败的情况。切记:添加日志之后,本地环境需要执行install-local.sh
脚本,对 repeater 重新打包并安装到本地环境才可生效,如何重新打包,可以看1 安装与启动中的 1.3 章节。
在录制回放过程中常遇到的情况以及对应日志的情况,在这里做一个小结。
以下日志没有特殊说明就是指~/logs/sandbox/repeater/repeater.log。
请求后没有生成录制记录
event missing sample rule
"[Error-0000]-uncaught exception occurred when dispatch event
。一般可能会是序列化的错误,可以留意这个日志之后的堆栈信息是否有SerializeException
相关字样的信息。[Error-0000]-broadcast record failed
回放结果不一致
can't find any sub invocation
——回放过程中没有在录制记录的子调用中找到这个该 mock 请求相同的调用,需要查看这一个 mock 请求在回放应用中的调用关系,了解为何录制是没有录制到这一个子调用。find invocation by xxx,but similarity not match
——回放过程中在录制记录的子调用中只找到了请求相同的但没有找到参数相同的调用。需要查看不一致的参数有哪些,在回放应用的源码中找到参数生成逻辑,了解为何录制和回放为何对于同一个步骤生成了不一样的参数。serialize
相关的 error 日志都是序列化问题。在开发过程中主要使用的调试手段是以 jar 包的方式启动应用,添加 java 远程调试相关参数,并以 agent 模式启动 repeater。
命令可参考 jvm-sandbox-repeater 代码中的bin/bootstrap.sh
中的启动命令。
${JAVA_HOME}/bin/java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000 \
-javaagent:${HOME}/sandbox/lib/sandbox-agent.jar=server.port=8820\;server.ip=0.0.0.0 \
-Dapp.name=repeater \
-Dapp.env=daily \
-jar 应用.jar
其中:
y
和n
,n
代表启动应用过程不中断,运行过程等待远程调试器连接,而y
代表调试器就绪后启动暂停,直到有远程调试器连接才继续执行启动。当我们需要调试 repeater 的初始化过程时,就需要用到y
模式。执行启动命令之后,需要调试 repeater,则使用 idea 打开 jvm-sandbox-repeater 源码,配置对应端口的远程调试,启动调试,连接上后在控制台打印日志:
Connected to the target VM, address: 'localhost:8000', transport: 'socket'
说明成功连上,可以对 repeater 进行断点调试了。
发现社区也有一篇关于 repeater 的调试说明且图文并茂的文章,这里放下传送门。