diff --git a/cat-client/pom.xml b/cat-client/pom.xml
index 85ff0d7479..e9a7a9e53a 100644
--- a/cat-client/pom.xml
+++ b/cat-client/pom.xml
@@ -30,6 +30,12 @@
junit
test
+
+ com.github.wangzihaogithub
+ spring-boot-protocol
+ 2.2.9
+ test
+
diff --git a/cat-client/src/main/java/com/dianping/cat/support/servlet/CatFilter.java b/cat-client/src/main/java/com/dianping/cat/support/servlet/CatFilter.java
index b4967698ab..2f19e29d35 100644
--- a/cat-client/src/main/java/com/dianping/cat/support/servlet/CatFilter.java
+++ b/cat-client/src/main/java/com/dianping/cat/support/servlet/CatFilter.java
@@ -38,6 +38,7 @@
import com.dianping.cat.Cat;
import com.dianping.cat.CatClientConstants;
import com.dianping.cat.message.Message;
+import com.dianping.cat.message.MessageTree;
import com.dianping.cat.message.Transaction;
import com.dianping.cat.message.context.TraceContextHelper;
import com.dianping.cat.message.internal.DefaultTransaction;
@@ -82,6 +83,7 @@ public void init(FilterConfig filterConfig) throws ServletException {
}
m_handlers.add(CatHandler.ENVIRONMENT);
+ m_handlers.add(CatHandler.ID_SETUP);
m_handlers.add(CatHandler.LOG_SPAN);
m_handlers.add(CatHandler.LOG_CLIENT_PAYLOAD);
}
@@ -104,6 +106,26 @@ public void handle(Context ctx) throws IOException, ServletException {
}
},
+ ID_SETUP {
+ @Override
+ public void handle(Context ctx) throws IOException, ServletException {
+ HttpServletRequest req = ctx.getRequest();
+ String id = req.getHeader("x-cat-id");
+ String parentId = req.getHeader("x-cat-parent-id");
+ String rootId = req.getHeader("x-cat-root-id");
+
+ if (id != null) {
+ MessageTree tree = TraceContextHelper.threadLocal().getMessageTree();
+
+ tree.setMessageId(id);
+ tree.setParentMessageId(parentId);
+ tree.setRootMessageId(rootId);
+ }
+
+ ctx.handle();
+ }
+ },
+
LOG_CLIENT_PAYLOAD {
@Override
public void handle(Context ctx) throws IOException, ServletException {
@@ -163,7 +185,7 @@ private void customizeStatus(Transaction t, HttpServletRequest req) {
if (catStatus != null) {
t.setStatus(catStatus.toString());
} else {
- t.success();
+ t.setStatus(Message.SUCCESS);
}
}
@@ -232,19 +254,13 @@ public void handle(Context ctx) throws IOException, ServletException {
};
}
- protected static class Context {
+ private static class Context {
private FilterChain m_chain;
private List m_handlers;
private int m_index;
- private String m_rootId;
-
- private String m_parentId;
-
- private String m_id;
-
private HttpServletRequest m_request;
private HttpServletResponse m_response;
@@ -261,26 +277,10 @@ public Context(HttpServletRequest request, HttpServletResponse response, FilterC
m_handlers = handlers;
}
- public String getId() {
- return m_id;
- }
-
- public String getParentId() {
- return m_parentId;
- }
-
public HttpServletRequest getRequest() {
return m_request;
}
- public HttpServletResponse getResponse() {
- return m_response;
- }
-
- public String getRootId() {
- return m_rootId;
- }
-
public String getType() {
return m_type;
}
@@ -299,18 +299,6 @@ public boolean isTop() {
return m_top;
}
- public void setId(String id) {
- m_id = id;
- }
-
- public void setParentId(String parentId) {
- m_parentId = parentId;
- }
-
- public void setRootId(String rootId) {
- m_rootId = rootId;
- }
-
public void setTop(boolean top) {
m_top = top;
}
@@ -320,7 +308,7 @@ public void setType(String type) {
}
}
- protected static interface Handler {
+ private static interface Handler {
public void handle(Context ctx) throws IOException, ServletException;
}
-}
+}
\ No newline at end of file
diff --git a/cat-client/src/test/java/com/dianping/cat/message/MessageAssert.java b/cat-client/src/test/java/com/dianping/cat/message/MessageAssert.java
index 011e74f4ae..4b3fe275d9 100644
--- a/cat-client/src/test/java/com/dianping/cat/message/MessageAssert.java
+++ b/cat-client/src/test/java/com/dianping/cat/message/MessageAssert.java
@@ -24,7 +24,7 @@ public static EventAssert event() {
return new EventAssert((Event) message);
}
- public static AssertSupport event(String type) {
+ public static EventAssert eventBy(String type) {
List types = new ArrayList();
for (MessageTree tree : new ArrayList(s_trees)) {
@@ -50,6 +50,26 @@ public static HeaderAssert header() {
return new HeaderAssert(tree);
}
+ public static HeaderAssert headerByTransaction(String type) {
+ List types = new ArrayList();
+
+ for (MessageTree tree : new ArrayList(s_trees)) {
+ Message message = tree.getMessage();
+
+ if (message instanceof Transaction) {
+ if (message.getType().equals(type)) {
+ return new HeaderAssert(tree);
+ } else if (!types.contains(message.getType())) {
+ types.add(message.getType());
+ }
+ }
+ }
+
+ Assert.fail(String.format("No message tree(%s) found, but was %s!", type, types.toString()));
+
+ return null; // this will NEVER be reached
+ }
+
public static void newTree(MessageTree tree) {
s_trees.push(tree);
}
@@ -71,70 +91,60 @@ public static TransactionAssert transaction() {
return new TransactionAssert((Transaction) message);
}
- public static MessageTreeAssert tree(String messageId) {
- List messageIds = new ArrayList();
+ public static TransactionAssert transactionBy(String type) {
+ List types = new ArrayList();
for (MessageTree tree : new ArrayList(s_trees)) {
- messageIds.add(tree.getMessageId());
+ Message message = tree.getMessage();
- if (tree.getMessageId().equals(messageId)) {
- return new MessageTreeAssert(tree);
+ if (message instanceof Transaction) {
+ if (message.getType().equals(type)) {
+ return new TransactionAssert((Transaction) message);
+ } else if (!types.contains(message.getType())) {
+ types.add(message.getType());
+ }
}
}
- Assert.fail(String.format("No message tree(%s) found, but was %s!", messageId, messageIds.toString()));
+ Assert.fail(String.format("No transaction(%s) found, but was %s!", type, types.toString()));
return null; // this will NEVER be reached
}
- public static class EventAssert extends AssertSupport {
- private Event m_event;
-
- public EventAssert(Event event) {
- super(event, "Event");
+ public static MessageTreeAssert tree(String messageId) {
+ List messageIds = new ArrayList();
- m_event = event;
- }
+ for (MessageTree tree : new ArrayList(s_trees)) {
+ messageIds.add(tree.getMessageId());
- public Event event() {
- return m_event;
+ if (tree.getMessageId().equals(messageId)) {
+ return new MessageTreeAssert(tree);
+ }
}
- }
- public static class HeaderAssert {
- private MessageTree m_tree;
+ Assert.fail(String.format("No message tree(%s) found, but was %s!", messageId, messageIds.toString()));
- public HeaderAssert(MessageTree tree) {
- m_tree = tree;
- }
+ return null; // this will NEVER be reached
+ }
- public HeaderAssert domain(String domain) {
- Assert.assertEquals("Domain mismatched!", domain, m_tree.getDomain());
- return this;
- }
+ public static MessageTreeAssert treeByTransaction(String type) {
+ List types = new ArrayList();
- public HeaderAssert messageId(String messageId) {
- Assert.assertEquals("Message id mismatched!", messageId, m_tree.getMessageId());
- return this;
- }
+ for (MessageTree tree : new ArrayList(s_trees)) {
+ Message message = tree.getMessage();
- public HeaderAssert messageIdStartsWith(String messageIdPrefix) {
- if (!m_tree.getMessageId().startsWith(messageIdPrefix)) {
- Assert.fail(String.format("Message id %s does not start with %s!", m_tree.getMessageId(), messageIdPrefix));
+ if (message instanceof Transaction) {
+ if (message.getType().equals(type)) {
+ return new MessageTreeAssert(tree);
+ } else if (!types.contains(message.getType())) {
+ types.add(message.getType());
+ }
}
-
- return this;
}
- public HeaderAssert parentMessageId(String parentMessageId) {
- Assert.assertEquals("Parent message id mismatched!", parentMessageId, m_tree.getParentMessageId());
- return this;
- }
+ Assert.fail(String.format("No message tree(%s) found, but was %s!", type, types.toString()));
- public HeaderAssert rootMessageId(String rootMessageId) {
- Assert.assertEquals("Root message id mismatched!", rootMessageId, m_tree.getRootMessageId());
- return this;
- }
+ return null; // this will NEVER be reached
}
@SuppressWarnings("unchecked")
@@ -197,6 +207,76 @@ public T type(String type) {
Assert.assertEquals(format("%s type mismatched!", m_class), type, m_message.getType());
return (T) this;
}
+
+ public AssertSupport withData() {
+ Assert.assertNotNull("Message id is NULL!", m_message.getData());
+ return this;
+ }
+ }
+
+ public static class EventAssert extends AssertSupport {
+ private Event m_event;
+
+ public EventAssert(Event event) {
+ super(event, "Event");
+
+ m_event = event;
+ }
+
+ public Event event() {
+ return m_event;
+ }
+ }
+
+ public static class HeaderAssert {
+ private MessageTree m_tree;
+
+ public HeaderAssert(MessageTree tree) {
+ m_tree = tree;
+ }
+
+ public HeaderAssert domain(String domain) {
+ Assert.assertEquals("Domain mismatched!", domain, m_tree.getDomain());
+ return this;
+ }
+
+ public HeaderAssert messageId(String messageId) {
+ Assert.assertEquals("Message id mismatched!", messageId, m_tree.getMessageId());
+ return this;
+ }
+
+ public HeaderAssert messageIdStartsWith(String messageIdPrefix) {
+ if (!m_tree.getMessageId().startsWith(messageIdPrefix)) {
+ Assert.fail(String.format("Message id %s does not start with %s!", m_tree.getMessageId(), messageIdPrefix));
+ }
+
+ return this;
+ }
+
+ public HeaderAssert parentMessageId(String parentMessageId) {
+ Assert.assertEquals("Parent message id mismatched!", parentMessageId, m_tree.getParentMessageId());
+ return this;
+ }
+
+ public HeaderAssert rootMessageId(String rootMessageId) {
+ Assert.assertEquals("Root message id mismatched!", rootMessageId, m_tree.getRootMessageId());
+ return this;
+ }
+
+ public HeaderAssert withMessageId() {
+ Assert.assertNotNull("Message id is NULL!", m_tree.getMessageId());
+ return this;
+ }
+
+ public HeaderAssert withParentMessageId() {
+ Assert.assertNotNull("Message id is NULL!", m_tree.getParentMessageId());
+ return this;
+ }
+
+ public HeaderAssert withRootMessageId() {
+ Assert.assertNotNull("Message id is NULL!", m_tree.getRootMessageId());
+ return this;
+ }
}
public static class MessageTreeAssert {
diff --git a/cat-client/src/test/java/com/dianping/cat/support/servlet/CatFilterTest.java b/cat-client/src/test/java/com/dianping/cat/support/servlet/CatFilterTest.java
index 55ded29890..77eb181d1a 100644
--- a/cat-client/src/test/java/com/dianping/cat/support/servlet/CatFilterTest.java
+++ b/cat-client/src/test/java/com/dianping/cat/support/servlet/CatFilterTest.java
@@ -21,169 +21,172 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.TimeUnit;
+import javax.servlet.DispatcherType;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.junit.After;
import org.junit.Assert;
-import org.junit.Ignore;
+import org.junit.Before;
import org.junit.Test;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Message;
+import com.dianping.cat.message.MessageAssert;
+import com.dianping.cat.message.MessageAssert.HeaderAssert;
+import com.dianping.cat.message.MessageAssert.TransactionAssert;
+import com.dianping.cat.message.MessageTree;
import com.dianping.cat.message.Transaction;
import com.dianping.cat.message.context.TraceContextHelper;
+import com.dianping.cat.message.pipeline.MessageHandler;
+import com.dianping.cat.message.pipeline.MessageHandlerAdaptor;
+import com.dianping.cat.message.pipeline.MessageHandlerContext;
import com.dianping.cat.support.Files;
import com.dianping.cat.support.Urls;
+import com.dianping.cat.support.Urls.UrlIO;
+import com.github.netty.StartupServer;
+import com.github.netty.protocol.HttpServletProtocol;
+import com.github.netty.protocol.servlet.ServletContext;
-@Ignore
public class CatFilterTest {
- // @After
- // public void after() throws Exception {
- // super.stopServer();
- // }
- //
- // @Before
- // public void before() throws Exception {
- // System.setProperty("devMode", "true");
- // super.startServer();
- // }
- //
- // @Override
- // protected String getContextPath() {
- // return "/mock";
- // }
- //
- // @Override
- // protected int getServerPort() {
- // return 2282;
- // }
- //
- // @Override
- // protected boolean isWebXmlDefined() {
- // return false;
- // }
- //
- // @Override
- // protected void postConfigure(WebAppContext context) {
- // context.addServlet(MockServlet.class, "/*");
- // context.addFilter(CatFilter.class, "/*", Handler.REQUEST);
- // }
+ private HttpServer m_server;
+
+ @After
+ public void after() {
+ m_server.close();
+ MessageAssert.reset();
+ }
+
+ @Before
+ public void before() {
+ // Cat.getBootstrap().testMode();
+ Cat.getBootstrap().getComponentContext().registerComponent(MessageHandler.class, new MockMessageHandler());
+ Cat.getBootstrap().initializeByDomain("mockApp");
+
+ m_server = new HttpServer();
+ m_server.start();
+ }
+
+ private String httpCall(String uri, String... headers) throws IOException {
+ String url = "http://localhost:2282" + uri;
+ UrlIO u = Urls.forIO().connectTimeout(1000);
+ Map> responseHeaders = new HashMap>();
+
+ for (int i = 0; i < headers.length; i += 2) {
+ u.header(headers[i], headers[i + 1]);
+ }
+
+ InputStream in = u.openStream(url, responseHeaders);
+ String content = Files.forIO().readFrom(in, "utf-8");
+
+ return content;
+ }
@Test
public void testMode0() throws Exception {
- String url = "http://localhost:2282/mock/mode0";
- InputStream in = Urls.forIO().openStream(url);
- String content = Files.forIO().readFrom(in, "utf-8");
+ Assert.assertEquals("/mock/mode0", httpCall("/mock/mode0?k1=v1&k2=v2"));
- Assert.assertEquals("mock content here!", content);
+ TransactionAssert ta = MessageAssert.transaction().type("URL").name("/mock/mode0").success().complete();
- TimeUnit.MILLISECONDS.sleep(100);
+ ta.childEvent(0).type("URL").name("URL.Server");
+ ta.childEvent(1).type("URL").name("URL.Method").data("HTTP/GET /mock/mode0?k1=v1&k2=v2");
+ ta.childTransaction(0).type("MockServlet").name("/mode0");
}
@Test
public void testMode1() throws Exception {
- String url = "http://localhost:2282/mock/mode1";
- Transaction t = Cat.newTransaction("Mock", "testMode1");
+ Transaction t = Cat.newTransaction("FilterTest", "testMode1");
+ String id = TraceContextHelper.threadLocal().getMessageTree().getMessageId();
+ String childId = TraceContextHelper.createMessageId();
- try {
- String childId = TraceContextHelper.createMessageId();
- String id = TraceContextHelper.threadLocal().getMessageTree().getMessageId();
+ Cat.logEvent("RemoteCall", "/mock/mode1", Message.SUCCESS, childId);
- Cat.logEvent("RemoteCall", url, Message.SUCCESS, childId);
+ Assert.assertEquals("/mock/mode1", httpCall("/mock/mode1?k1=v1&k2=v2", //
+ "x-cat-id", childId, //
+ "x-cat-parent-id", id, //
+ "x-cat-root-id", id //
+ ));
- InputStream in = Urls.forIO().connectTimeout(100) //
- .header("X-Cat-Id", childId) //
- .header("X-Cat-Parent-Id", id) //
- .header("X-Cat-Root-Id", id) //
- .openStream(url);
- String content = Files.forIO().readFrom(in, "utf-8");
+ t.success().complete();
- Assert.assertEquals("mock content here!", content);
+ // child message tree
+ {
+ HeaderAssert ha = MessageAssert.headerByTransaction("URL");
- t.setStatus(Message.SUCCESS);
- } finally {
- t.complete();
- }
+ ha.withMessageId().withParentMessageId().withRootMessageId();
- TimeUnit.MILLISECONDS.sleep(100);
- }
+ TransactionAssert ta = MessageAssert.transactionBy("URL").name("/mock/mode1").success().complete();
- @Test
- public void testMode2() throws Exception {
- String url = "http://localhost:2282/mock/mode2";
- Map> headers = new HashMap>();
- InputStream in = Urls.forIO().connectTimeout(100) //
- .header("X-Cat-Source", "container") //
- .header("X-CAT-TRACE-MODE", "true") //
- .openStream(url, headers);
- String content = Files.forIO().readFrom(in, "utf-8");
+ ta.childEvent(0).type("URL").name("URL.Server");
+ ta.childEvent(1).type("URL").name("URL.Method").data("HTTP/GET /mock/mode1?k1=v1&k2=v2");
+ ta.childTransaction(0).type("MockServlet").name("/mode1");
+ }
- Assert.assertEquals("mock content here!", content);
+ // parent message tree
+ {
+ HeaderAssert ha = MessageAssert.headerByTransaction("FilterTest");
- String id = getHeader(headers, "X-CAT-ID");
- String parentId = getHeader(headers, "X-CAT-PARENT-ID");
- String rootId = getHeader(headers, "X-CAT-ROOT-ID");
+ ha.withMessageId();
- Assert.assertNotNull(id);
- Assert.assertNotNull(parentId);
- Assert.assertNotNull(rootId);
- Assert.assertFalse(id.equals(rootId));
+ TransactionAssert ta = MessageAssert.transactionBy("FilterTest").name("testMode1").success().complete();
- TimeUnit.MILLISECONDS.sleep(100);
+ ta.childEvent(0).type("RemoteCall").name("/mock/mode1").withData();
+ }
}
- private String getHeader(Map> headers, String name) {
- List values = headers.get(name);
+ private class HttpServer extends StartupServer {
+ public HttpServer() {
+ super(2282);
+
+ ServletContext servletContext = new ServletContext();
+ EnumSet types = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD);
+
+ servletContext.addFilter("cat-filter", new CatFilter()) //
+ .addMappingForUrlPatterns(types, false, "/*");
+ servletContext.addServlet("mock-servlet", new MockServlet()) //
+ .addMapping("/mock/*");
- if (values != null) {
- int len = values.size();
+ HttpServletProtocol protocol = new HttpServletProtocol(servletContext);
+ protocol.setMaxBufferBytes(1024 * 1024);
- if (len == 0) {
- return null;
- } else if (len == 1) {
- return values.get(0);
- } else {
- StringBuilder sb = new StringBuilder();
- boolean first = true;
+ getProtocolHandlers().add(protocol);
+ getServerListeners().add(protocol);
+ }
+ }
- for (String value : values) {
- if (first) {
- first = false;
- } else {
- sb.append(',');
- }
+ private static class MockMessageHandler extends MessageHandlerAdaptor {
+ @Override
+ public int getOrder() {
+ return 0;
+ }
- sb.append(value);
- }
+ @Override
+ protected void handleMessagreTree(MessageHandlerContext ctx, MessageTree tree) {
+ MessageAssert.newTree(tree);
- return sb.toString();
- }
- } else {
- return null;
+ System.out.println(tree);
}
}
- public static class MockServlet extends HttpServlet {
+ private static class MockServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
PrintWriter writer = res.getWriter();
- Transaction t = Cat.newTransaction("Mock", req.getRequestURI());
+ Transaction t = Cat.newTransaction("MockServlet", req.getPathInfo());
try {
- writer.write("mock content here!");
-
- // no status set by purpose
+ writer.write(req.getRequestURI());
} finally {
- t.complete();
+ t.success().complete();
}
}
}