Logging in Spring WebFlux

Logging in Spring WebFlux is important for monitoring, debugging, and tracing the flow of requests through the reactive application. Here is how to effectively use logging in a Spring WebFlux application. There are log logger frameworks available in the market to handle logs in the software application. Here, we use built logger functionality in WebFlux by defining the Logger object by using LoggerFactory in this application.

Logger Creation:

private static final Logger logger = LoggerFactory.getLogger(ControllerClass.class);

Key Features of Logging in Spring WebFlux:

Below we provide the list of key features of the logger in the Spring WebFlux component.

Features

Description

Logging Levels

Loggers allow you to specify the severity of the logs, helping to filter and manage the verbosity of the logging output.

Configuration Flexibility

Configuration files allow you to set logging levels, Appenders, and format without changing the application code.

Appenders or Handlers

Loggers can direct log output to various destinations using Appenders or Handlers.

Message Formatting

– Loggers support customization message formats using patterns.
– Patterns can include timestamps, log levels, thread names, logger names, and the actual log message.

Contextual Information

Loggers can include contextual information such as thread names, class names, method names, and custom key-value pairs.

Conditional Logging

– Loggers can be configured to log messages conditionally based on the environment, log level, or custom conditions.
– This reduces unnecessary logging in production environments while providing detailed logs during development or debugging.

Asynchronous Logging

Asynchronous logging improves application performance by putting the logging process on a separate thread.

Log Rotation and Archiving

Loggers support log rotation to manage log file sizes and archiving to keep old logs for future reference

Structured Logging

Loggers can produce structured logs, often in JSON format, which are easier to parse and analyze using log management tools

Integration with Monitoring Tools

Loggers can be integrated with monitoring and alerting tools.

Error Handling

Loggers provide mechanisms to log exceptions and stack traces, making it easier to diagnose errors.

Logging Frameworks

Popular logging frameworks include Logback, Log4j2, and SLF4J.

Steps To Implement Logging in Spring WebFlux

To Implement logging in spring WebFlux, here we created a Spring Boot project which is maven type. For this project, we use below dependencies.

Project Dependencies:

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

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

Project Folder:

Below is the project structure, after successfully creating the project.


Step 1: Create logback-spring.xml

Once the project was successfully created, we created an XML configuration file named logback-spring.xml in the resource folder. This file is used to define the log pattern.

You can see this file in the project folder image above.

XML
<?xml version="1.0" encoding="UTF-8"?>

<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="STDOUT" />
    </root>

    <logger name="org.springframework.web" level="DEBUG" />
    <logger name="org.springframework.web.reactive" level="DEBUG" />
</configuration>


Step 2: Create RestController

Once the XML configuration file for logging is created, we proceeded to create a RestController class named LogHandler, annotated with @RestController. This class is responsible for defining the API endpoints and implementing the necessary business logic. Below, we provide the code for this handler. Inside the class, we instantiated an object for the Logger class using the LoggerFactory class, which takes the class name as the target input class.

Java
package com.app;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;

import reactor.core.publisher.Mono;

@RestController
public class LogController {
    private static final Logger logger = LoggerFactory.getLogger(LogController.class);
    public Mono<ServerResponse> welcomeMsg(ServerRequest request){
        logger.info("Inside welcome method");
        return ServerResponse.ok().bodyValue("Welcome to w3wiki");
    }
    
    public Mono<ServerResponse> sumOfNumbers(ServerRequest request){
        logger.info("Inside sum Of Numbers method");
        int sum = 0;
        int n = 10;
        for(int i=1; i<=n; i++)
            sum= sum+i;
        return ServerResponse.ok().bodyValue("Sum of "+" n :" + sum);
    }
}
  • In the above class, we created two different types of APIs to test the logger functionality in the Handler class.
  • Firstly, we created a method named welcomeMsg(). This method returns a String type of Mono object in the form of a Server Response. In this method, we added a logger message as you can see in the above code.
  • Following that, we created another method called sumOfNumbers() in a similar manner. This method calculates the sum of N numbers and returns the result in the form of a Server Response.


Step 3: Create a Router Function

Finally, we created a Router Function class named LogConfig using the @Configuration Spring annotation. In this class, we define the API endpoints with related mappings by auto-wiring the LogHandler class. We autowire the LogHandler because we need access to the API methods from LogHandler. Using the RouterFunction interface, we define the routes, which return a route.

Java
package com.app;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;

@Configuration
public class LogConfig {
    
    @Autowired
    private LogController handler;
    
    @Bean
    RouterFunction<ServerResponse> route() {
        return RouterFunctions.route(RequestPredicates.GET("/api/welcome"), handler::welcomeMsg)
                .andRoute(RequestPredicates.GET("/api/sum"), handler::sumOfNumbers);
    }
}

In the above LogConfig class, we define two routing points for two methods in the LogHandler class. Here, the router function returns a Server Response for every route in the LogConfig class.


Step 4: Running the Application

Once the project development is completed with the required logic, we can run this project as a Spring Boot App or by using Maven commands. Run the project as a Spring Boot App, and it will run on port 8080 with the Netty server by default.


Step 5: Testing with Postman

Now, let’s test the API endpoint using the Postman tool.

welcome API:

This API is GET Mapping

http://localhost:8080/api/welcome

Output:


sum API:

This API is GET Mapping

http://localhost:8080/api/sum

Here the N value is 10.

Output:


Step 6: Observing Logs

Now we need to trace loggers in the application. Open the console and observe the logs. Based on these logs, we can trace the execution of the application. Below, we provide the final output image for the logger, marked for a better understanding of the concept.




Contact Us