gateway、webflux、reactor-netty请求日志输出的方式是什么(gateway,reactor-netty,webflux,开发技术)

时间:2024-04-28 23:32:52 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

gateway、webflux、reactor-netty请求日志输出

场景

在使用spring cloud gateway时想要输出请求日志,考虑到两种实现方案

方案一

官网中使用Reactor Netty Access Logs方案,配置“-Dreactor.netty.http.server.accessLogEnabled=true”开启日志记录。

输出如下:

reactor.netty.http.server.AccessLog :
10.2.20.177 - - [02/Dec/2020:16:41:57 +0800] "GET /fapi/gw/hi/login HTTP/1.1" 200 319 8080 626 ms

  • 优点:简单方便

  • 缺点:格式固定,信息量少

方案二

创建一个logfilter,在logfilter中解析request,并输出请求信息

  • 优点:可以自定义日志格式和内容,可以获取body信息

  • 缺点:返回信息需要再写一个filter,没有匹配到路由时无法进入到logfilter中

思路

对方案一进行改造,使其满足需求。对reactor-netty源码分析,主要涉及

  • AccessLog:日志工具,日志结构体

  • AccessLogHandler:http1.1协议日志控制,我们主要使用这个。

  • AccessLogHandler2:http2协议日志控制

代码如下:

packagereactor.netty.http.server;importreactor.util.Logger;importreactor.util.Loggers;importjava.time.ZonedDateTime;importjava.time.format.DateTimeFormatter;importjava.util.Locale;importjava.util.Objects;finalclassAccessLog{staticfinalLoggerlog=Loggers.getLogger("reactor.netty.http.server.AccessLog");staticfinalDateTimeFormatterDATE_TIME_FORMATTER=DateTimeFormatter.ofPattern("dd/MMM/yyyy:HH:mm:ssZ",Locale.US);staticfinalStringCOMMON_LOG_FORMAT="{}-{}[{}]\"{}{}{}\"{}{}{}{}ms";staticfinalStringMISSING="-";finalStringzonedDateTime;Stringaddress;CharSequencemethod;CharSequenceuri;Stringprotocol;Stringuser=MISSING;CharSequencestatus;longcontentLength;booleanchunked;longstartTime=System.currentTimeMillis();intport;AccessLog(){this.zonedDateTime=ZonedDateTime.now().format(DATE_TIME_FORMATTER);}AccessLogaddress(Stringaddress){this.address=Objects.requireNonNull(address,"address");returnthis;}AccessLogport(intport){this.port=port;returnthis;}AccessLogmethod(CharSequencemethod){this.method=Objects.requireNonNull(method,"method");returnthis;}AccessLoguri(CharSequenceuri){this.uri=Objects.requireNonNull(uri,"uri");returnthis;}AccessLogprotocol(Stringprotocol){this.protocol=Objects.requireNonNull(protocol,"protocol");returnthis;}AccessLogstatus(CharSequencestatus){this.status=Objects.requireNonNull(status,"status");returnthis;}AccessLogcontentLength(longcontentLength){this.contentLength=contentLength;returnthis;}AccessLogincreaseContentLength(longcontentLength){if(chunked){this.contentLength+=contentLength;}returnthis;}AccessLogchunked(booleanchunked){this.chunked=chunked;returnthis;}longduration(){returnSystem.currentTimeMillis()-startTime;}voidlog(){if(log.isInfoEnabled()){log.info(COMMON_LOG_FORMAT,address,user,zonedDateTime,method,uri,protocol,status,(contentLength>-1?contentLength:MISSING),port,duration());}}}
  • AccessLogHandler:日志控制

packagereactor.netty.http.server;importio.netty.buffer.ByteBuf;importio.netty.buffer.ByteBufHolder;importio.netty.channel.ChannelDuplexHandler;importio.netty.channel.ChannelHandlerContext;importio.netty.channel.ChannelPromise;importio.netty.channel.socket.SocketChannel;importio.netty.handler.codec.http.HttpRequest;importio.netty.handler.codec.http.HttpResponse;importio.netty.handler.codec.http.HttpResponseStatus;importio.netty.handler.codec.http.HttpUtil;importio.netty.handler.codec.http.LastHttpContent;/***@authorVioletaGeorgieva*/finalclassAccessLogHandlerextendsChannelDuplexHandler{AccessLogaccessLog=newAccessLog();@OverridepublicvoidchannelRead(ChannelHandlerContextctx,Objectmsg){if(msginstanceofHttpRequest){finalHttpRequestrequest=(HttpRequest)msg;finalSocketChannelchannel=(SocketChannel)ctx.channel();accessLog=newAccessLog().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")publicvoidwrite(ChannelHandlerContextctx,Objectmsg,ChannelPromisepromise){if(msginstanceofHttpResponse){finalHttpResponseresponse=(HttpResponse)msg;finalHttpResponseStatusstatus=response.status();if(status.equals(HttpResponseStatus.CONTINUE)){//"FutureReturnValueIgnored"thisisdeliberatectx.write(msg,promise);return;}finalbooleanchunked=HttpUtil.isTransferEncodingChunked(response);accessLog.status(status.codeAsText()).chunked(chunked);if(!chunked){accessLog.contentLength(HttpUtil.getContentLength(response,-1));}}if(msginstanceofLastHttpContent){accessLog.increaseContentLength(((LastHttpContent)msg).content().readableBytes());ctx.write(msg,promise.unvoid()).addListener(future->{if(future.isSuccess()){accessLog.log();}});return;}if(msginstanceofByteBuf){accessLog.increaseContentLength(((ByteBuf)msg).readableBytes());}if(msginstanceofByteBufHolder){accessLog.increaseContentLength(((ByteBufHolder)msg).content().readableBytes());}//"FutureReturnValueIgnored"thisisdeliberatectx.write(msg,promise);}}

执行顺序

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

解决方案

对AccessLog和AccessLogHandler进行重写,输出自己想要的内容和样式。

AccessLogHandler中重写了ChannelDuplexHandler中的channelRead和write方法,还可以对ChannelInboundHandler和ChannelOutboundHandler中的方法进行重写,覆盖请求的整个生命周期。

spring-webflux、gateway、springboot-start-web问题

Spring-webflux

当两者一起时配置的并不是webflux web application, 仍然时一个spring mvc web application。

官方文档中有这么一段注解:

很多开发者添加spring-boot-start-webflux到他们的spring mvc web applicaiton去是为了使用reactive WebClient. 如果希望更改webApplication 类型需要显示的设置,如SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE).

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

结论一:

当两者一起时配置的并不是webflux web application, 仍然时一个spring mvc web application。但是启动不会报错,可以正常使用,但是webflux功能失效

gateway、webflux、reactor-netty请求日志输出的方式是什么

Spring-gateway

因为gateway和zuul不一样,gateway用的是长连接,netty-webflux,zuul1.0用的就是同步webmvc。

所以你的非gateway子项目启动用的是webmvc,你的gateway启动用的是webflux. spring-boot-start-web和spring-boot-start-webflux相见分外眼红。

不能配置在同一pom.xml,或者不能在同一项目中出现,不然就会启动报错

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>

结论二:

当spring-cloud-gateway和spring-boot-starer-web两者一起时配置的时候, 启动直接报错,依赖包冲突不兼容

 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:gateway、webflux、reactor-netty请求日志输出的方式是什么的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:python中pip安装库时出现Read timed out怎么解决下一篇:

3 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18