CatFilter.java 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. package com.dianping.cat.servlet;
  2. import java.io.IOException;
  3. import java.util.ArrayList;
  4. import java.util.List;
  5. import javax.servlet.Filter;
  6. import javax.servlet.FilterChain;
  7. import javax.servlet.FilterConfig;
  8. import javax.servlet.ServletException;
  9. import javax.servlet.ServletRequest;
  10. import javax.servlet.ServletResponse;
  11. import javax.servlet.http.HttpServletRequest;
  12. import javax.servlet.http.HttpServletResponse;
  13. import org.unidal.helper.Joiners;
  14. import org.unidal.helper.Joiners.IBuilder;
  15. import com.dianping.cat.Cat;
  16. import com.dianping.cat.CatConstants;
  17. import com.dianping.cat.configuration.client.entity.Server;
  18. import com.dianping.cat.message.Message;
  19. import com.dianping.cat.message.Transaction;
  20. import com.dianping.cat.message.internal.DefaultMessageManager;
  21. import com.dianping.cat.message.internal.DefaultTransaction;
  22. public class CatFilter implements Filter {
  23. private List<Handler> m_handlers = new ArrayList<Handler>();
  24. @Override
  25. public void destroy() {
  26. }
  27. @Override
  28. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
  29. ServletException {
  30. Context ctx = new Context((HttpServletRequest) request, (HttpServletResponse) response, chain, m_handlers);
  31. ctx.handle();
  32. }
  33. protected String getOriginalUrl(ServletRequest request) {
  34. return ((HttpServletRequest) request).getRequestURI();
  35. }
  36. @Override
  37. public void init(FilterConfig filterConfig) throws ServletException {
  38. m_handlers.add(CatHandler.ENVIRONMENT);
  39. m_handlers.add(CatHandler.LOG_SPAN);
  40. m_handlers.add(CatHandler.LOG_CLIENT_PAYLOAD);
  41. m_handlers.add(CatHandler.ID_SETUP);
  42. }
  43. private static enum CatHandler implements Handler {
  44. ENVIRONMENT {
  45. @Override
  46. public void handle(Context ctx) throws IOException, ServletException {
  47. HttpServletRequest req = ctx.getRequest();
  48. boolean top = !Cat.getManager().hasContext();
  49. ctx.setTop(top);
  50. if (top) {
  51. ctx.setType(CatConstants.TYPE_URL);
  52. setTraceMode(req);
  53. } else {
  54. ctx.setType(CatConstants.TYPE_URL_FORWARD);
  55. }
  56. ctx.handle();
  57. }
  58. protected void setTraceMode(HttpServletRequest req) {
  59. String traceMode = "X-CAT-TRACE-MODE";
  60. String headMode = req.getHeader(traceMode);
  61. if ("true".equals(headMode)) {
  62. Cat.getManager().setTraceMode(true);
  63. }
  64. }
  65. },
  66. ID_SETUP {
  67. private String m_servers;
  68. private String getCatServer() {
  69. if (m_servers == null) {
  70. DefaultMessageManager manager = (DefaultMessageManager) Cat.getManager();
  71. List<Server> servers = manager.getConfigManager().getServers();
  72. m_servers = Joiners.by(',').join(servers, new IBuilder<Server>() {
  73. @Override
  74. public String asString(Server server) {
  75. String ip = server.getIp();
  76. Integer httpPort = server.getHttpPort();
  77. return ip + ":" + httpPort;
  78. }
  79. });
  80. }
  81. return m_servers;
  82. }
  83. @Override
  84. public void handle(Context ctx) throws IOException, ServletException {
  85. boolean isTraceMode = Cat.getManager().isTraceMode();
  86. HttpServletResponse res = ctx.getResponse();
  87. if (isTraceMode) {
  88. String id = Cat.getCurrentMessageId();
  89. res.setHeader("X-CAT-ROOT-ID", id);
  90. res.setHeader("X-CAT-SERVER", getCatServer());
  91. }
  92. ctx.handle();
  93. }
  94. },
  95. LOG_CLIENT_PAYLOAD {
  96. @Override
  97. public void handle(Context ctx) throws IOException, ServletException {
  98. HttpServletRequest req = ctx.getRequest();
  99. String type = ctx.getType();
  100. if (ctx.isTop()) {
  101. logRequestClientInfo(req, type);
  102. logRequestPayload(req, type);
  103. } else {
  104. logRequestPayload(req, type);
  105. }
  106. ctx.handle();
  107. }
  108. protected void logRequestClientInfo(HttpServletRequest req, String type) {
  109. StringBuilder sb = new StringBuilder(1024);
  110. String ip = "";
  111. String ipForwarded = req.getHeader("x-forwarded-for");
  112. if (ipForwarded == null) {
  113. ip = req.getRemoteAddr();
  114. } else {
  115. ip = ipForwarded;
  116. }
  117. sb.append("IPS=").append(ip);
  118. sb.append("&VirtualIP=").append(req.getRemoteAddr());
  119. sb.append("&Server=").append(req.getServerName());
  120. sb.append("&Referer=").append(req.getHeader("referer"));
  121. sb.append("&Agent=").append(req.getHeader("user-agent"));
  122. Cat.logEvent(type, type + ".Server", Message.SUCCESS, sb.toString());
  123. }
  124. protected void logRequestPayload(HttpServletRequest req, String type) {
  125. StringBuilder sb = new StringBuilder(256);
  126. sb.append(req.getScheme().toUpperCase()).append('/');
  127. sb.append(req.getMethod()).append(' ').append(req.getRequestURI());
  128. String qs = req.getQueryString();
  129. if (qs != null) {
  130. sb.append('?').append(qs);
  131. }
  132. Cat.logEvent(type, type + ".Method", Message.SUCCESS, sb.toString());
  133. }
  134. },
  135. LOG_SPAN {
  136. public static final char SPLIT = '/';
  137. private void customizeStatus(Transaction t, HttpServletRequest req) {
  138. Object catStatus = req.getAttribute(CatConstants.CAT_STATE);
  139. if (catStatus != null) {
  140. t.setStatus(catStatus.toString());
  141. } else {
  142. t.setStatus(Message.SUCCESS);
  143. }
  144. }
  145. private void customizeUri(Transaction t, HttpServletRequest req) {
  146. if (t instanceof DefaultTransaction) {
  147. Object catPageType = req.getAttribute(CatConstants.CAT_PAGE_TYPE);
  148. if (catPageType instanceof String) {
  149. ((DefaultTransaction) t).setType(catPageType.toString());
  150. }
  151. Object catPageUri = req.getAttribute(CatConstants.CAT_PAGE_URI);
  152. if (catPageUri instanceof String) {
  153. ((DefaultTransaction) t).setName(catPageUri.toString());
  154. }
  155. }
  156. }
  157. private String getRequestURI(HttpServletRequest req) {
  158. String url = req.getRequestURI();
  159. int length = url.length();
  160. StringBuilder sb = new StringBuilder(length);
  161. for (int index = 0; index < length;) {
  162. char c = url.charAt(index);
  163. if (c == SPLIT && index < length - 1) {
  164. sb.append(c);
  165. StringBuilder nextSection = new StringBuilder();
  166. boolean isNumber = false;
  167. boolean first = true;
  168. for (int j = index + 1; j < length; j++) {
  169. char next = url.charAt(j);
  170. if ((first || isNumber == true) && next != SPLIT) {
  171. isNumber = isNumber(next);
  172. first = false;
  173. }
  174. if (next == SPLIT) {
  175. if (isNumber) {
  176. sb.append("{num}");
  177. } else {
  178. sb.append(nextSection.toString());
  179. }
  180. index = j;
  181. break;
  182. } else if (j == length - 1) {
  183. if (isNumber) {
  184. sb.append("{num}");
  185. } else {
  186. nextSection.append(next);
  187. sb.append(nextSection.toString());
  188. }
  189. index = j + 1;
  190. break;
  191. } else {
  192. nextSection.append(next);
  193. }
  194. }
  195. } else {
  196. sb.append(c);
  197. index++;
  198. }
  199. }
  200. return sb.toString();
  201. }
  202. @Override
  203. public void handle(Context ctx) throws IOException, ServletException {
  204. HttpServletRequest req = ctx.getRequest();
  205. Transaction t = Cat.newTransaction(ctx.getType(), getRequestURI(req));
  206. try {
  207. ctx.handle();
  208. customizeStatus(t, req);
  209. } catch (ServletException e) {
  210. t.setStatus(e);
  211. Cat.logError(e);
  212. throw e;
  213. } catch (IOException e) {
  214. t.setStatus(e);
  215. Cat.logError(e);
  216. throw e;
  217. } catch (Throwable e) {
  218. t.setStatus(e);
  219. Cat.logError(e);
  220. throw new RuntimeException(e);
  221. } finally {
  222. customizeUri(t, req);
  223. t.complete();
  224. }
  225. }
  226. private boolean isNumber(char c) {
  227. return (c >= '0' && c <= '9') || c == '.' || c == '-' || c == ',';
  228. }
  229. };
  230. }
  231. protected static class Context {
  232. private FilterChain m_chain;
  233. private List<Handler> m_handlers;
  234. private int m_index;
  235. private HttpServletRequest m_request;
  236. private HttpServletResponse m_response;
  237. private boolean m_top;
  238. private String m_type;
  239. public Context(HttpServletRequest request, HttpServletResponse response, FilterChain chain, List<Handler> handlers) {
  240. m_request = request;
  241. m_response = response;
  242. m_chain = chain;
  243. m_handlers = handlers;
  244. }
  245. public HttpServletRequest getRequest() {
  246. return m_request;
  247. }
  248. public HttpServletResponse getResponse() {
  249. return m_response;
  250. }
  251. public String getType() {
  252. return m_type;
  253. }
  254. public void handle() throws IOException, ServletException {
  255. if (m_index < m_handlers.size()) {
  256. Handler handler = m_handlers.get(m_index++);
  257. handler.handle(this);
  258. } else {
  259. m_chain.doFilter(m_request, m_response);
  260. }
  261. }
  262. public boolean isTop() {
  263. return m_top;
  264. }
  265. public void setTop(boolean top) {
  266. m_top = top;
  267. }
  268. public void setType(String type) {
  269. m_type = type;
  270. }
  271. }
  272. protected static interface Handler {
  273. public void handle(Context ctx) throws IOException, ServletException;
  274. }
  275. }