| <?xml version="1.0"?> |
| <!-- |
| |
| Copyright (c) 2013, 2020 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<Long, TimeWindowStatistics></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 loggical 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> |