
13

记一次线上报错日志问题排查
source link: https://www.cnblogs.com/barantt/p/14606410.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

记一次线上报错日志问题排查
今天阳光明媚,掐指一算,今天比较适合划水。
于是早上到公司之后先是蹲了厕所,然后就准备翻阅公众号推文。
看的正嗨,突然钉钉群里开始响了,
生产日志群报了一条警告,如下:

报错信息很明确
UnsupportedOperationException
java.lang.UnsupportedOperationException
at java.util.AbstractMap.put(AbstractMap.java:209)
at com.ifugle.rap.dsb.bot.service.messageBus.chatResult.postProcessor.BizCategoryResultResolveProcessor.concatBizCategoryChatResult(BizCategoryResultResolveProcessor.java:98)
定位到业务代码如下
/**
* 拼接业务多轮聊天结果
*
* @param utterance
* @param chatResult
*/
private void concatBizCategoryChatResult(String utterance, Map<String, Object> chatResult) {
Object botAction = bizCategoryChatResult.get(MESSAGE_BOT_ACTION);
if (NullUtil.isNotNull(botAction)) {
chatResult.put(MESSAGE_BOT_ACTION, botAction);//--->这行代码报错
chatResult.put(DISPLAY_CONTENT, bizCategoryChatResult.get(DISPLAY_CONTENT));
chatResult.put(MESSAGE_BOT_FRAMEWORK, bizCategoryChatResult.get(MESSAGE_BOT_FRAMEWORK));
}
}
一个普普通通的map的put操作,怎么就报错了呢?继续往下看。
报错是在AbstractMap,翻看源码
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
这个抽象累定义了一个public的put方法,但是里面是直接抛出了异常。
分析一下,应该是某个类继承了AbstractMap这个类,但是又没有重写put方法,于是就直接调用了父类的put方法导致直接抛异常了。
我又翻看了阿里云上的日志发现传过来的这个map是一个空的。
我的第一反应就是集合工具类Collections里面的静态方法emptyMap(),因为我们业务代码中有很多地方都用到了这个。
这里贴一小段代码
if (!continueSendToRobot) {
chatResult = toManResult.getResult();
if (chatResult == null) {
chatResult = EMPTY_CHAT_RESULT;//<---- 看到这个EMPTY_CHAT_RESULT没
}
chatMessageForm.setChatResult(chatResult);
return ExitHandle.class;
}
这个是个静态变量,于是我又找到了定义它的地方
// 空的聊天内容
Map<String, Object> EMPTY_CHAT_RESULT = Collections.emptyMap();
继续看这个emptyMap()
public static final <K,V> Map<K,V> emptyMap() {
return (Map<K,V>) EMPTY_MAP;
}
//又是一个静态变量
//继续看
public static final Map EMPTY_MAP = new EmptyMap<>();
//这里是new了一个EmptyMap对象
//继续看这个对象,如果这个对象是继承了AbstractMap恰好它没有重写put方法的话,那就证明我的猜想每问题
private static class EmptyMap<K,V> extends AbstractMap<K,V> implements Serializable
//可以看到这个EmptyMap是Collections的一个静态内部类,继承了AbstractMap
再看看这个类的所有方法

可以看到该类并没有重写put方法!
那么问题来了,怎么解决呢?
后面我在业务代码里面加了一个判断逻辑,当这个map是AbstractMap并且是一个空map时,重新给他new一个HashMap。
错误示范请勿参考!
/**
* 拼接业务多轮聊天结果
*
* @param utterance
* @param chatResult
*/
private void concatBizCategoryChatResult(String utterance, Map<String, Object> chatResult) {
// 新加代码
if (NullUtil.isNull(chatResult) && chatResult instanceof AbstractMap) {
chatResult = new HashMap<>();
}
Object botAction = bizCategoryChatResult.get(MESSAGE_BOT_ACTION);
if (NullUtil.isNotNull(botAction)) {
chatResult.put(MESSAGE_BOT_ACTION, botAction);//--->这行代码报错
chatResult.put(DISPLAY_CONTENT, bizCategoryChatResult.get(DISPLAY_CONTENT));
chatResult.put(MESSAGE_BOT_FRAMEWORK, bizCategoryChatResult.get(MESSAGE_BOT_FRAMEWORK));
}
}
至此,问题就解决啦~~
继续划水。
更新一下,非常感谢@mrfangzheng在评论里面的指正,我上面这种BUG的修复方案是错误的,学习了谢谢!
我现在的解决方案就是把这个map返回回去,也是这位老哥给的建议,再次感谢。
修正版如下
/**
* 拼接业务多轮聊天结果
*
* @param utterance
* @param chatResult
*/
private Map<String, Object> concatBizCategoryChatResult(String utterance, Map<String, Object> chatResult) {
// 新加代码
if (NullUtil.isNull(chatResult) && chatResult instanceof AbstractMap) {
chatResult = new HashMap<>();
}
Object botAction = bizCategoryChatResult.get(MESSAGE_BOT_ACTION);
if (NullUtil.isNotNull(botAction)) {
chatResult.put(MESSAGE_BOT_ACTION, botAction);//--->这行代码报错
chatResult.put(DISPLAY_CONTENT, bizCategoryChatResult.get(DISPLAY_CONTENT));
chatResult.put(MESSAGE_BOT_FRAMEWORK, bizCategoryChatResult.get(MESSAGE_BOT_FRAMEWORK));
}
return chatResult;
}
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK