| <?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 &jee9.jakarta.inject.Inject; annotation. | |
| Please note the usage of the &jee9.jakarta.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 &jee9.jakarta.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 &jee9.jakarta.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> | |
| <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=[[jakarta.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> |