Jersey Rest Logging using LoggingFeature

In this post, we will learn how to enable logging in Jersey Rest Framework using LoggingFeature.
Logging is the process of writing log messages during the execution of a program to a central place. This logging allows you to report and persist error and warning messages as well as info messages (e.g., runtime statistics) so that the messages can later be retrieved and analyzed.
Jersey Logging supports the logging request and response via internal client and server filters, which are configured and registered by LoggingFeature propertiesLoggingFeature has been introduced in Jersey 2.23 version and deprecates an older LoggingFilter.

Important : Jersey uses JDK built-in logging feature : `java.util.logging`
Jersey Framework internally uses java.util.logging  package to support logging. 

1. Logging on the Server side

How to enable Jersey logging on the server side using LoggingFeature? The LoggingFeature might be registered explicitly on ResourceConfig for server-side logging. 
Example:
package com.javadevelopersguide.jersey.config;

import java.util.logging.Level;
import java.util.logging.Logger;

import javax.ws.rs.ApplicationPath;

import org.glassfish.jersey.logging.LoggingFeature;
import org.glassfish.jersey.server.ResourceConfig;

@ApplicationPath("resources")
public class AppResourceConfig extends ResourceConfig {
 public AppResourceConfig() {
  packages("com.javadevelopersguide.jersey.resources");
  register(new LoggingFeature(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME),
    Level.INFO, LoggingFeature.Verbosity.PAYLOAD_ANY, 10000));
 }
}
Register LoggingFeature to ResourceConfig class and the Configurable options.
register(new LoggingFeature(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME),
 Level.INFO, LoggingFeature.Verbosity.PAYLOAD_ANY, 10000));
1.1 Configurable options
Logger name
Defines a logger used to log request and response messages.
Default value is LoggingFeature.DEFAULT_LOGGER_NAME.
Logger level
Defines level that will be used to log messages by logging filters. Messages will be logged only if the effective level of the logger allows it.
Default value is LoggingFeature.DEFAULT_LOGGER_LEVEL.
Verbosity
Verbosity determines how detailed message will be logged. See LoggingFeature.Verbosity Javadoc.
The lowest verbosity LoggingFeature.Verbosity.HEADERS_ONLY will log only request/response headers.
The medium verbosity (LoggingFeature.Verbosity.PAYLOAD_TEXT) will log request/response headers, as well as an entity if considered a readable text. The entity is considered a readable text, if MediaType is text/* or is one of
  • application/atom+xml
  • application/json
  • application/svg+xml
  • application/x-www-form-urlencoded
  • application/xhtml+xml
  • application/xml
The highest verbosity LoggingFeature.Verbosity.PAYLOAD_ANY will log all types of an entity (besides the request/response headers.
Note that the entity is logged up to the specified maximum number of bytes (see LoggingFeature.LOGGING_FEATURE_MAX_ENTITY_SIZE).
The default value is LoggingFeature.DEFAULT_VERBOSITY.
Maximum entity size
The maximum number of entity bytes to be logged (and buffered) - if the entity is larger, logging filter will print (and buffer in memory) only the specified number of bytes and print "...more..." string at the end. Negative values are interpreted as zero.
Default value LoggingFeature.DEFAULT_MAX_ENTITY_SIZE.
An example of server-side logging with entity Hello World!
Jun 13, 2018 5:27:46 PM org.glassfish.jersey.logging.LoggingInterceptor log
INFO: 4 * Server has received a request on thread http-nio-8080-exec-3
4 > GET http://localhost:8080/jersey-logging-server-client-example/resources/helloworld
4 > accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
4 > accept-encoding: gzip, deflate, br
4 > accept-language: en-US,en;q=0.9
4 > cache-control: max-age=0
4 > connection: keep-alive
4 > host: localhost:8080
4 > upgrade-insecure-requests: 1
4 > user-agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36

Jun 13, 2018 5:27:46 PM org.glassfish.jersey.logging.LoggingInterceptor log
INFO: 4 * Server responded with a response on thread http-nio-8080-exec-3
4 < 200
4 < Content-Type: text/html
Helloworld !!!!

2. Logging on the Client side

We can configure logging at client side similar as server side.
register(new LoggingFeature(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME),
        Level.INFO, LoggingFeature.Verbosity.PAYLOAD_ANY, 10000));
For example:
protected static ClientConfig createClientConfig() {
 ClientConfig config = new ClientConfig();
 config.register(new LoggingFeature(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME),
        Level.INFO, LoggingFeature.Verbosity.PAYLOAD_ANY, 10000));
 return config;
}

private static void getUsers() {
 Client client = ClientBuilder.newClient(createClientConfig());

 String entity = client.target("http://localhost:8080/jersey-crud-example/api").path("users")
   .request(MediaType.APPLICATION_JSON).header("some-header", "true").get(String.class);

 System.out.println(entity);
}
3. Output:
Jun 13, 2018 5:26:48 PM org.glassfish.jersey.logging.LoggingInterceptor log
INFO: 1 * Sending client request on thread main
1 > GET http://localhost:8080/jersey-logging-server-client-example/resources/users
1 > Accept: application/json
1 > some-header: true

Jun 13, 2018 5:26:48 PM org.glassfish.jersey.logging.LoggingInterceptor log
INFO: 1 * Client response received on thread main
1 < 200
1 < Content-Length: 144
1 < Content-Type: application/json
1 < Date: Wed, 13 Jun 2018 11:56:48 GMT
[{"email":"demo@gmail.com","id":100,"name":"A"},
{"email":"demo1@gmail.com","id":101,"name":"B"},
{"email":"demo2@gmail.com","id":102,"name":"C"}]

[{"email":"demo@gmail.com","id":100,"name":"A"},
{"email":"demo1@gmail.com","id":101,"name":"B"},
{"email":"demo2@gmail.com","id":102,"name":"C"}]

4. Conclusion

This guide illustrated how to enable logging using LoggingFeature in Jersey Framework using latest jersey rest 2.27 and ResourceConfig @ApplicationPath annotation based configuration.
In the next guide of the series, we will focus on more Jersey rest examples, concepts, and more.
All the code of this article is available over on Github. This is a Maven-based project, so it should be easy to import and run as it is.

Comments

  1. I've realized that is necessary to add one more line in the class AppResourceConfig to make the log work:

    Logger.getLogger("").setLevel(Level.INFO);

    Thank you for this very nice article!

    ReplyDelete

Post a Comment

Leave Comment