Enterprise Java

HTTP Request and Response Logging Using Logbook in Spring

Zalando Logbook is a popular Java library that provides detailed HTTP request and response logging capabilities. It’s highly customizable and can be easily integrated into Spring Boot applications. Let us delve into understanding how to set up and use Zalando Logbook for HTTP logging in the Spring application for various logging needs, and ensure that your HTTP traffic is logged efficiently and securely.

1. Introduction

In modern software development, effective logging is a crucial aspect of maintaining and troubleshooting applications. Logging helps developers understand what’s happening inside an application by recording details of its execution. When it comes to web applications, especially those built using RESTful services, logging HTTP requests and responses can be invaluable. This is where Zalando Logbook comes into play.

Zalando Logbook is an open-source Java library designed to provide comprehensive and customizable HTTP request and response logging. It is particularly useful in microservices architectures, where tracking the flow of requests across multiple services is essential for monitoring, debugging, and auditing. The library is flexible, allowing developers to configure what gets logged, how it gets logged, and even mask sensitive data to protect privacy. Whether you’re building a new application or enhancing an existing one, Zalando Logbook can be a powerful addition to your logging toolkit.

1.1 Why Use Zalando Logbook?

Zalando Logbook offers several advantages:

  • Detailed Logging: It logs the complete HTTP request and response, including headers, body, and status.
  • Customizability: You can configure which parts of the request/response to log and even modify the log format.
  • Compatibility: It integrates seamlessly with Spring Boot and other frameworks.
  • Security: Sensitive data can be masked before logging.

1.2 Sink

In Zalando Logbook, a Sink is a critical component responsible for handling how HTTP request and response logs are processed and output. The Sink combines two primary functions: formatting the logs and writing them to a destination. Different types of sinks can be used depending on the desired format and output for the logs.

  • DefaultSink: This is the most commonly used sink in the Zalando Logbook. It combines a log formatter and a log writer to process the HTTP logs. For example, the DefaultSink can use the DefaultHttpLogFormatter to format logs as plain text, which is useful for simple logging scenarios where human readability is the priority. The formatted logs are then written using the DefaultHttpLogWriter, which typically writes to the console or a file.
  • JsonHttpLogFormatter: Another type of sink involves the use of the JsonHttpLogFormatter. This formatter converts HTTP request and response logs into a structured JSON format, which is ideal for systems that prefer JSON for log aggregation, searching, or further processing. When paired with the DefaultHttpLogWriter in a DefaultSink, this setup ensures that the logs are output in a JSON format, making them easier to parse and analyze in tools like ELK stack or Splunk.
  • CurlHttpLogFormatter: A more specialized sink configuration might use the CurlHttpLogFormatter, which formats HTTP requests as cURL commands. This can be particularly useful for debugging or reproducing requests in command-line environments. Developers can copy the generated cURL command from the logs and execute it directly in a terminal to replicate the HTTP request, which can be valuable during development or troubleshooting.

In addition to the standard sinks provided by Zalando Logbook, such as DefaultSink and sinks utilizing JsonHttpLogFormatter or CurlHttpLogFormatter, there are also specialized sinks like CommonsLogFormatSink and ExtendedLogFormatSink. These sinks cater to specific logging requirements and formats.

  • CommonsLogFormatSink: This sink formats HTTP logs in a way that is compatible with the Apache Commons Logging framework. It uses the CommonsLogHttpLogFormatter to generate logs in a format that integrates well with applications or systems that rely on Apache Commons Logging. This format is particularly useful if you are working with legacy systems or frameworks that expect logs in a Commons Logging format. The logs produced by CommonsLogFormatSink are typically more aligned with the structure and style used by Commons Logging, making it easier to integrate and maintain consistency with existing logging practices.
  • ExtendedLogFormatSink: The ExtendedLogFormatSink is designed for scenarios where more detailed and customizable logging is required. This sink uses an extended log formatter that allows for a more granular and customizable log output compared to the standard log formatters. The ExtendedLogFormatSink provides greater flexibility in how HTTP requests and responses are logged, including additional metadata and custom formatting options. This can be beneficial for applications that need to capture detailed logging information or require a specific log structure for integration with external systems or analysis tools.

Both CommonsLogFormatSink and ExtendedLogFormatSink offer specialized features that cater to different logging needs. By using these sinks, developers can ensure that their logging setup meets the specific requirements of their application environment and integrates seamlessly with other logging frameworks or systems.

2. Code Example

2.1 Dependencies

Add the following dependencies to your pom.xml file or if you have created a spring project from start.spring.io the Spring dependencies will be automatically populated. To start using Zalando Logbook, add the other Maven dependency to your pom.xml file

<dependencies>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!—Zalando Logbook dependencies -->
<dependency>
	<groupId>org.zalando</groupId>
	<artifactId>logbook-spring-boot-starter</artifactId>
	<version>3.9.0</version>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-test</artifactId>
	<scope>test</scope>
</dependency> 
</dependencies> 

2.2 Configure application and database properties

Add the following properties to the application.properties file present in the resources folder.

spring.application.name=springlogbook
server.port=9500
spring.main.banner-mode=off

# Logbook
logging.level.org.zalando.logbook.Logbook=TRACE

2.3 Create a Controller file

Create a controller class responsible for interacting with the user.

@RestController
@RequestMapping("/logbook")
public class Mycontroller {

    // http://localhost:9500/logbook/health
    @GetMapping("/health")
    public String health() {
        return "I am healthy";
    }

    // http://localhost:9500/logbook/do-no-log
    @GetMapping("/do-not-log")
    public String doNotLog() {
        return "I am not logged";
    }

    // http://localhost:9500/logbook/lorem
    @GetMapping("/lorem")
    public String getLoreumIpsum() {
        return List.of("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.").toString();
    }
}

The provided code is a simple Spring Boot controller that defines three HTTP GET endpoints under the base path /logbook. The controller is annotated with @RestController and @RequestMapping("/logbook"), indicating that it is a REST controller and all endpoints within it will have the base path /logbook.

  • The first endpoint, /health, is mapped to the health method, which returns the string “I am healthy.” This can be accessed via an HTTP GET request to http://localhost:9500/logbook/health. This endpoint could be used for health checks to determine if the application is running properly.
  • The second endpoint, /do-not-log, is mapped to the doNotLog method, which returns the string “I am not logged.” This can be accessed via an HTTP GET request to http://localhost:9500/logbook/do-not-log. The method name suggests that this endpoint might be configured in Logbook not to be logged, though the actual exclusion logic would need to be configured separately.
  • The third endpoint, /lorem, is mapped to the getLoreumIpsum method, which returns a string containing a Lorem Ipsum placeholder text. This can be accessed via an HTTP GET request to http://localhost:9500/logbook/lorem. The placeholder text is wrapped in a List and then converted to a string using the toString() method before being returned.

2.4 Basic Configuration

Once you have added the dependency, Logbook will automatically start logging HTTP requests and responses. However, you can further customize its behavior by creating a configuration class.

@Configuration
public class LogbookLibConfig {

    @Bean
    public Logbook logbook() {
        Predicate<HttpRequest> exclude = Conditions.exclude(
                Conditions.requestTo("/logbook/health").or(
                        Conditions.requestTo("/logbook/do-not-log"))
        );

        //DefaultSink httpSink = new DefaultSink(new DefaultHttpLogFormatter(), new DefaultHttpLogWriter());

        //DefaultSink curlSink = new DefaultSink(new CurlHttpLogFormatter(), new DefaultHttpLogWriter());

        DefaultSink jsonSink = new DefaultSink(new JsonHttpLogFormatter(), new DefaultHttpLogWriter());

        return Logbook.builder()
                .condition(exclude)
                .sink(jsonSink)
                .build();
    }
}

The provided code defines a Spring Boot configuration class named LogbookLibConfig, which customizes the behavior of Zalando Logbook, a library used for logging HTTP requests and responses in Java applications. This class is annotated with @Configuration, indicating that it contains one or more Spring beans that will be managed by the Spring container.

The logbook method is annotated with @Bean, which means it will return a configured Logbook instance that can be used throughout the application for logging purposes. The method begins by defining a Predicate named exclude using Logbook’s Conditions.exclude method. This predicate is configured to exclude logging for HTTP requests made to the paths /logbook/health and /logbook/do-not-log. This exclusion logic is achieved by combining two conditions using the or method.

The code then defines different types of sinks which are responsible for formatting and writing the logs. The DefaultSink class is used to create these sinks. The jsonSink formats the HTTP logs as JSON using the JsonHttpLogFormatter and writes them using the DefaultHttpLogWriter.

Finally, the method returns a Logbook instance configured with the exclusion condition and the jsonSink. This Logbook instance will log all HTTP requests and responses, except those matching the excluded paths, and will format the logs in JSON format before writing them out.

2.5 Create the Main file

The SpringlogbookApplication class is the main entry point of a Spring Boot application.

@SpringBootApplication
public class SpringlogbookApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringlogbookApplication.class, args);

        System.out.println("Spring Boot Application Started at = " + context.getStartupDate());
    }
}

2.6 Run the application

Run your Spring Boot application and the application will be started on a port number specified in the application properties file. As soon as the application is started trigger the endpoints and the following logs will be shown on the IDE console.

……

2024-08-15T14:59:28.173+05:30  INFO 25096 --- [springlogbook] [           main] j.s.SpringlogbookApplication             : Started SpringlogbookApplication in 2.954 seconds (process running for 4.192)
2024-08-15T14:59:51.183+05:30  INFO 25096 --- [springlogbook] [nio-9500-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2024-08-15T14:59:51.183+05:30  INFO 25096 --- [springlogbook] [nio-9500-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2024-08-15T14:59:51.185+05:30  INFO 25096 --- [springlogbook] [nio-9500-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 2 ms

……

2024-08-15T14:59:51.334+05:30 TRACE 25096 --- [springlogbook] [nio-9500-exec-1] org.zalando.logbook.Logbook              : {"origin":"remote","type":"request","correlation":"dcacb5b682fe6ca0","protocol":"HTTP/1.1","remote":"0:0:0:0:0:0:0:1","method":"GET","uri":"http://localhost:9500/logbook/lorem","host":"localhost","path":"/logbook/lorem","scheme":"http","port":"9500","headers":{"accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"],"accept-encoding":["gzip, deflate, br, zstd"],"accept-language":["en-US,en;q=0.9"],"cache-control":["max-age=0"],"connection":["keep-alive"],"cookie":["Pycharm-58bde449=798190aa-d5d9-4cbf-8dd2-c088f229f130; Webstorm-a1fbc3c1=78f1f608-9dbb-4f13-b188-3eee36e9258e; Idea-62fc47a=527f9477-6099-4267-9953-aa209d38ecd3"],"host":["localhost:9500"],"sec-ch-ua":["\"Not)A;Brand\";v=\"99\", \"Google Chrome\";v=\"127\", \"Chromium\";v=\"127\""],"sec-ch-ua-mobile":["?0"],"sec-ch-ua-platform":["\"Windows\""],"sec-fetch-dest":["document"],"sec-fetch-mode":["navigate"],"sec-fetch-site":["none"],"sec-fetch-user":["?1"],"upgrade-insecure-requests":["1"],"user-agent":["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"]}}

2024-08-15T14:59:51.412+05:30 TRACE 25096 --- [springlogbook] [nio-9500-exec-1] org.zalando.logbook.Logbook              : {"origin":"local","type":"response","correlation":"dcacb5b682fe6ca0","duration":191,"protocol":"HTTP/1.1","status":200,"headers":{"Connection":["keep-alive"],"Content-Length":["125"],"Content-Type":["text/html;charset=UTF-8"],"Date":["Thu, 15 Aug 2024 09:29:51 GMT"],"Keep-Alive":["timeout=60"]},"body":"[Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.]"}

3. Conclusion

Zalando Logbook is a powerful tool for HTTP logging in Java applications. It provides detailed logs that can be customized to fit the needs of your application. By following the steps outlined in this article, you can easily integrate and configure Zalando Logbook to improve your application’s observability and debugging capabilities.

4. Download the source code

Download
You can download the full source code of this example here: HTTP Request and Response Logging Using Logbook in Spring

Yatin Batra

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button