Troubleshooting Jersey REST Server and Client
The logging in Jersey, the reference JAX-RS implementation, is little sub-optimal. For example if it cannot find a method producing the expected MIME type then it will return "Unsupported mime type" to the client but won't log anything (which mime type was requested, which mime types are actually available, ...). Debugging it isn't exactly easy either, so what to do?
Well, I don't know the ultimate solution but want to share few tips.
To enable it for the Jersey Test framework you'd do something like this in your test class:
To enable it for the server itself (though might be not such a good idea to enable this in production), you would set it in web.xml:
provided that you have the class
As you can see, there is still no info regarding accepted/supported MIME types.
Notice that even thoug the log level is ALL, the logs still might be quite useless to troubleshoot some problems (such s the unsupported MIME type).
Client:
Server:
Well, I don't know the ultimate solution but want to share few tips.
Enable Tracing of Request Matching
Jersey since version 1.1.5 supports request matching tracing, provided somehow detailed information about the matching process in the response headers.To enable it for the Jersey Test framework you'd do something like this in your test class:
public class MyJerseyTest extends JerseyTest {
public MyJerseyTest() {
super(new WebAppDescriptor
.Builder("my.package.with.jaxrs.resources")
.contextPath("myCtxPath")
.servletPath("/myServletPath")
.initParam("com.sun.jersey.config.feature.Trace", "true")
.build());
}
// Your test methods here ...; you can get the trace headers via ClientResponse#getHeaders()
}
To enable it for the server itself (though might be not such a good idea to enable this in production), you would set it in web.xml:
<web-app ...> <servlet> <servlet-name>Jersey REST Service for value codes</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> ... <init-param> <param-name>com.sun.jersey.config.feature.Trace</param-name> <param-value>true</param-value> </init-param>The headers, which you can obtain via e.g. curl -i or via
</servlet> ... </web-app>
ClientResponse#getHeaders()
, might look like this:
{X-Jersey-Trace-008=[mapped exception to response: javax.ws.rs.WebApplicationException@56f9659d -> 415 (Unsupported Media Type)],
X-Jersey-Trace-002=[accept right hand path java.util.regex.Matcher[pattern=/myResource/([-0-9a-zA-Z_]+)(/.*)? region=0,17 lastmatch=/myResource/23/mySubresources]: "/myResource/23/mySubresources" -> "/myResource/23" : "/mySubresources"],
X-Jersey-Trace-003=[accept resource: "myResource/23" -> @Path("/myResource/{item: [-0-9a-zA-Z_]+}") com.example.MyExampleResource@41babddb],
X-Jersey-Trace-000=[accept root resource classes: "/myResource/23/mySubresources"],
X-Jersey-Trace-001=[match path "/myResource/23/mySubresources" -> "/application\.wadl(/.*)?", "/myResource/([-0-9a-zA-Z_]+)(/.*)?", "/myResource(/.*)?", "/mySubresources/([-0-9a-zA-Z_]+)(/.*)?"],
X-Jersey-Trace-006=[accept sub-resource methods: "myResource/23" : "/mySubresources", GET -> com.example.MyExampleResource@41babddb],
X-Jersey-Trace-007=[accept termination (matching failure): "/mySubresources"],
X-Jersey-Trace-004=[match path "/mySubresources" -> "/mySubresources(/)?", ""],
X-Jersey-Trace-005=[accept right hand path java.util.regex.Matcher[pattern=/mySubresources(/)? region=0,6 lastmatch=/mySubresources]: "/mySubresources" -> "/mySubresources" : ""]
, Transfer-Encoding=[chunked], Date=[Tue, 31 Jan 2012 14:48:26 GMT], server=[grizzly/2.1.2], Content-Type=[text/html; charset=iso-8859-1]}
provided that you have the class
com.example.MyExampleResource
annotated with @Path("/myResource/{item: [-0-9a-zA-Z_]+}")
and a method annotated with @GET @Path("mySubresources")
(and the class field @PathParam("item") Long item
).As you can see, there is still no info regarding accepted/supported MIME types.
Get Detailed Logging Into a File
Jersey uses Java logging, which is know for being difficult to configure. Here is a dirty trick to get detailed Jersey logs into a file:
public class MyJerseyTest extends JerseyTest {
@BeforeClass public static void setupJerseyLog() throws Exception {
Handler fh = new ConsoleHandler(); // FileHandler("/tmp/jersey_test.log");
Logger.getLogger("").addHandler(fh);
Logger.getLogger("com.sun.jersey").setLevel(Level.FINEST);
}
// Your test methods here ...
}
Notice that even thoug the log level is ALL, the logs still might be quite useless to troubleshoot some problems (such s the unsupported MIME type).
Configure Request/Response Logging Filters
Jersey provides a LoggingFilter that can be used to log request/response entities and it can be installed both into the server and the client. The com.sun.jersey.api.container.filter.LoggingFilter may be installed into the server via init-params, the com.sun.jersey.api.client.filter.LoggingFilter may be installed into the client via client.addFilter. JerseTest automatically installs the LoggingFilter into the client it uses if the system property "enableLogging" is set (to whatever- this must happen before JersyTest's constuctor).Client:
// Alternatively, call this before the JersetTest constructor: System.setProperty("enableLogging", "true");
WebResource resource = resource();
resource.addFilter(new com.sun.jersey.api.client.filter.LoggingFilter());
ClientResponse response = resource.path(..)...get(..);
Server:
public MyJerseyIT() {
super(new WebAppDescriptor.Builder()
... // set paths, packages etc.
.initParam("com.sun.jersey.spi.container.ContainerRequestFilters", "com.sun.jersey.api.container.filter.LoggingFilter")
.build());
}