问题分析:日志回溯场景
<p>[TOC]</p>
<p>以下以一个具体实例,描述从错误日志分析触发场景的方法;
示例背景:
<strong>现象:</strong>服务器出现响应异常,几分钟后自动回复;
<strong>输入:</strong>查看error.log 发现在响应异常的时间段内出现了数据库语句的执行错误;</p>
<h1>反向回查代码</h1>
<h2>1 查看报错日志</h2>
<p>查找报错日志,SQL执行的语句红色标注部分:显示SQL解析异常,符号错误;
<img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=78cbf0be82109fc9d490cfe4235a01d2&amp;file=file.png" alt="" /></p>
<h2>2 回查原始语句</h2>
<p>回查代码,看看这里实际要填入什么
<img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=e4277ace421f4199505a0ca7c2cf02e7&amp;file=file.png" alt="" /></p>
<h2>3 回查调用点(目的要追溯到controller的映射请求名)</h2>
<p>数据库查询方法调用点:
<img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=209edd64400667cb2941206fdc0acf9b&amp;file=file.png" alt="" />
调用点所在函数:
<img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=284ced383f16b1c35e201f53490674fc&amp;file=file.png" alt="" />
cotroller调用点:
<img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=e85c147e0b8f8103ce2617cbf0c24fa0&amp;file=file.png" alt="" />
好了,下一步我们需要去小程序的工程,查找 applet/message/list 这个HTTP访问请求的发起页面;</p>
<h2>4 小程序页面</h2>
<p>全局查找锁定
<img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=f30c5969f3cd2d6bc50fb59ea6fd928c&amp;file=file.png" alt="" />
继续查找 messageList的调用点;我们看到调用点就一个;
<img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=bd97285c98f2b3f676938ad964ffceb6&amp;file=file.png" alt="" />
我们看到 init方法中调用了messageList()函数,说明在页面加载的时候就会触发;
查看页面所在文件路径;
<img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=a195da802bec9926bc73ab2c6008f6e6&amp;file=file.png" alt="" />
我们在页面上查看News页面所在位置如下:
<img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=0c9ab8b8930ec0c81d748e5aa2239a5c&amp;file=file.png" alt="" /></p>
<p>如上过程,就最终锁定到了具体的触发错误的位置;</p>
<h1>数据流及场景分析</h1>
<h2>1 数据流</h2>
<p>结合报错知道整个流程:
1、当用户查看页面时,调用了News页面的加载;
2、News页面加载调用api.js中定义的 messageList()方法;
3、messgaList()方法,映射的是 applet/message/list 请求;
4、server端通过spring-boot映射的响应方法是: AppletMessageController.listMessage();
5、controller,通过private IDeviceRunLogService deviceRunLogService; 成员的listMessage(page, pageDTO)方法获取数据;
6、实际调用的是DeviceRunLogServiceImpl 这个具体的实现类的对象方法;</p>
<pre><code class="language-java">@Service
@AllArgsConstructor
public class DeviceRunLogServiceImpl extends ServiceImpl&lt;DeviceRunLogMapper, DeviceRunLog&gt; implements IDeviceRunLogService {
...
public IPage&lt;AppletMessageListVO&gt; listMessage(Page&lt;AppletMessageListVO&gt; page, AppletMessageListDTO pageDTO) {
...
IPage&lt;AppletMessageListVO&gt; iPage = this.baseMapper.listMessage(page, pageDTO, deviceIds, userId, gatewayIds);
}
}</code></pre>
<p>7、然后调用MyBatis 映射的执行SQL,这个定义在 DeviceRunLogMapper.xml 文件中
至此,走到了我们的报错位置;
<img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=ec3c3b395834685f599912e7fa566505&amp;file=file.png" alt="" /></p>
<h2>2 分析</h2>
<p>然后我们看到是因为用户查看消息的时候,他的设备列表是空的,触发了这个异常;
假定了用户一定能查询到设备而触发;</p>
<h2>3 策略</h2>
<p>1、重现场景;确认分析的正确性、检查是否有其他异常场景;
2、方案预期:可以通过在调用this.baseMapper.listMessage(page, pageDTO, deviceIds, userId, gatewayIds) 之前检查这个deviceIds等输入参数是否为空;</p>