package com.dianping.cat.servlet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.unidal.helper.Joiners;
import org.unidal.helper.Joiners.IBuilder;
import com.dianping.cat.Cat;
import com.dianping.cat.CatConstants;
import com.dianping.cat.configuration.client.entity.Server;
import com.dianping.cat.message.Message;
import com.dianping.cat.message.Transaction;
import com.dianping.cat.message.internal.DefaultMessageManager;
import com.dianping.cat.message.internal.DefaultTransaction;
public class CatFilter implements Filter {
private List m_handlers = new ArrayList();
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
Context ctx = new Context((HttpServletRequest) request, (HttpServletResponse) response, chain, m_handlers);
ctx.handle();
}
protected String getOriginalUrl(ServletRequest request) {
return ((HttpServletRequest) request).getRequestURI();
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
m_handlers.add(CatHandler.ENVIRONMENT);
m_handlers.add(CatHandler.LOG_SPAN);
m_handlers.add(CatHandler.LOG_CLIENT_PAYLOAD);
m_handlers.add(CatHandler.ID_SETUP);
}
private static enum CatHandler implements Handler {
ENVIRONMENT {
@Override
public void handle(Context ctx) throws IOException, ServletException {
HttpServletRequest req = ctx.getRequest();
boolean top = !Cat.getManager().hasContext();
ctx.setTop(top);
if (top) {
ctx.setType(CatConstants.TYPE_URL);
setTraceMode(req);
} else {
ctx.setType(CatConstants.TYPE_URL_FORWARD);
}
ctx.handle();
}
protected void setTraceMode(HttpServletRequest req) {
String traceMode = "X-CAT-TRACE-MODE";
String headMode = req.getHeader(traceMode);
if ("true".equals(headMode)) {
Cat.getManager().setTraceMode(true);
}
}
},
ID_SETUP {
private String m_servers;
private String getCatServer() {
if (m_servers == null) {
DefaultMessageManager manager = (DefaultMessageManager) Cat.getManager();
List servers = manager.getConfigManager().getServers();
m_servers = Joiners.by(',').join(servers, new IBuilder() {
@Override
public String asString(Server server) {
String ip = server.getIp();
Integer httpPort = server.getHttpPort();
return ip + ":" + httpPort;
}
});
}
return m_servers;
}
@Override
public void handle(Context ctx) throws IOException, ServletException {
boolean isTraceMode = Cat.getManager().isTraceMode();
HttpServletResponse res = ctx.getResponse();
if (isTraceMode) {
String id = Cat.getCurrentMessageId();
res.setHeader("X-CAT-ROOT-ID", id);
res.setHeader("X-CAT-SERVER", getCatServer());
}
ctx.handle();
}
},
LOG_CLIENT_PAYLOAD {
@Override
public void handle(Context ctx) throws IOException, ServletException {
HttpServletRequest req = ctx.getRequest();
String type = ctx.getType();
if (ctx.isTop()) {
logRequestClientInfo(req, type);
logRequestPayload(req, type);
} else {
logRequestPayload(req, type);
}
ctx.handle();
}
protected void logRequestClientInfo(HttpServletRequest req, String type) {
StringBuilder sb = new StringBuilder(1024);
String ip = "";
String ipForwarded = req.getHeader("x-forwarded-for");
if (ipForwarded == null) {
ip = req.getRemoteAddr();
} else {
ip = ipForwarded;
}
sb.append("IPS=").append(ip);
sb.append("&VirtualIP=").append(req.getRemoteAddr());
sb.append("&Server=").append(req.getServerName());
sb.append("&Referer=").append(req.getHeader("referer"));
sb.append("&Agent=").append(req.getHeader("user-agent"));
Cat.logEvent(type, type + ".Server", Message.SUCCESS, sb.toString());
}
protected void logRequestPayload(HttpServletRequest req, String type) {
StringBuilder sb = new StringBuilder(256);
sb.append(req.getScheme().toUpperCase()).append('/');
sb.append(req.getMethod()).append(' ').append(req.getRequestURI());
String qs = req.getQueryString();
if (qs != null) {
sb.append('?').append(qs);
}
Cat.logEvent(type, type + ".Method", Message.SUCCESS, sb.toString());
}
},
LOG_SPAN {
public static final char SPLIT = '/';
private void customizeStatus(Transaction t, HttpServletRequest req) {
Object catStatus = req.getAttribute(CatConstants.CAT_STATE);
if (catStatus != null) {
t.setStatus(catStatus.toString());
} else {
t.setStatus(Message.SUCCESS);
}
}
private void customizeUri(Transaction t, HttpServletRequest req) {
if (t instanceof DefaultTransaction) {
Object catPageType = req.getAttribute(CatConstants.CAT_PAGE_TYPE);
if (catPageType instanceof String) {
((DefaultTransaction) t).setType(catPageType.toString());
}
Object catPageUri = req.getAttribute(CatConstants.CAT_PAGE_URI);
if (catPageUri instanceof String) {
((DefaultTransaction) t).setName(catPageUri.toString());
}
}
}
private String getRequestURI(HttpServletRequest req) {
String url = req.getRequestURI();
int length = url.length();
StringBuilder sb = new StringBuilder(length);
for (int index = 0; index < length;) {
char c = url.charAt(index);
if (c == SPLIT && index < length - 1) {
sb.append(c);
StringBuilder nextSection = new StringBuilder();
boolean isNumber = false;
boolean first = true;
for (int j = index + 1; j < length; j++) {
char next = url.charAt(j);
if ((first || isNumber == true) && next != SPLIT) {
isNumber = isNumber(next);
first = false;
}
if (next == SPLIT) {
if (isNumber) {
sb.append("{num}");
} else {
sb.append(nextSection.toString());
}
index = j;
break;
} else if (j == length - 1) {
if (isNumber) {
sb.append("{num}");
} else {
nextSection.append(next);
sb.append(nextSection.toString());
}
index = j + 1;
break;
} else {
nextSection.append(next);
}
}
} else {
sb.append(c);
index++;
}
}
return sb.toString();
}
@Override
public void handle(Context ctx) throws IOException, ServletException {
HttpServletRequest req = ctx.getRequest();
Transaction t = Cat.newTransaction(ctx.getType(), getRequestURI(req));
try {
ctx.handle();
customizeStatus(t, req);
} catch (ServletException e) {
t.setStatus(e);
Cat.logError(e);
throw e;
} catch (IOException e) {
t.setStatus(e);
Cat.logError(e);
throw e;
} catch (Throwable e) {
t.setStatus(e);
Cat.logError(e);
throw new RuntimeException(e);
} finally {
customizeUri(t, req);
t.complete();
}
}
private boolean isNumber(char c) {
return (c >= '0' && c <= '9') || c == '.' || c == '-' || c == ',';
}
};
}
protected static class Context {
private FilterChain m_chain;
private List m_handlers;
private int m_index;
private HttpServletRequest m_request;
private HttpServletResponse m_response;
private boolean m_top;
private String m_type;
public Context(HttpServletRequest request, HttpServletResponse response, FilterChain chain, List handlers) {
m_request = request;
m_response = response;
m_chain = chain;
m_handlers = handlers;
}
public HttpServletRequest getRequest() {
return m_request;
}
public HttpServletResponse getResponse() {
return m_response;
}
public String getType() {
return m_type;
}
public void handle() throws IOException, ServletException {
if (m_index < m_handlers.size()) {
Handler handler = m_handlers.get(m_index++);
handler.handle(this);
} else {
m_chain.doFilter(m_request, m_response);
}
}
public boolean isTop() {
return m_top;
}
public void setTop(boolean top) {
m_top = top;
}
public void setType(String type) {
m_type = type;
}
}
protected static interface Handler {
public void handle(Context ctx) throws IOException, ServletException;
}
}
一键复制
编辑
Web IDE
原始数据
按行查看
历史