Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How do gateway, webflux and reactor-netty request log output?

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

This article introduces the knowledge of "how gateway, webflux and reactor-netty request log output". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

Gateway, webflux, reactor-netty request log output scenario

When using spring cloud gateway, you want to output the request log, considering two implementation scenarios

Option one

Reactor Netty Access Logs solution is used on the official website, and log recording is enabled by configuring "- Dreactor.netty.http.server.accessLogEnabled=true".

The output is as follows:

Reactor.netty.http.server.AccessLog:

10.2.20.177-[02/Dec/2020:16:41:57 + 0800] "GET / fapi/gw/hi/login HTTP/1.1" 200319 8080 626 ms

Advantages: simple and convenient

Disadvantages: fixed format and less information

Option 2

Create a logfilter, parse the request in logfilter, and output the request information

Advantages: you can customize the log format and content, and you can get body information.

Disadvantages: you need to write another filter for the returned information. If there is no match to the route, you cannot enter the logfilter.

Train of thought

The first plan is modified to meet the demand. Analysis of reactor-netty source code, mainly related to

AccessLog: logging tool, log structure

AccessLogHandler:http1.1 protocol log control, which we mainly use.

AccessLogHandler2:http2 protocol log control

The code is as follows:

Package reactor.netty.http.server; import reactor.util.Logger;import reactor.util.Loggers; import java.time.ZonedDateTime;import java.time.format.DateTimeFormatter;import java.util.Locale;import java.util.Objects; final class AccessLog {static final Logger log = Loggers.getLogger ("reactor.netty.http.server.AccessLog"); static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern ("dd/MMM/yyyy:HH:mm:ss Z", Locale.US) Static final String COMMON_LOG_FORMAT = "{}-{} [{}]\" {} {}\ "{} ms"; static final String MISSING = "-"; final String zonedDateTime; String address; CharSequence method; CharSequence uri; String protocol; String user = MISSING; CharSequence status; long contentLength; boolean chunked; long startTime = System.currentTimeMillis () Int port; AccessLog () {this.zonedDateTime = ZonedDateTime.now (). Format (DATE_TIME_FORMATTER);} AccessLog address (String address) {this.address = Objects.requireNonNull (address, "address"); return this;} AccessLog port (int port) {this.port = port; return this } AccessLog method (CharSequence method) {this.method = Objects.requireNonNull (method, "method"); return this;} AccessLog uri (CharSequence uri) {this.uri = Objects.requireNonNull (uri, "uri"); return this;} AccessLog protocol (String protocol) {this.protocol = Objects.requireNonNull (protocol, "protocol"); return this } AccessLog status (CharSequence status) {this.status = Objects.requireNonNull (status, "status"); return this;} AccessLog contentLength (long contentLength) {this.contentLength = contentLength; return this;} AccessLog increaseContentLength (long contentLength) {if (chunked) {this.contentLength + = contentLength;} return this } AccessLog chunked (boolean chunked) {this.chunked = chunked; return this;} long duration () {return System.currentTimeMillis ()-startTime;} void log () {if (log.isInfoEnabled ()) {log.info (COMMON_LOG_FORMAT, address, user, zonedDateTime, method, uri, protocol, status, (contentLength >-1? ContentLength: MISSING), port, duration ();}

AccessLogHandler: log control

Package reactor.netty.http.server; import io.netty.buffer.ByteBuf;import io.netty.buffer.ByteBufHolder;import io.netty.channel.ChannelDuplexHandler;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelPromise;import io.netty.channel.socket.SocketChannel;import io.netty.handler.codec.http.HttpRequest;import io.netty.handler.codec.http.HttpResponse;import io.netty.handler.codec.http.HttpResponseStatus;import io.netty.handler.codec.http.HttpUtil;import io.netty.handler.codec.http.LastHttpContent / * * @ author Violeta Georgieva * / final class AccessLogHandler extends ChannelDuplexHandler {AccessLog accessLog = new AccessLog (); @ Override public void channelRead (ChannelHandlerContext ctx, Object msg) {if (msg instanceof HttpRequest) {final HttpRequest request = (HttpRequest) msg; final SocketChannel channel = (SocketChannel) ctx.channel () AccessLog = new AccessLog () .address (channel.remoteAddress () .getHostString ()) .port (channel.localAddress () .getPort ()) .method (request.method () .name ()) .uri (request.uri ()) .protocol (request.protocolVersion () .text ()) } ctx.fireChannelRead (msg);} @ Override @ SuppressWarnings ("FutureReturnValueIgnored") public void write (ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {if (msg instanceof HttpResponse) {final HttpResponse response = (HttpResponse) msg; final HttpResponseStatus status = response.status () If (status.equals (HttpResponseStatus.CONTINUE)) {/ / "FutureReturnValueIgnored" this is deliberate ctx.write (msg, promise); return;} final boolean chunked = HttpUtil.isTransferEncodingChunked (response); accessLog.status (status.codeAsText ()) .chunked (chunked) If (! chunked) {accessLog.contentLength (HttpUtil.getContentLength (response,-1));}} if (msg instanceof LastHttpContent) {accessLog.increaseContentLength (LastHttpContent) msg) .content () .readableBytes ()) Ctx.write (msg, promise.unvoid ()) .addListener (future-> {if (future.isSuccess ()) {accessLog.log ();}}); return } if (msg instanceof ByteBuf) {accessLog.increaseContentLength ((ByteBuf) msg). ReadableBytes ();} if (msg instanceof ByteBufHolder) {accessLog.increaseContentLength (ByteBufHolder) msg). Content (). ReadableBytes ());} / / "FutureReturnValueIgnored" this is deliberate ctx.write (msg, promise);}}

Execution sequence

AccessLogHandler.channelRead > GlobalFilter.filter > AbstractLoadBalance.choose > response.writeWith > AccessLogHandler.write

Solution

Rewrite AccessLog and AccessLogHandler to output the content and style you want.

The channelRead and write methods in ChannelDuplexHandler are overridden in AccessLogHandler, and methods in ChannelInboundHandler and ChannelOutboundHandler can also be overridden to cover the entire lifecycle of the request.

Spring-webflux, gateway, springboot-start-web question Spring-webflux

When both are configured, it is not a webflux web application, it is still a spring mvc web application.

There is a note in the official document:

Many developers add spring-boot-start-webflux to their spring mvc web applicaiton to use reactive WebClient. If you want to change the webApplication type, you need to display the settings, such as SpringApplication.setWebApplicationType (WebApplicationType.REACTIVE).

Org.springframework.boot spring-boot-starter-webflux org.springframework.boot spring-boot-starter-web

Conclusion 1:

When both are configured, it is not a webflux web application, it is still a spring mvc web application. But the startup will not report an error and can be used normally, but the webflux function is invalid.

Spring-gateway

Because gateway is different from zuul, gateway uses a long connection and netty-webflux,zuul1.0 uses synchronous webmvc.

So your non-gateway sub-project starts with webmvc, and your gateway starts with webflux. Spring-boot-start-web and spring-boot-start-webflux are extremely jealous when they meet.

Cannot be configured in the same pom.xml or in the same project, otherwise an error will be started

Org.springframework.cloud spring-cloud-starter-gateway

Conclusion 2:

When spring-cloud-gateway and spring-boot-starer-web are configured together, the startup directly reports an error and the dependency package conflict is incompatible.

This is the end of the content of "how gateway, webflux, and reactor-netty request log output". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report