设为首页 加入收藏

TOP

侦探剧场:堆内存神秘溢出事件(三)
2018-03-06 09:03:08 】 浏览:1129
Tags:侦探 剧场 内存 神秘 溢出 事件
ead not in (select thread from log151) 查找log150中没有151的线程,有一堆workflowMessageListenerContainer

查了下151的workflowMessageListenerContainer日志,并没有什么异常…

至此,通过查看web相关请求的响应时间,排除了web相关请求,通过两台机器对比线程,排除了非web相关请求。这样问题就死在这里了…

小光抬眼看了下时间,已经到了晚上,思路也渐渐的不清晰了,暂时休息,明天继续。

5. 第二天,根据不在场证明确定嫌疑人

第二天,小光早早的起了床,并立了一个Flag,今天肯定能查到原因。因为昨晚他突然想到,当一个请求很耗时,甚至都不返回成为死循环时,可能连日志都没有。

同时,WebFilter的日志打印,是在finally中,当请求无法返回时,当然不会打印日志,昨天确实是忽略了这个问题,走了个大的弯路。

public void doFilter(ServletRequest request, ServletResponse response,
					 FilterChain arg2) throws IOException, ServletException {
    long startTime = System.currentTimeMillis();
    StringBuffer url = new StringBuffer();
    try {
        url = url.append(((HttpServletRequest)request).getRequestURL().toString());
        arg2.doFilter(request, response);
    } catch (Throwable e){
        request.setAttribute("errmsg", e.getClass()+"-"+e.getMessage());
        RequestDispatcher rd = request.getRequestDispatcher("/resources/error.jsp");
        try {  
            rd.forward(request, response);  
            return;  
        }catch(Exception ex){}  
    } finally{
        if (!url.toString().contains("resources")) {
            logger.info(String.format("time %s,%s", url, System.currentTimeMillis() - startTime));
        }
    }
}

可以看到,只有finally中打印了日志,请求之前并没有打印日志。

那么是否有before和after都打印了日志,只要分析一下有before但是没有after的请求,那么就可以定位到问题点了!

想到这里,小光立马兴奋了一起,打开代码,找寻其他切入点,果然找到了一个WebInterceptor:

public class RequestLoggerHandler extends HandlerInterceptorAdapter {
    private static Logger logger = LogManager.getLogger(RequestLoggerHandler.class);
    private ThreadLocal<Long> startTime = new ThreadLocal();

    public RequestLoggerHandler() {
    }

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        this.startTime.set(System.currentTimeMillis());
        User user = SessionUserUtil.getCurrentSessionUser();
        logger.info("[http]preHandle url: {}, user:{}, inParams: {}", new Object[]{request.getRequestURL(), user, this.toJSONString(request.getParameterMap())});
        return true;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        logger.info("[http]postHandle url: {}, cause [{}] ms", new Object[]{request.getRequestURL(), System.currentTimeMillis() - ((Long)this.startTime.get()).longValue()});
        ThreadTokenHelper.clear();
    }

    private String toJSONString(Object object) {
        try {
            return JSON.toJSONString(object);
        } catch (Exception var3) {
            logger.warn("request请求参数序列化{}异常......");
            var3.printStackTrace();
            return null;
        }
    }
}

这里的before和after都打印了日志,且日志可以通过上面的n2即日志id来关联,没有日志id的时候可以使用请求地址来做对比。

结构化该请求相关的日志

cat all_is_well.log | grep '20180110-08:2[2-4].*com.xxx.commons.log.RequestLoggerHandler.*'
导出日志。

SELECT count(1),n2 FROM requestlog GROUP BY n2
查询数据,找出其中为奇数的请求。

最终竟然真的找到了一个,而且有且只有一个

time thread level clazz n1 n2
23:26.449 [catalina-exec-19] INFO com.commons.log.RequestLoggerHandler [1406449_454_770] [25216485580601]

查看时间点,也确实与案发时间对的上。为增加确定性,搜索该时间点之后线程catalina-exec-19的相关日志,发现在该时间点之后,就没有与此线程相关的日志了。由此,根据各线程的不在场证明可以基本确定嫌疑人为线程catalina-exec-19。

查看该条日志,得到请求信息

首页 上一页 1 2 3 4 5 6 下一页 尾页 3/6/6
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇如何编写相对标准的后端项目(二.. 下一篇从 Java9 共享内存加载 modules ..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目