/* 发送trace日志到总线上 */ private void sendTrace(HttpServletRequest req, TraceContext c, BufferedResponseWrapper res) { AccessBean b = new AccessBean(); b.setStamp(FilterHelpers.getRequestTime(req)); b.setCost((int) FilterHelpers.getCostTime(req)); b.setTraceId(c.getTraceId()); b.setRpcId(c.getParentRpcId()); b.setClientIp(getRemoteIp(req)); b.setServerIp(ConfigHelper.getServerInnerIP()); b.setProfile(ConfigHelper.getProcessInfo().getProfile()); b.setCode(res.getStatus()); b.setSize(res.getLength()); b.setReferer(req.getHeader("Referer")); b.setUserAgent(req.getHeader("User-Agent")); b.setCookie(req.getHeader("Cookie")); b.setUid(FilterHelpers.getUserId(req)); String url = req.getServerName(); if (req.getServerPort() != 80) { url += ':' + req.getServerPort(); } if (req.getQueryString() != null) { url += '?' + req.getQueryString(); } b.setUrl(url); Message m = new Message("JinJingAccess", c.getTraceId(), JSON.toJSONBytes(b)); RocketMqSender.getInstance().asyncSend(m); }
private void fillTraceContext(CharsetDetectRequestWrapper reqWrapper) { TraceContext traceContext = TraceContext.get(); Pair<String, String> traceAndStep = FilterHelpers.getTraceIdAndRpcId(reqWrapper); traceContext.setTraceId(traceAndStep.first); traceContext.setParentRpcId(traceAndStep.second); traceContext.setSpider(FilterHelpers.isSpider(reqWrapper)); traceContext.setColor(FilterHelpers.isColorized(reqWrapper)).setFail(false); }
private void copyResponse(HttpServletResponse res, BufferedResponseWrapper wrapper) throws IOException { if (wrapper.isError()) { res.setContentType("text/html; charset=UTF-8"); res.sendError(wrapper.getStatus()); } // 发送响应内容 wrapper.flushBuffer(); if (wrapper.getLength() > 0) { if (wrapper.isGZipped()) { res.setHeader("Content-Encoding", "gzip"); } if (!res.isCommitted()) { String traceId = TraceContext.get().getTraceId(); if (!Strings.isNullOrEmpty(traceId)) { res.setHeader("x-trace-id", traceId); } res.setContentLength(wrapper.getLength()); wrapper.writeTo(res.getOutputStream()); res.flushBuffer(); } } }
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; // 设定请求开始时间 FilterHelpers.getRequestTime(req); if (request.getAttribute(alreadyFilteredAttributeName) != null || shouldNotFilter(req)) { // Proceed without invoking this filter... chain.doFilter(request, response); } else { // Do invoke this filter... request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE); CharsetDetectRequestWrapper reqWrapper = new CharsetDetectRequestWrapper(req); boolean gzip = false; // 是否启用GZip压缩 if (enableGZip) { String encoding = req.getHeader("Accept-Encoding"); if (encoding != null && encoding.contains("gzip")) { gzip = true; } } BufferedResponseWrapper resWrapper = new BufferedResponseWrapper(res, gzip); try { // XXX: 生成traceId,需要请求_traceId的参数,所以必须放到CharsetEncodingHandler后面 fillTraceContext(reqWrapper); chain.doFilter(reqWrapper, resWrapper); if (TraceContext.get().isColor()) { Cookie cookie = new Cookie("_color", "1"); cookie.setMaxAge(3600); cookie.setPath("/"); resWrapper.addCookie(cookie); } } catch (Exception e) { LOG.error("{}", req.getRequestURL(), e); resWrapper.setStatus(500); // 这里把异常抛出去,针对服务端异常,接入层nginx可以统计到,否则就统计不到 throw new ServletException( req.getRequestURL() + ", message: " + e.getMessage(), e.getCause()); } finally { request.removeAttribute(alreadyFilteredAttributeName); try { if (resWrapper.getLocation() != null) { res.sendRedirect(resWrapper.getLocation()); } else { setContentType(res); try { copyResponse(res, resWrapper); } catch (Exception e) { long cost = FilterHelpers.getCostTime(req); LOG.error("{}, cost={}ms", req.getRequestURL(), cost, e); } } } finally { TraceContext c = TraceContext.get(); TraceContext.remove(); // 染色日志发送到总线上 if (c.isColor()) { sendTrace(req, c, resWrapper); } // 统计页面状态信息 PageStatusReporter.getInstance().stat(req, c.getCost(), res.getStatus(), c.isSpider()); } } } }