blob: 0f561e9f238b7ef1785ae7bc2ccfa72b2bd2b9ed [file] [log] [blame]
<?xml version="1.0"?>
<!--
Copyright (c) 2013, 2021 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0, which is available at
http://www.eclipse.org/legal/epl-2.0.
This Source Code may also be made available under the following Secondary
Licenses when the conditions for such availability set forth in the
Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
version 2 with the GNU Classpath Exception, which is available at
https://www.gnu.org/software/classpath/license.html.
SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-->
<!DOCTYPE chapter [<!ENTITY % ents SYSTEM "jersey.ent" > %ents;]>
<chapter xmlns="http://docbook.org/ns/docbook"
version="5.0"
xml:lang="en"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink"
xsi:schemaLocation="http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd
http://www.w3.org/1999/xlink http://www.w3.org/1999/xlink.xsd"
xml:id="monitoring_tracing">
<title>Monitoring and Diagnostics</title>
<section xml:id="monitoring">
<title>Monitoring Jersey Applications</title>
<section>
<title>Introduction</title>
<important>
<para>
Jersey monitoring support has been released as a <emphasis>beta release</emphasis> in Jersey 2.1 version.
As such, the exposed monitoring public APIs and functionality described in this section may change in the
future Jersey releases.
</para>
</important>
<para>
Jersey provides functionality for monitoring JAX-RS/Jersey applications. Application monitoring is useful
when you need to identify the performance hot-spots in your JAX-RS application, observe
execution statistics of particular resources or listen to application
or request lifecycle events. Note that this functionality is Jersey-specific extension to JAX-RS API.
</para>
<para>
Jersey monitoring support is divided into three functional areas:
<variablelist>
<varlistentry>
<term>Event Listeners</term>
<listitem>
<para>
Event listeners allow users to receive and process a predefined set of events that occur during
an application lifecycle (such as application initialization, application destroy) as well as
request processing lifecycle events (request started, resource method finished, exception thrown,
etc.). This feature is always enabled in Jersey server runtime and is leveraged by the other
monitoring features.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Monitoring Statistics</term>
<listitem>
<para>
Jersey can be configured to process lifecycle events in order to expose a wide range of
runtime monitoring statistics to the end user. The statistics are accessible trough an injectable
&jersey.server.monitoring.MonitoringStatistics; interface. The statistics provide general information
about the application as well as fine-grained execution statistics on particular resources and sub
resources and exposed URIs. For performance reasons, this functionality must be explicitly enabled
prior using.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>JMX MBeans with statistics</term>
<listitem>
<para>
In addition to the injectable &lit.jersey.server.monitoring.MonitoringStatistics; data, Jersey
is able to expose the statistics as JMX MBeans (for example
&jersey.server.monitoring.ApplicationMXBean;).
Jersey monitoring MXBeans can be accessed programmatically using JMX APIs or browsed via JMX-enabled
tool (<literal>JConsole</literal> for example). This functionality is also disabled by default for
performance reasons and must be enabled if needed.
</para>
</listitem>
</varlistentry>
</variablelist>
All monitoring related APIs (beta!) can be found in the <literal>jersey-server</literal> module in
<literal>org.glassfish.jersey.server.monitoring</literal> package. Monitoring in Jersey is currently supported on
the server side.
</para>
</section>
<section>
<title>Event Listeners</title>
<para>
Jersey defines two types of event listeners that you can implement and register with your application:
<itemizedlist>
<listitem>
<para>&jersey.server.monitoring.ApplicationEventListener; for listening to application events, and</para>
</listitem>
<listitem>
<para>&jersey.server.monitoring.RequestEventListener; for listening to events of request processing.</para>
</listitem>
</itemizedlist>
Only the first type, &lit.jersey.server.monitoring.ApplicationEventListener;
can be directly registered as an application-wide provider. The &lit.jersey.server.monitoring.RequestEventListener;
is designed to be specific to every request and can be only returned from the
&lit.jersey.server.monitoring.ApplicationEventListener; as such.
</para>
<para>
Let's start with an example. The following examples show simple implementations of Jersey event listeners as well
as a test JAX-RS resource that will be monitored.
<example>
<title>Application event listener</title>
<programlisting language="java" linenumbering="numbered"><![CDATA[public class MyApplicationEventListener
implements ApplicationEventListener {
private volatile int requestCnt = 0;
@Override
public void onEvent(ApplicationEvent event) {
switch (event.getType()) {
case INITIALIZATION_FINISHED:
System.out.println("Application "
+ event.getResourceConfig().getApplicationName()
+ " was initialized.");
break;
case DESTROY_FINISHED:
System.out.println("Application "
+ event.getResourceConfig().getApplicationName() destroyed.");
break;
}
}
@Override
public RequestEventListener onRequest(RequestEvent requestEvent) {
requestCnt++;
System.out.println("Request " + requestCnt + " started.");
// return the listener instance that will handle this request.
return new MyRequestEventListener(requestCnt);
}
}]]></programlisting>
</example>
<example>
<title>Request event listener</title>
<programlisting language="java" linenumbering="numbered"><![CDATA[public class MyRequestEventListener implements RequestEventListener {
private final int requestNumber;
private final long startTime;
public MyRequestEventListener(int requestNumber) {
this.requestNumber = requestNumber;
startTime = System.currentTimeMillis();
}
@Override
public void onEvent(RequestEvent event) {
switch (event.getType()) {
case RESOURCE_METHOD_START:
System.out.println("Resource method "
+ event.getUriInfo().getMatchedResourceMethod()
.getHttpMethod()
+ " started for request " + requestNumber);
break;
case FINISHED:
System.out.println("Request " + requestNumber
+ " finished. Processing time "
+ (System.currentTimeMillis() - startTime) + " ms.");
break;
}
}
}]]></programlisting>
</example>
<example>
<title>Event listener test resource</title>
<programlisting language="java" linenumbering="numbered"><![CDATA[@Path("resource")
public class TestResource {
@GET
public String getSomething() {
return "get";
}
@POST
public String postSomething(String entity) {
return "post";
}
}]]></programlisting>
</example>
</para>
<para>
Once the listeners and the monitored resource are defined, it's time to initialize our application. The following
piece of code shows a &jersey.server.ResourceConfig; that is used to initialize the application (please
note that only &lit.jersey.server.monitoring.ApplicationEventListener; is registered as provider).
<programlisting language="java" linenumbering="numbered"><![CDATA[ResourceConfig resourceConfig =
new ResourceConfig(TestResource.class, MyApplicationEventListener.class)
.setApplicationName("my-monitored-application");]]></programlisting>
Our example application now contains a simple resource <literal>TestResource</literal> that defines resource methods
for &lit.http.GET; and &lit.http.POST; and a custom <literal>MyApplicationEventListener</literal> event listener.
</para>
<para>
The registered <literal>MyApplicationEventListener</literal> implements two methods defined by the
&lit.jersey.server.monitoring.ApplicationEventListener; interface. A method <literal>onEvent()</literal> handles
all application lifecycle events. In our case the method handles only 2 application events - initialization
and destroy. Other event types are ignored. All application event types are defined
in &jersey.server.monitoring.ApplicationEvent;<literal>.Type</literal>. The second method <literal>onRequest</literal>
is invoked by Jersey runtime every time a new request is received. The request event type passed to the method
is always <literal>START</literal>. If you want to listen to any other request lifecycle events for the new request,
you are expected to return an instance of &lit.jersey.server.monitoring.RequestEventListener; that will handle the
request. It is important to understand, that the instance will handle only the request for which it has been returned
from an <literal>ApplicationEventListener.onRequest</literal> method and not any other requests. In our case the
returned request event listener keeps information about the request number of the current request and a start time of
the request which is later used to print out the request processing times statistics. This demonstrates the principle
of listening to request events: for one request there is one instance which can be used to hold all the information
about the particular request. In other words, &lit.jersey.server.monitoring.RequestEventListener; is designed to be
implicitly request-scoped.
</para>
<para>
Jersey represents lifecycle events via &jersey.server.monitoring.RequestEvent; and
&jersey.server.monitoring.ApplicationEvent; types. Instances of these classes contain information
about respective events. The most important information is the event type <literal>Type</literal> retrievable via
<literal>getType()</literal> method,
which identifies the type of the event. Events contain also additional information that is dependent on a particular
event type. This information can be retrieved via event getters. Again, some getters return valid information for all
event types, some are specific to a sub-set of event types. For example, in the
&lit.jersey.server.monitoring.RequestEvent;, the <literal>getExceptionCause()</literal> method returns valid
information only when event type is <literal>ON_EXCEPTION</literal>. On the other hand,
a <literal>getContainerRequest()</literal> can be used to return current request context for any request event type.
See javadoc of events and event types to get familiar with event types and information valid for each event type.
</para>
<para>
Our <literal>MyRequestEventListener</literal> implementation is focused on processing 2 request events. First,
it listens for an event that is triggered before a resource method is executed. Also, it hooks to a "request finished"
event. As mentioned earlier, the request event <literal>START</literal> is handled only in the
<literal>MyApplicationEventListener</literal>. The <literal>START</literal> event type will never be invoked on
<literal>RequestEventListener</literal>. Therefore the logic for measuring the <literal>startTime</literal> is in the
constructor which is invoked from <literal>MyApplicationEventListener.onRequest()</literal>. An attempt to handling
the request <literal>START</literal> event in a <literal>RequestEventListener.onEvent()</literal> method would be a
mistake.
</para>
<para>
Let's deploy the application and use a simple test client code to produce some activity in order to spawn new events:
<programlisting language="java" linenumbering="numbered"><![CDATA[target.path("resource").request()
.post(Entity.entity("post", MediaType.TEXT_PLAIN_TYPE));
target.path("resource").request().get();]]></programlisting>
In the code above, the <literal>target</literal> is a &jaxrs.client.WebTarget; instance pointing to the application
context root path. Using the <xref linkend="client" />, we invoke &lit.http.GET; and &lit.http.POST; methods
on the <literal>MyResource</literal> JAX-RS resource class that we implemented earlier.
</para>
<para>
When we start the application, run the test client and then stop the application, the console output for the
deployed server-side application would contain the following output:
<programlisting language="text" linenumbering="unnumbered">Application my-monitored-application was initialized.
Request 1 started.
Resource method POST started for request 1
Request 1 finished. Processing time 330 ms.
Request 2 started.
Resource method GET started for request 2
Request 2 finished. Processing time 4 ms.
Application my-monitored-application destroyed.</programlisting>
</para>
<section>
<title>Guidelines for implementing Jersey event listeners</title>
<itemizedlist>
<listitem><para>
Implement event listeners as thread safe. While individual events will be arriving serially,
individual listener invocations may occur from different threads. Thus make sure that your listeners
are processing data safely with respect to their
<link xlink:href='&wikipedia.uri;Java_Memory_Model'>Java Memory Model</link> visibility (in the example
above the fields <literal>requestNumber</literal>, <literal>startTime</literal> of
<literal>MyRequestEventListener</literal> are final and therefore the same value is
visible for all threads executing the <literal>onEvent()</literal> method).
</para></listitem>
<listitem><para>
Do not block the thread executing the event listeners by performing long-running tasks. Execution of event
listeners is a part of the standard application and request processing and as such needs to finish as quickly
as possible to avoid negative impact on overall application performance.
</para></listitem>
<listitem><para>
Do not try to modify mutable objects returned from &lit.jersey.server.monitoring.ApplicationEvent; and
&lit.jersey.server.monitoring.RequestEvent; getters to avoid experiencing undefined behavior.
Events listeners should use the information for read only purposes only. Use different techniques like
filters, interceptors or other providers to modify the processing of requests and applications. Even though
modification might be possible and might work as desired now, your code is in risk of producing intermittent
failures or unexpected behaviour (for example after migrating to new Jersey version).
</para></listitem>
<listitem><para>
If you do not want to listen to request events, do not return an empty listener in the
<literal>onRequest()</literal> method. Return <literal>null</literal> instead. Returning empty listener
might have a negative performance impact. Do not rely on JIT optimizing out the empty listener invocation
code.
</para></listitem>
<listitem><para>
If you miss any event type or any detail in the events, let us know via Jersey user mailing list.
</para></listitem>
</itemizedlist>
</section>
<section>
<title>Monitoring Statistics</title>
<para>
Event listeners described in the previous section are all-purpose facility. For example, you may decide to
use them to measure various execution statistics of your application. While this might be an easy task for simple
statistics like "how much time was spent on execution of each Java method?", nevertheless, if you want to measure
statistics based on URIs and individual resources, the implementation might get rather complex soon, especially
when considering sub-resources and sub-resource locators. To save you the trouble, Jersey provides feature for
collecting events and calculating a pre-defined set of monitoring and execution statistics, including
application configuration, exception mappers execution, minimum/maximum/average execution times for individual
resource methods as well as entire request processing etc.
</para>
<para>
Calculating the monitoring statistics has obviously a performance impact, therefore this feature is
disabled by default. To enable the feature, set the following configuration property to &lit.true;:
</para>
<programlisting language="java" linenumbering="unnumbered">jersey.config.server.monitoring.statistics.enabled=true</programlisting>
<para>
The property description can be found in &jersey.server.ServerProperties.MONITORING_STATISTICS_ENABLED;
This will calculate the statistics. The easiest way how to get statistics is to let Jersey
to inject them. See the following example:
</para>
<example>
<title>Injecting MonitoringStatistics</title>
<programlisting language="java" linenumbering="numbered"><![CDATA[@Path("resource")
public static class StatisticsResource {
@Inject
Provider<MonitoringStatistics> monitoringStatisticsProvider;
@GET
public String getSomething() {
final MonitoringStatistics snapshot
= monitoringStatisticsProvider.get().snapshot();
final TimeWindowStatistics timeWindowStatistics
= snapshot.getRequestStatistics()
.getTimeWindowStatistics().get(0l);
return "request count: " + timeWindowStatistics.getRequestCount()
+ ", average request processing [ms]: "
+ timeWindowStatistics.getAverageDuration();
}
}}]]></programlisting>
</example>
<para>
&jersey.server.monitoring.MonitoringStatistics; are
injected into the resource using an &jee6.javax.inject.Inject; annotation.
Please note the usage of the &jee6.javax.inject.Provider; for injection (it will be discussed later).
Firstly, the snapshot of statistics is retrieved by the <literal>snapshot()</literal> method.
The snapshot of statistics is an immutable copy of statistics which does not change over the time.
Additionally, data in a snapshot are consistent. It's recommended to create snapshots before working with
the statistics data and then process the snapshot data.
Working with original non-snapshot data makes sense when data consistency is not important and
performance is of highest concern. While it is currently not the case, the injected non-snapshot data may
be implemented as mutable for performance reasons in a future release of Jersey.
</para>
<para>
The injected monitoring statistics represent the root of the collected statistics hierarchy. The hierarchy
can be traversed to retrieve any partial statistics data. In the example, we retrieve certain request
&jersey.server.monitoring.TimeWindowStatistics; data. In our case, those are the request execution statistics
for a time window defined by long value 0 which means unlimited time window. This means we are retrieving
the global request execution statistics measured since a start of the application.
Finally, request count and average duration from the statistics are used to produce the String response.
When we invoke few &lit.http.GET; requests on the <literal>StatisticsResource</literal>, we get the
following console output:
<programlisting language="text" linenumbering="unnumbered">request count: 1, average request processing [ms]: 260
request count: 2, average request processing [ms]: 135
request count: 3, average request processing [ms]: 93
request count: 4, average request processing [ms]: 73</programlisting>
</para>
<para>
Let's look closer at &jersey.server.monitoring.MonitoringStatistics; interface.
&lit.jersey.server.monitoring.MonitoringStatistics; interface defines getters by which other nested
statistics can be retrieved. All statistics are in the same package and ends with
<literal>Statistics</literal> postfix. Statistics interfaces are the following:
<variablelist>
<varlistentry>
<term>&jersey.server.monitoring.MonitoringStatistics;</term>
<listitem>
<para>main top level statistics</para>
</listitem>
</varlistentry>
<varlistentry>
<term>&jersey.server.monitoring.ResponseStatistics;</term>
<listitem>
<para>response statistics (eg. response status codes and their count)</para>
</listitem>
</varlistentry>
<varlistentry>
<term>&jersey.server.monitoring.ResourceStatistics;</term>
<listitem>
<para>statistics of execution of resources (resource classes or resource URIs)</para>
</listitem>
</varlistentry>
<varlistentry>
<term>&jersey.server.monitoring.ResourceMethodStatistics;</term>
<listitem>
<para>statistics of execution of resource methods</para>
</listitem>
</varlistentry>
<varlistentry>
<term>&jersey.server.monitoring.ExecutionStatistics;</term>
<listitem>
<para>statistic of execution of a target (resource, request, resource method)</para>
</listitem>
</varlistentry>
<varlistentry>
<term>&jersey.server.monitoring.TimeWindowStatistics;</term>
<listitem>
<para>statistics of execution time in specific interval (eg. executions in last 5 minutes)</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<para>
Each time-monitored target contains &lit.jersey.server.monitoring.ExecutionStatistics;. So, for example
resource method contains execution statistics of its execution. Each
&lit.jersey.server.monitoring.ExecutionStatistics; contains multiple
&lit.jersey.server.monitoring.TimeWindowStatistics;. Currently, each
&lit.jersey.server.monitoring.ExecutionStatistics; contains
&lit.jersey.server.monitoring.TimeWindowStatistics; for these time windows:
<itemizedlist>
<listitem><para>0: unlimited=> all execution since start of the application</para></listitem>
<listitem><para>1000: 1s => stats measured in last 1 second</para></listitem>
<listitem><para>15000: 15s => stats measured in last 15 seconds</para></listitem>
<listitem><para>60000: 1min => stats measured in last 1 minute</para></listitem>
<listitem><para>900000: 15min => stats measured in last 15 minutes</para></listitem>
<listitem><para>3600000: 1hour => stats measured in last hour minutes</para></listitem>
</itemizedlist>
All the time window statistics can be retrieved from a <literal>Map&lt;Long, TimeWindowStatistics&gt;</literal>
map returned from <literal>ExecutionStatistics.getTimeWindowStatistics()</literal>. Key of the map
is the number of milliseconds of interval (so, for example key 60000 points
to statistics for last one minute).
</para>
<para>
Note, that <literal>snapshot()</literal> method was called in the example only on the top level
&lit.jersey.server.monitoring.MonitoringStatistics;. This produced a snapshot of the entire
tree of statistics and therefore we do not need to call <literal>snapshot()</literal>
on &lit.jersey.server.monitoring.TimeWindowStatistics; again.
</para>
<para>
Statistics are injected using the &jee6.javax.inject.Provider;. This is preferred way of
injecting statistics. The reason is simple. Statistics might change over time and contract
of &lit.jersey.server.monitoring.MonitoringStatistics; does not make any assumptions about mutability of
monitoring statistics instances (to allow future optimizations and changes in implementation strategy). In
order to get always latest statistics, we recommend injecting a &jee6.javax.inject.Provider; rather than a
direct reference and use its <literal>get()</literal> method to retrieve the latest statistics. For example,
in singleton resources the use of the technique is very important otherwise statistics might correspond
to the time when singleton was firstly created and might not update since that time.
</para>
<section>
<title>Listening to statistics changes</title>
<para>
Statistics are not calculated for each request or each change. Statistics are calculated only
from the collected data in regular intervals for performance reasons (for example once per second).
If you want to be notified about new statistics, register an implementation of
&jersey.server.monitoring.MonitoringStatisticsListener; as one of your custom application providers.
Your listener will be called every time the new statistics are calculated and the updated statistics
data will be passed to the listener method. This is another way of receiving statistics.
See the linked listener API documentation for more information.
</para>
</section>
</section>
<section>
<title>Monitoring Statistics as MBeans</title>
<note>
<para>
Jersey examples contains a
<link xlink:href='&jersey.github.examples.uri;/monitoring-webapp'>Monitoring Web Application Example</link>
which demonstrates usage of MBean statistics.
</para>
</note>
<para>
Jersey provides feature to expose monitoring statistics as JMX MXBeans.
In order to enable monitoring statistics MXBeans exposure, the
&jersey.server.ServerProperties.MONITORING_STATISTICS_MBEANS_ENABLED; must be set to &lit.true;.
</para>
<programlisting language="java" linenumbering="unnumbered">jersey.config.server.monitoring.statistics.mbeans.enabled=true</programlisting>
<para>
Note that enabling exposure of monitoring MXBeans causes that also the calculation of
&lit.jersey.server.monitoring.MonitoringStatistics; is automatically enabled as the exposed
MXBean statistics are extracted from &lit.jersey.server.monitoring.MonitoringStatistics;.
</para>
<para>
The easiest way is to browse the MXBeans in the JConsole. Open the JConsole
(<literal>$JAVA_HOME/bin/jconsole</literal>). Then connect to the process where JAX-RS application is running
(server on which the application is running). Switch to a MBean tab and in the MBean tree on the left side
find a group <literal>org.glassfish.jersey</literal>. All deployed Jersey applications are located under this
group. If you don't see such this group, then MBeans are not exposed (check the configuration property and
logs if they not contain any exceptions or errors). The following figure is an example of an output from the
JConsole:
</para>
<mediaobject>
<imageobject>
<imagedata fileref="images/monitoring-jsconsole.png" format="PNG" width="100%" scalefit="1" align="center"/>
</imageobject>
</mediaobject>
<para>
Under the root <literal>org.glassfish.jersey</literal> Jersey MBean group you can find your application.
If the server contains more Jersey application, all will be present under the root Jersey the group. In the
screen-shot, the deployed JAX-RS application is named <literal>myApplication</literal> (the name can be defined
via &jersey.server.ResourceConfig; directly or by setting the &jersey.server.ServerProperties.APPLICATION_NAME;
property).
Each application contains <literal>Global</literal>, <literal>Resource</literal> and
<literal>Uris</literal> sub-groups. The <literal>Global</literal> group contains all global
statistics like overall requests statistics of the entire application (<literal>AllRequestTimes</literal>),
configuration of the JAX-RS application (<literal>Configuration</literal>), statistics about
&jaxrs.ext.ExceptionMapper; execution (<literal>ExceptionMapper</literal>) and statistics about
produced responses (<literal>Responses</literal>).
</para>
<para>
<literal>Resources</literal> and <literal>Uris</literal> groups contains monitoring statistics specific to
individual resources.
Statistics in <literal>Resources</literal> are bound to the JAX-RS resource Java classes loaded by the
application. <literal>Uris</literal> contains statistics of resources based on the matched application Uris
(one URI entry represents all methods bound to the particular URI, e.g. <literal>/resource/exception</literal>).
As Jersey provides programmatic resource builders (described in the chapter
<link linkend="resource-builder">"Programmatic API for Building Resources"</link>), one Java resource class
can be an endpoint for resource methods on many different URIs. And also one URI can be served by method from
many different Java classes. Therefore both views are not to be compared 1:1. Instead they provide
different logical views on your JAX-RS application. This monitoring feature can also be helpful when designing
the JAX-RS APIs as it provides nice view on available root application URIs.
</para>
<para>
Both logical views on the resources exposed by application share few common principles. A single resource entry
is always a set of resource methods which are available under the <literal>methods</literal> sub-group. Statistics
can be found in MBeans <literal>MethodTimes</literal> and <literal>RequestTimes</literal>.
<literal>MethodTimes</literal> contains statistics measured on resource methods (duration of execution of a
code of the a resource method), whereas <literal>RequestTimes</literal> contains statistics of an entire request
execution (not only a time of the execution of the resource method but the overall time of the execution of whole
request by Jersey runtime). Another useful information is that statistics directly under resource (not under
the <literal>methods</literal> sub-group) contains summary of statistics for all resource methods grouped in the
resource entry.
</para>
<para>Additional useful details about statistics</para>
<itemizedlist>
<listitem><para><literal>Global->Configuration->Registered(Classes/Instances)</literal>:
registered resource classes and instances by the user (i.e., not added by &jersey.server.ModelProcessor;
during deployment for example).
</para></listitem>
<listitem><para><literal>Global->ExceptionMapper->ExceptionMapperCount</literal>:
map that contains exception mapper classes as keys and number of their execution as values.
</para></listitem>
<listitem><para>
<literal>Global->Responses->ResponseCodesToCountMap</literal>:
map that contains response codes as keys and their total occurrence in responses as values.
</para></listitem>
<listitem><para>
Resource groups contain also entries for resources that were added by Jersey at deployment time using
&lit.jersey.server.ModelProcessor; (for example all &lit.http.OPTIONS; methods, <literal>WADL</literal>).
&lit.http.HEAD; methods are not present in the MXBeans view (even HEAD methods are in resources).
</para></listitem>
<listitem><para>
Execution statistics for different time windows have different update intervals. The shorter the time window,
the shorter the update interval. This causes that immediately after the application start, the shorter time
windows (such as 15 seconds) may contain higher values than longer ones (e.g. 1 hour time window). The reason
is that 1 hour interval will show information that is not up to date and therefore has smaller value. This
inconsistency is not so much significant when application is running longer time. Total unlimited time windows
contains always up-to-date data. This inconsistency will get fixed in a future Jersey release.
</para></listitem>
</itemizedlist>
<para>
MXBeans can be also accessed using JMX. To do so, you would need to use the interfaces of MXBeans.
These interfaces are even useful when working with MXBeans only trough <literal>JConsole</literal> as
they contain Javadocs for each MXBean and attribute. Monitoring MBeans are defined by following interfaces:
<itemizedlist>
<listitem><para>
&jersey.server.monitoring.ApplicationMXBean;: contains configuration statistics
</para></listitem>
<listitem><para>
&jersey.server.monitoring.ExceptionMapperMXBean;: contains statistics of exception mappers
</para></listitem>
<listitem><para>
&jersey.server.monitoring.ResourceMethodMXBean;: contains statistics of resource method
</para></listitem>
<listitem><para>
&jersey.server.monitoring.ResourceMXBean;: contains statistics of resource
</para></listitem>
<listitem><para>
&jersey.server.monitoring.ResponseMXBean;: contains statistics of responses
</para></listitem>
</itemizedlist>
The list does not contain MXBean for the execution and time window statistics. The reason is that
this bean is defined as a &jdk6.DynamicMBean;. Attributes of this dynamic MBean contains
statistics for all time windows available.
</para>
<para>
MXBeans do not reference each other but can be retrieved by their &jdk6.ObjectName;s which
are designed in the way, that final MBean tree looks nicely organized in <emphasis>JConsole</emphasis>.
Each MXBean is uniquely identified by its &lit.jdk6.ObjectName; and properties of
&lit.jdk6.ObjectName; are structured hierarchically, so that each MXBean can be identified to which
parent it belong to (e.g. execution statistics dynamic MXBean belongs to resource method MXBean, which
belongs to resource and which belongs to application). Check the &lit.jdk6.ObjectName;s of
exposed MXBeans to investigate the structure (for example through JConsole).
</para>
<para>
To reiterate, exposing Jersey MXBeans and the calculating monitoring statistics may have an performance impact
on your application and therefore should be enabled only when needed. Also, please note, that Jersey
monitoring is exposing quite a lot of information about the monitored application which might be viewed as
problematic in some cases (e.g. in production server deployments).
</para>
</section>
</section>
</section>
<section xml:id="tracing">
<title>Tracing Support</title>
<para>
Apart from monitoring and collecting application statistics described in <xref linkend="monitoring"/>, Jersey
can also provide tracing or diagnostic information about server-side processing of individual requests.
This facility may provide vital information when troubleshooting your misbehaving Jersey or JAX-RS application.
When enabled, Jersey tracing facility collects useful information from all parts of JAX-RS server-side request
processing pipeline:
<literal>PreMatchRequestFilter</literal>, <literal>ResourceMatching</literal>, <literal>RequestFilter</literal>,
<literal>ReadIntercept</literal>, <literal>MBR</literal>, <literal>Invoke</literal>,
<literal>ResponseFilter</literal>, <literal>WriteIntercept</literal>, <literal>MBW</literal>, as well as
<literal>ExceptionHandling</literal>.
</para>
<para>
The collected tracing information related to a single request is returned to the requesting client in the HTTP
headers of a response for the request. The information is also logged on the server side using a dedicated Java
Logger instance.
</para>
<section xml:id="tracing.configuration">
<title>Configuration options</title>
<para>
Tracing support is disabled by default. You can enable it either "globally" for all application requests
or selectively per request. The tracing support activation is controlled by setting the
<literal>jersey.config.server.tracing.type</literal> application configuration property. The property value
is expected to be one of the following:
<itemizedlist>
<listitem>
<para>
<literal>OFF</literal> - tracing support is disabled (default value).
</para>
</listitem>
<listitem>
<para>
<literal>ON_DEMAND</literal> - tracing support is in a stand-by mode; it is enabled selectively
per request, via a special <literal>X-Jersey-Tracing-Accept</literal> HTTP request header.
</para>
</listitem>
<listitem>
<para>
<literal>ALL</literal> - tracing support is enabled for all request.
</para>
</listitem>
</itemizedlist>
</para>
<para>
The level of detail of the information provided by Jersey tracing facility - the tracing threshold - can be
customized. The tracing threshold can be set at the application level via
<literal>jersey.config.server.tracing.threshold</literal> application configuration property,
or at a request level, via <literal>X-Jersey-Tracing-Threshold</literal> HTTP request header. The request level
configuration overrides any application level setting. There are 3 supported levels of detail for Jersey tracing:
<itemizedlist>
<listitem>
<para>
<literal>SUMMARY</literal> - very basic summary information about the main request processing stages.
</para>
</listitem>
<listitem>
<para>
<literal>TRACE</literal> - detailed information about activities in all the main request processing
stages (default threshold value).
</para>
</listitem>
<listitem>
<para>
<literal>VERBOSE</literal> - most verbose mode that provides extended information similar to
<literal>TRACE</literal> level, however with details on entity providers
(<literal>MBR</literal>/<literal>MBW</literal>) that were skipped during the provider selection
phase for any reason (lower priority, pattern matching, etc). Additionally, in this mode all
received request headers are echoed as part of the tracing information.
</para>
</listitem>
</itemizedlist>
</para>
</section>
<section>
<title>Tracing Log</title>
<para>
As mentioned earlier, all tracing information is also logged using a dedicated Java Logger. The individual
tracing messages are logged immediately as the tracing events occur. The default name of the tracing logger
is prefixed <literal>org.glassfish.jersey.tracing.</literal> with a default suffix <literal>general</literal>.
This logger name can be customized per request by including a <literal>X-Jersey-Tracing-Logger</literal>
HTTP request header as will be shown later.
</para>
</section>
<section>
<title>Configuring tracing support via HTTP request headers</title>
<para>
Whenever the tracing support is active (<literal>ON_DEMAND</literal> or <literal>ALL</literal>) you
can customize the tracing behaviour by including one or more of the following request HTTP headers in your
individual requests:
<itemizedlist>
<listitem>
<para>
<literal>X-Jersey-Tracing-Accept</literal> - used to enable the tracing support for the particular
request. It is applied only when the application-level tracing support is configured to
<literal>ON_DEMAND</literal> mode. The value of the header is not used by the Jersey tracing
facility and as such it can be any arbitrary (even empty) string.
</para>
</listitem>
<listitem>
<para>
<literal>X-Jersey-Tracing-Threshold</literal> - used to override the tracing level of detail.
Allowed values are: <literal>SUMMARY</literal>, <literal>TRACE</literal>, <literal>VERBOSE</literal>.
</para>
</listitem>
<listitem>
<para>
<literal>X-Jersey-Tracing-Logger</literal> - used to override the tracing Java logger name suffix.
</para>
</listitem>
</itemizedlist>
</para>
</section>
<section>
<title>Format of the HTTP response headers</title>
<para>
At the end of request processing all tracing messages are appended to the HTTP response as individual
headers named <literal>X-Jersey-Tracing-</literal><emphasis><literal>nnn</literal></emphasis> where
<emphasis><literal>nnn</literal></emphasis> is index number of message starting at <literal>0</literal>.
</para>
<para>
Each tracing message is in the following format: <literal>CATEGORY [TIME] TEXT</literal>, e.g.
<screen>X-Jersey-Tracing-007: WI [85.95 / 183.69 ms | 46.77 %] WriteTo summary: 4 interceptors</screen>
</para>
<para>
The <literal>CATEGORY</literal> is used to categorize tracing events according to the following
event types:
<itemizedlist>
<listitem>
<para>
<literal>START</literal> - start of request processing information
</para>
</listitem>
<listitem>
<para>
<literal>PRE-MATCH</literal> - pre-matching request filter processing
</para>
</listitem>
<listitem>
<para>
<literal>MATCH</literal> - matching request URI to a resource method
</para>
</listitem>
<listitem>
<para>
<literal>REQ-FILTER</literal> - request filter processing
</para>
</listitem>
<listitem>
<para>
<literal>RI</literal> - entity reader interceptor processing
</para>
</listitem>
<listitem>
<para>
<literal>MBR</literal> - message body reader selection and invocation
</para>
</listitem>
<listitem>
<para>
<literal>INVOKE</literal> - resource method invocation
</para>
</listitem>
<listitem>
<para>
<literal>RESP-FILTER</literal> - response filter processing
</para>
</listitem>
<listitem>
<para>
<literal>WI</literal> - write interceptor processing
</para>
</listitem>
<listitem>
<para>
<literal>MBW</literal> - message body writer selection and invocation
</para>
</listitem>
<listitem>
<para>
<literal>MVC</literal> - template engine integration
</para>
</listitem>
<listitem>
<para>
<literal>EXCEPTION</literal> - exception mapping
</para>
</listitem>
<listitem>
<para>
<literal>FINISHED</literal> - processing finish summary
</para>
</listitem>
</itemizedlist>
</para>
<para>
The <literal>TIME</literal>, if present, is a composite value that consists of 3 parts
<literal>[ duration / time_from_start | total_req_ratio ]</literal>:
<orderedlist>
<listitem>
<para>
<literal>duration</literal> - the duration of the current trace event [milliseconds];
e.g. duration of filter processing
</para>
</listitem>
<listitem>
<para>
<literal>time_from_start</literal> - the end time of the current event with respect to
the request processing start time [milliseconds]
</para>
</listitem>
<listitem>
<para>
<literal>total_req_ratio</literal> - the duration of the current event with respect to
the total request processing time [percentage]; this value tells you how significant part
of the whole request processing time has been spent in the processing phase described by
the current event
</para>
</listitem>
</orderedlist>
There are certain tracing events that do not have any duration. In such case, duration values are not set
(<literal>----</literal> literal).
</para>
<para>
The tracing event <literal>TEXT</literal> is a free-form detailed text information about the
current diagnostic event.
<tip>
<para>
For better identification, instances of JAX-RS components are represented by class name,
identity hash code and <literal>@Priority</literal> value if set, e.g.
<literal>[org.glassfish.jersey.tests.integration.tracing.ContainerResponseFilter5001 @494a8227 #5001]</literal>.
</para>
</tip>
</para>
</section>
<section>
<title>Tracing Examples</title>
<para>
Example of <literal>SUMMARY</literal> level messages
from <literal>tests/integration/tracing-support</literal> module:
<example>
<title>Summary level messages</title>
<screen linenumbering="numbered"><![CDATA[$ curl -i http://localhost:9998/ALL/root/sub-resource-locator/sub-resource-method -H content-type:application/x-jersey-test --data '-=#[LKR]#=-' -H X-Jersey-Tracing-Threshold:SUMMARY -H accept:application/x-jersey-test -X POST
X-Jersey-Tracing-000: START [ ---- / ---- ms | ---- %] baseUri=[http://localhost:9998/ALL/] requestUri=[http://localhost:9998/ALL/root/sub-resource-locator/sub-resource-method] method=[POST] authScheme=[n/a] accept=[application/x-jersey-test] accept-encoding=n/a accept-charset=n/a accept-language=n/a content-type=[application/x-jersey-test] content-length=[11]
X-Jersey-Tracing-001: PRE-MATCH [ 0.01 / 0.68 ms | 0.01 %] PreMatchRequest summary: 2 filters
X-Jersey-Tracing-002: MATCH [ 8.44 / 9.15 ms | 4.59 %] RequestMatching summary
X-Jersey-Tracing-003: REQ-FILTER [ 0.01 / 9.20 ms | 0.00 %] Request summary: 2 filters
X-Jersey-Tracing-004: RI [86.14 / 95.49 ms | 46.87 %] ReadFrom summary: 3 interceptors
X-Jersey-Tracing-005: INVOKE [ 0.04 / 95.70 ms | 0.02 %] Resource [org.glassfish.jersey.tests.integration.tracing.SubResource @901a4f3] method=[public org.glassfish.jersey.tests.integration.tracing.Message org.glassfish.jersey.tests.integration.tracing.SubResource.postSub(org.glassfish.jersey.tests.integration.tracing.Message)]
X-Jersey-Tracing-006: RESP-FILTER [ 0.01 / 96.55 ms | 0.00 %] Response summary: 2 filters
X-Jersey-Tracing-007: WI [85.95 / 183.69 ms | 46.77 %] WriteTo summary: 4 interceptors
X-Jersey-Tracing-008: FINISHED [ ---- / 183.79 ms | ---- %] Response status: 200/SUCCESSFUL|OK]]></screen>
</example>
</para>
<para>
Example <literal>TRACE</literal> level messages of <literal>jersey-mvc-jsp</literal> integration,
from <literal>examples/bookstore-webapp</literal> module:
<example>
<title>On demand request, snippet of MVC JSP forwarding</title>
<screen linenumbering="numbered"><![CDATA[$ curl -i http://localhost:9998/items/3/tracks/0 -H X-Jersey-Tracing-Accept:whatever
...
X-Jersey-Tracing-033: WI [ 0.00 / 23.39 ms | 0.02 %] [org.glassfish.jersey.server.mvc.internal.TemplateMethodInterceptor @141bcd49 #4000] BEFORE context.proceed()
X-Jersey-Tracing-034: WI [ 0.01 / 23.42 ms | 0.02 %] [org.glassfish.jersey.filter.LoggingFilter @2d427def #-2147483648] BEFORE context.proceed()
X-Jersey-Tracing-035: MBW [ ---- / 23.45 ms | ---- %] Find MBW for type=[org.glassfish.jersey.server.mvc.internal.ImplicitViewable] genericType=[org.glassfish.jersey.server.mvc.internal.ImplicitViewable] mediaType=[[javax.ws.rs.core.MediaType @7bfbfeae]] annotations=[]
X-Jersey-Tracing-036: MBW [ ---- / 23.52 ms | ---- %] [org.glassfish.jersey.server.mvc.internal.ViewableMessageBodyWriter @78b353d4] IS writeable
X-Jersey-Tracing-037: MVC [ ---- / 24.05 ms | ---- %] Forwarding view to JSP page [/org/glassfish/jersey/examples/bookstore/webapp/resource/Track/index.jsp], model [org.glassfish.jersey.examples.bookstore.webapp.resource.Track @3937f594]
X-Jersey-Tracing-038: MBW [ 1.09 / 24.63 ms | 4.39 %] WriteTo by [org.glassfish.jersey.server.mvc.internal.ViewableMessageBodyWriter @78b353d4]
X-Jersey-Tracing-039: WI [ 0.00 / 24.67 ms | 0.01 %] [org.glassfish.jersey.filter.LoggingFilter @2d427def #-2147483648] AFTER context.proceed()
X-Jersey-Tracing-040: WI [ 0.00 / 24.70 ms | 0.01 %] [org.glassfish.jersey.server.mvc.internal.TemplateMethodInterceptor @141bcd49 #4000] AFTER context.proceed()
...]]></screen>
</example>
</para>
</section>
</section>
</chapter>