SAP错误消息调试之七种武器:让所有的错误消息都能被定位
目录
-
SAPGUI Where Used List
-
ABAP调试器观察点
-
ABAP调试器动态断点
-
ABAP代码静态扫描
-
SAT
-
ST05
-
迷之方法???
具体场景:在SE38里随便输入一个并不存在的程序名,点击Display按钮,显示一个提示消息。我们的任务是通过调试或者使用Netweaver提供的其他工具找到抛出这个消息的ABAP代码的准确位置。
方法1: 使用SAPGUI自带的Where Used List功能
鼠标单击SE38里显示的提示消息,查看这条消息的技术明细:DS017,其中DS代表Message Class的ID,017是这条消息在Message Class里的编号。

事务码SE91, 打开DS message class,定位到第17条消息,点击这个图标使用Where Used List功能。

结果发现SAP标准程序里抛出这个消息的地方太多了。。。

这种情况下只得一条一条看了。注意我们在SE38里看到的消息显示前面有个绿灯,因此说明ABAP代码抛出这条消息时,是以类型S(Successful)投递的。这样我们只看结果列表里MESSAGE s017这种记录,对于MESSAGE E017直接忽略,因为后者抛出的消息前面显示的是红灯。
很快找到了这一条记录,但我还不能100%确认。此时双击进去,设置一个断点,然后回到SE38,再点一次Display按钮。

此时断点触发,说明ABAP include LWBABAPF00的第813行就是我要找的抛出这个提示消息的准确位置。
方法2: 使用ABAP调试器的watch point(观察点)功能
通过ABAP的关键字MESSAGE抛出消息时,系统变量SY-MSGID会自动被填充消息所属的Message Class,在Jerry这个例子里为DS,而SY-MSGNO被填充为抛出消息的编号,这个例子里为017. 因此,通过在调试器里创建watch point并维护相应的触发条件。在程序运行时,一旦触发条件满足,watch point触发,此时执行到的ABAP语句即为消息弹出的准确位置。
在命令输入栏里键入/h打开调试模式,点击Display按钮,弹出调试器:

在调试器的此处创建一个watch point:

条件维护如下,然后按F8继续程序的执行,之后调试器会自动在抛出消息的ABAP代码处停下来。



方法3: 使用ABAP调试器里类型为ABAP命令的动态断点
在调试器此处创建类型为ABAP Commands的动态断点,命令设置为MESSAGE. 这样,ABAP调试器会自动在所有出现了MESSAGE关键字的地方停下来。

也可以在菜单Breakpoints->Breakpoint at处创建很多其他类型的断点,相当有用。


从方法4开始介绍的消息定位方法,已经不再局限于使用ABAP调试器,而是灵活运用SAP Netweaver里提供的各种有用工具。
方法4: ABAP源代码静态扫描
事务码SE93里输入SE38,找到SE38实现的ABAP程序名和所处的开发包名称。

方法4的理论依据是,既然我们在SE38里看到了DS017这条消息,那么SE38的实现代码里,必定会出现MESSAGE S017这行代码。因此在方法4里我们改变思路,不再采用动态调试的办法,而选择和它相反的思路。
使用源代码扫描工具程序RS_ABAP_SOURCE_SCAN查找SE38实现代码里所有出现了MESSAGE S017的ABAP代码位置:

不到一秒钟,就找到了准确的位置:

另一个事务码CODE_SCANNER也提供了类似的ABAP代码扫描功能,界面和RS_ABAP_SOURCE_SCAN略微有点差异


方法5:使用ABAP应用性能分析工具SAT
进入事务码SAT,创建一个新的跟踪Variant,Aggregation(聚合)记得设置为None,否则后续查看结果时将得不到期望看到的完整树形结构。

在Transaction字段里输入SE38,点击Execute按钮,这样就在跟踪模式下启动了SE38.

接着和以前一样,点击Display按钮,看到提示消息后,返回到SAT界面。这样SE38从启动到弹出提示消息,再到退出这整个过程所执行的ABAP代码都被SAT记录下来了。此时会看到一个进度条,表明SAT在格式化所记录内容的进度:

等到100%完成后,来到SAT的结果展示页面里,点击Call Hierarchy标签页,SE38执行的所有ABAP statement罗列如下。使用SAT自带的搜索按钮,输入MESSAGE S017, 执行即可得到结果。双击后就能进入对应的ABAP代码。


虽然SAT最主要的用途是用来做应用性能分析和优化的,但在Jerry介绍的这个场景里,它也起到了辅助消息定位的作用。
除此之外说句题外话,SAT的Processing Blocks界面以树形结构显示了ABAP代码的一层层调用关系,对于我们分析和学习复杂应用的执行逻辑也非常有帮助。

方法6: 使用ABAP数据库执行跟踪和性能分析工具ST05
ST05虽然同离别钩一样,能有效帮助大家的消息定位工作,但如果你在客户生产系统里打开了ST05的性能分析开关,之后忘记了关掉,那说不定你可能不得不同你的工作离别了。
ABAP从业人员在怀疑应用程序的性能瓶颈出现在数据库层面时,往往都会在事务码ST05里将数据库跟踪开关打开,在跟踪模式下重新运行应用,拿到跟踪结果以此来分析数据库的性能。
在这个例子里,用ST05跟踪SE38这个事务码的执行,能得到过程中访问过的所有数据库表的名称,和访问它们的性能。
为什么要弄清楚SE38到底访问了哪些数据库表?根据经验推断,我们在SE38里输入程序的名称点击Display按钮后,SE38的实现必定会从某个数据库表(即Netweaver里存储所有ABAP程序名称的数据库表)里根据该名称进行搜索,如果搜索未命中,说明该程序并不存在,从而抛一条消息给用户。
换言之,SE38里根据用户输入去数据库表里使用OPEN SQL进行查询,和抛出提示消息,这两处代码的位置一定相邻。因此我们只要找到了SE38里查询报表名称的数据库表的位置,那么距离抛出提示消息的代码位置也不远了。
对于SE38里访问数据库表的性能,是毫不关心的,直接忽略。在ST05的结果列表里,我只盯着Object Name里显示的数据库表名称,PROGDIR在里面太显眼了。这张表存放的就是所有ABAP程序的名称,右边的就是访问该表的ABAP OPEN SQL:
SELECT WHERE ''NAME" = 'ASDASDD' AND "STATE" = 'A'.
我之前在ST05跟踪模式下随便输了个程序名ASDASDD, 所以SE38试图到表PROGDIR里查找一个名叫ASDASDD且状态为激活状态(A-Activated)的程序。

点击上图的Display按钮,就能看到访问数据库表PRODDIR的代码了,位于第774行:

鼠标稍稍往下滑动一下,第813行就是我们要找到抛出提示消息的代码位置。两个挨得确实够近吧?

方法7: 使用搜索引擎根据关键字DS 017查找,或者直接向认识的专家求助
同样,当遇到我们难以定位的消息时,我们可以直接使用搜索引擎,或者向自己认识的专家求助。

浙公网安备 33010602011771号