Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to turn on the access log for Spring WebFlux?

For Spring WebFlux running on Netty I want to have access logs like in Tomcat, but I find nothing in the Spring documentation.

Can anyone help?

like image 565
hongshuwei Avatar asked Nov 03 '17 08:11

hongshuwei


People also ask

How do you add a spring log?

React + Spring Boot Microservices and SpringSpring Boot uses Apache Commons logging for all internal logging. Spring Boot's default configurations provides a support for the use of Java Util Logging, Log4j2, and Logback. Using these, we can configure the console logging as well as file logging.

How do I log a body response in WebClient?

Logging Request and Response with Body HTTP clients have features to log the bodies of requests and responses. Thus, to achieve the goal, we are going to use a log-enabled HTTP client with our WebClient. We can do this by manually setting WebClient. Builder#clientConnector – let's see with Jetty and Netty HTTP clients.

How do I log in spring boot Microservices?

You can create an executable JAR file, and run the Spring Boot application by using the following Maven or Gradle commands. After “BUILD SUCCESS”, you can find the JAR file under the target directory. After “BUILD SUCCESSFUL”, you can find the JAR file under the build/libs directory.


2 Answers

This has been implemented in Netty v0.7.9.RELEASE following this issue. According to the instructions posted here you can enable the log so:

  • Run your application with -Dreactor.netty.http.server.accessLogEnabled=true system property

AND

  • Enable INFO logging of reactor.netty.http.server.AccessLog

Note that only CLF is supported for the moment.

Other solutions, available before that feature was implemented, are eg.:

Wire log

As @GreyTeardrop mentioned in the comment, you can set the log level of reactor.ipc.netty.channel.ContextHandler and reactor.ipc.netty.http.server.HttpServer to DEBUG. This will produce a multi-line dump of each message as a hex + ASCII table. Not exactly pleasant fo production use, but can be useful for debugging.

Spring Actuator HTTP trace

If you have Spring Actuator in your project, is supports tracing of HTTP requests. The trace information is sent to a HttpTraceRepository bean. By default it's a InMemoryHttpTraceRepository that holds the last 100 traces.

You can leverage that by implementing your own HttpTraceRepository or a decorator to it that will add logging of the traces. You need to register it as a bean - it will replace the autoconfigured InMemoryHttpTraceRepository.

Note that the HTTP traces only have a limited set of information about the request and response, eg. you don't have access to request/response body or size.

A solution that I ended up implementing looks like this:

@Bean
public HttpTraceRepository httpTraceRepository() {
    return new AccessLoggingHttpTraceRepositoryDecorator(
            new InMemoryHttpTraceRepository(),
            LoggerFactory.getLogger("netty.Access"),
            new HttpTraceLogFormatter()
    );
}

public class AccessLoggingHttpTraceRepositoryDecorator implements HttpTraceRepository {

    private HttpTraceRepository delegate;
    private Logger logger;
    private HttpTraceLogFormatter formatter;

    public AccessLoggingHttpTraceRepositoryDecorator(HttpTraceRepository delegate, Logger logger, HttpTraceLogFormatter formatter) {
        this.delegate = delegate;
        this.logger = logger;
        this.formatter = formatter;
    }

    @Override
    public List<HttpTrace> findAll() {
        return delegate.findAll();
    }

    @Override
    public void add(HttpTrace trace) {
        if (logger.isDebugEnabled()) {
            try {
                logger.debug(formatter.format(trace));
            } catch (Exception e) {
                logger.error("Failed to log trace " + trace, e);
            }
        }
        delegate.add(trace);
    }
}

public class HttpTraceLogFormatter {
    public String format(HttpTrace trace) {
        // TODO implement this according to your preference
        return ...;
    }
}

With this approach you can get an almost Common Log Format message.

You may need to adjust in your application.yml what is included in the trace object by specifying

management:
  trace:
    http:
      include: REQUEST_HEADERS, RESPONSE_HEADERS, PRINCIPAL, REMOTE_ADDRESS, TIME_TAKEN

By default only REQUEST_HEADERS, RESPONSE_HEADERS, COOKIE_HEADERS, TIME_TAKEN are included.

Your own access logging WebFilter

Spring Boot Actuator implements tracing with the help of HttpTraceWebFilter. If you don't want to use the Actuator's solution, you may take inspiration from the source code of the HttpTraceWebFilter and implement your own WebFilter. Expose it as a Spring bean and it will be automatically registered with Netty.

like image 120
Adam Michalik Avatar answered Sep 17 '22 01:09

Adam Michalik


Extending the excellent answer from Adam Michalik, I just want to mention that using the JVM argument -Dreactor.netty.http.server.accessLogEnabled=true along with the logger reactor.netty.http.server.AccessLog worked for me with Greenwich but not with Finchley.

I'm using Spring Cloud Gateway v2.1.2, so I guess this makes sense considering the Release Trains section of Spring Cloud.

like image 26
Greg Avatar answered Sep 19 '22 01:09

Greg