Tracing in Jersey

A common complaint we have been hearing is that JAX-RS/Jersey can be hard to debug when the application is not behaving as expected, for example "why the \*!@& is my resource class not matching and instead the client is receiving a 404 response?"

It is difficult for the devloper to know what is going on because there is no visibility to how the request is matched and dispatched to the application.

A number of JAX-RS and Jersey features were inspired by Stapler the underlying Web/HTTP framework for Hudson. And tracing is another idea. With Hudson it is possible set a system property and trace messages in the form of response headers will be returned to the client, as described here.

Jersey now supports the same feature implemented in 1.1.5-ea-SNAPSHOT. Adding the following servlet/filter initialization parameter enables tracing:


If we modify the bookstore sample to include the above initialization parameter in the web.xml and go to the URL http://localhost:8080/bookstore/items/3/tracks/2/ then analyze the response headers using firebug we can see:

Trace headers have a number associated with. Not all clients or servers may preserve the order in which headers are written (the Jersey server and client does) so the numbering is useful to re-construct the order of tracing. It also helps when referring to a particular trace statement.

Trace 001:

X-Jersey-Trace-001  match path "/items/3/tracks/2/" -> "/application\\.wadl(/.\*)?", "/happy(/.\*)?", "(/.\*)?"

presents the request path and the initial set of regular expressions that will be matched, in order from left to right.

Trace 002:

X-Jersey-Trace-002  accept right hand path 
                        java.util.regex.Matcher[pattern=(/.\*)? region=0,18 lastmatch=/items/3/tracks/2/]: 
                        "/items/3/tracks/2/" -> "" : "/items/3/tracks/2/" 

presents what regular expression was matched in trace 001, "(/.\*)?". It is called "accept right hand path" because some left hand path of the request URI has been matched by an @Path declaration, "", leaving some right hand path of the request URI, "/items/3/tracks/2/", to be further matched (the URI matching process will terminate when there is no right hand path left).

Trace 003:

X-Jersey-Trace-003  accept resource: "" -> @Path("/") com.sun.jersey.samples.bookstore.resources.Bookstore@9f9655 

presents the resource that matched the left hand path in trace 002. In this case it is the Bookstore resource that is annotated with @Path("/").

Trace 004:

X-Jersey-Trace-004  match path "/items/3/tracks/2/" -> "/items/([\^/]+?)(/.\*)?", ""

presents a further match on the right hand path in trace 002.

Trace 005:

X-Jersey-Trace-005  accept right hand path 
                        java.util.regex.Matcher[pattern=/items/([\^/]+?)(/.\*)? region=0,18 lastmatch=/items/3/tracks/2/]: 
                        "/items/3/tracks/2/" -> "/items/3" : "/tracks/2/"

presents the left hand path, "/items/3", and the right hand path, "/tracks/2", that matched the regular expression, "/items/([\^/]+?)(/.\*)?", from the ordered set in trace 004.

Trace 006:

X-Jersey-Trace-006  accept sub-resource locator: "" : "items/3/" -> @Path("/items/{itemid}/") 
                        com.sun.jersey.samples.bookstore.resources.Bookstore@9f9655.getItem(java.lang.String) = 

presents the sub-resource locator that was invoked on the Bookstore resource. In this case it is the Java method getItem annotated with @Path("/items/{itemsid}"). This sub-resource locator returns an instance of the CD resource to match more of the right hand path, "/tracks/2".

The same pattern for traces 004 to 006 repeats itself for traces 007 to 009 with a sub-resource locator being matched on the CD resource that returns a Track resource.

Trace 010 indicates that URI matching has completed because there is no right hand path left and resource methods are ready to be matched.

Trace 011:

X-Jersey-Trace-011  accept resource methods: "items/3/tracks/2/", GET -> 

presents that resource methods will be matched on the Track resource for the GET request.

Trace 012

X-Jersey-Trace-012  accept implicit view: "" -> com.sun.jersey.samples.bookstore.resources.Track@6fb5ef, 

presents that an implicit view has been selected to process the GET request. The Track resource is the controller and the model, the JSP "/com/sun/jersey/samples/bookstore/resources/Track/index.jsp" is the view that processes the model.

Trace 013

X-Jersey-Trace-013  matched message body writer: com.sun.jersey.spi.template.ResolvedViewable@817f19, 
                        "text/html;qs=5" -> com.sun.jersey.server.impl.template.ViewableMessageBodyWriter@9f17b1 

presents that a message body writer was matched to process the response entity returned by the implicit view in trace 012. The ViewableMessageBodyWriter is selected to write a ResolvedViewable with the media type "text/html;qs=5".

The above traces present how Jersey is returning an HTML page to the browser. Curl can be utilized to obtain XML instead:

$ curl -i http://localhost:8080/bookstore/items/3/tracks/2/
HTTP/1.1 200 OK
X-Powered-By: Servlet/3.0
Server: GlassFish v3
X-Jersey-Trace-000: accept root resource classes: "/items/3/tracks/2/"
X-Jersey-Trace-001: match path "/items/3/tracks/2/" -> "/application\\.wadl(/.\*)?", "/happy(/.\*)?", "(/.\*)?"
X-Jersey-Trace-002: accept right hand path 
                        java.util.regex.Matcher[pattern=(/.\*)? region=0,18 lastmatch=/items/3/tracks/2/]: 
                        "/items/3/tracks/2/" -> "" : "/items/3/tracks/2/"
X-Jersey-Trace-003: accept resource: "" -> @Path("/") com.sun.jersey.samples.bookstore.resources.Bookstore@19d1c871
X-Jersey-Trace-004: match path "/items/3/tracks/2/" -> "/items/([\^/]+?)(/.\*)?", ""
X-Jersey-Trace-005: accept right hand path 
                        java.util.regex.Matcher[pattern=/items/([\^/]+?)(/.\*)? region=0,18 lastmatch=/items/3/tracks/2/]: 
                        "/items/3/tracks/2/" -> "/items/3" : "/tracks/2/"
X-Jersey-Trace-006: accept sub-resource locator: "" : "items/3/" -> @Path("/items/{itemid}/") 
                        com.sun.jersey.samples.bookstore.resources.Bookstore@19d1c871.getItem(java.lang.String) = 
X-Jersey-Trace-007: match path "/tracks/2/" -> "/tracks/([\^/]+?)(/.\*)?", ""
X-Jersey-Trace-008: accept right hand path 
                        java.util.regex.Matcher[pattern=/tracks/([\^/]+?)(/.\*)? region=0,10 lastmatch=/tracks/2/]: 
                        "/tracks/2/" -> "/tracks/2/" : ""
X-Jersey-Trace-009: accept sub-resource locator: "items/3/" : "tracks/2/" -> @Path("/tracks/{num}/") 
                        com.sun.jersey.samples.bookstore.resources.CD@4eb24759.getTrack(int) = 
X-Jersey-Trace-010: match path "" -> ""
X-Jersey-Trace-011: accept resource methods: "items/3/tracks/2/", GET -> 
X-Jersey-Trace-012: matched resource method: public com.sun.jersey.samples.bookstore.resources.Track 
X-Jersey-Trace-013: matched message body writer: com.sun.jersey.samples.bookstore.resources.Track@435792a0, 
                        "application/xml" -> com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$App@27cce278
Content-Type: application/xml

The traces are the same as previously presented up to trace 012. Trace 012 presents the resource method getXml that is invoked on the Track resource. Trace 013 presents that XMLRootElementProvider has been selected to serialize out Track with the media type "application/xml".

Like Stapler/Hudson Jersey also supports per-request tracing. Adding the following servlet/filter initialization parameter enables per-request tracing:

The client enables tracing by sending a request header "X-Jersey-Trace-Accept" with any value.


[Trackback] This post was mentioned on Twitter by James Strachan: like the new jersey tracing feature

Posted by uberVU - social comments on November 27, 2009 at 11:19 AM CET #

Neat feature... Keep 'em coming!

Posted by Solomon Duskis on November 30, 2009 at 02:26 PM CET #

[Trackback] See [blog post by Paul Sandoz|] null

Posted by JIRA: Atlassian REST on December 06, 2009 at 09:15 PM CET #

Post a Comment:
  • HTML Syntax: NOT allowed



« April 2014