调试,是程序开发中的基本技巧。快速定位错误消息在源代码中的位置,对发现和解决程序中的问题有着重要的意义。在SAP CRM中,错误消息通常在前台的Web Client页面中展示,应该怎样定位相关代码的位置呢?
我在SAP的网站上面找到了一篇不错的相关文章,翻译在这里。
本文链接:http://www.cnblogs.com/hhelibeb/p/6269133.html
-------------------------------------------正文分割线------------------------------------------------------------
在我的博客“六种调试技巧”中,Fabian Geyer提出了一个有关ERP应用查错的很好的观点。
他的原论述:
某些ERP应用(比如财务的)在“探测”到错误发生的时候经常使用一种“消息收集器”技术,特别是操作“多对象”的时候。“消息收集器”会被“存储”在一个“错误集”里面,在所有的检查完成后,将会产生一个也许包含了多个错误的列表,并且通过弹窗或列表被展示出来。
在这些情况下,在消息被“展示”的时候对程序进行分析就太晚了,因为导致错误发生的应用数据/环境在其它位置(在运行期间发生的更早)。在这些情形下,我通常在函数MESSAGE_STORE中设置断点。
为防止BC Application日志技术带来相同的问题(SLG0, SLG1等),可以在函数BAL_LOG_MSG_ADD中添加断点。
实际上,CRM应用中的错误消息处理逻辑是一样的,让我使用服务合同处理的例子进行说明:
如何找到触发消息CRM_ORDERADM_I编号505的代码?
注:如果看不到错误消息的详细信息,请前往事务代码SU3,维护用户参数 BSPWD_USER_LEVEL = 6
方法1:使用源代码扫描
有关如何使用源代码扫描的细节,请参考我之前的博文。
为了写博客,我使用了这个方法来定位,只花了几分钟就找到了准确的代码位置。
首先我使用源代码扫码工具(搜索关键字 = 505)来找消息号505的ITEM_TYPE_NOT_FOUND常量。因为我知道程序CRM_STATUS_CON已经定义了所有状态的常量,所以我用如下的参数运行了搜索程序:
结果如下:
接着再一次使用源代码扫描器。这里有个问题:怎样指定输入参数?
1,我们知道服务合同由One Order框架实现。随意打开一个函数模块CRM_ORDER_*例如CRM_ORDER_READ,获取它的包名CRM_ORDER:
2,输入以下内容后执行搜索程序:
什么也没找到。接着我把CRM_ORDER改为CRM_ORDER*,这次获得了七个候选结果,然后在每个当中设置断点,重复你触发错误的场景。
证实了上面结果中的第三个是我们寻找的地方:
方法2:使用函数模块 BAL_LOG_MSG_ADD
这个由Fabian Geyer提出的技巧也非常好。在函数模块BAL_LOG_MSG_ADD中设置断点,然后重复服务合同中的场景。断点会被触发(你可以观察到这个函数模块处于调用栈的最顶点),并且我们发现代码的位置和方法1中找到的位置完全一样。
在这个例子中,方法2的定位甚至比方法1更加有效率。感谢Fabian分享给我们如此有用的技巧。
在函数模块BALW_BAPIRETURN_GET2中设置断点也是一个不错的尝试。
为什么两个方法都无效?为什么断点没能在我的应用中被触发?
还是以服务合同为例,业务事务类似于销售订单、服务订单和服务合同经由所谓的One Order框架实现。按照我在上面最开始的部分引用过的Fabian的论述,One Order框架的探测逻辑——在这个例子里即是DETERMINE_ITEM_TYPE中的逻辑——只是在这个项目第一次被插入的时候起作用。一旦发现错误,函数组CRM_MESSAGES中各自的函数模块会被调用来持有错误消息。之后在错误的服务合同再次被打开的时候,就不会再有项目的类型检查了。相反,错误消息经由读取这个函数组中的函数模块来获取,并显示在UI上面。
当我在服务合同删除一个项目产品时,对于这个项目来说已经过时的错误信息也会同时通过CRM_MESSAGES_DELETE删除。
因此当我在难以命中业务事务应用中出现的错误消息时,我会选择删除旧的错误项目、重建它,或者从头开始创建一个新的。当然,如果我们需要在生产系统调试,这两个办法都不合适。
在这种情况下,如果你能确保客户生产系统中出现的错误消息也能在你的开发系统中重现,你还是可以使用本文中提到的技巧,用高效率的方式找到相应代码的位置。