In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
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.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.