0

我一直在尝试使用 webflux 配置 spring-boot 2.1 以将访问日志存储在 JSON 中。此外,我需要将协议、状态代码等信息作为单独的 JSON 字段(不是消息的一部分)。查看互联网,我发现了 logstash-logback-encoder。这似乎有我需要的一切。但是在运行时我收到以下错误:

ERROR in ch.qos.logback.core.FileAppender[accessLog] - Appender [accessLog] failed to append. java.lang.ClassCastException: ch.qos.logback.classic.spi.LoggingEvent cannot be cast to ch.qos.logback.access.spi.IAccessEvent
at java.lang.ClassCastException: ch.qos.logback.classic.spi.LoggingEvent cannot be cast to ch.qos.logback.access.spi.IAccessEvent
at  at net.logstash.logback.composite.accessevent.AccessEventFormattedTimestampJsonProvider.getTimestampAsMillis(AccessEventFormattedTimestampJsonProvider.java:20)
at  at net.logstash.logback.composite.FormattedTimestampJsonProvider.writeTo(FormattedTimestampJsonProvider.java:149)
at  at net.logstash.logback.composite.JsonProviders.writeTo(JsonProviders.java:77)
at  at net.logstash.logback.composite.CompositeJsonFormatter.writeEventToGenerator(CompositeJsonFormatter.java:189)
at  at net.logstash.logback.composite.CompositeJsonFormatter.writeEventToOutputStream(CompositeJsonFormatter.java:166)
at  at net.logstash.logback.encoder.CompositeJsonEncoder.encode(CompositeJsonEncoder.java:122)
at  at net.logstash.logback.encoder.CompositeJsonEncoder.encode(CompositeJsonEncoder.java:34)
at  at ch.qos.logback.core.OutputStreamAppender.subAppend(OutputStreamAppender.java:230)
at  at ch.qos.logback.core.OutputStreamAppender.append(OutputStreamAppender.java:102)
at  at ch.qos.logback.core.UnsynchronizedAppenderBase.doAppend(UnsynchronizedAppenderBase.java:84)
at  at ch.qos.logback.core.spi.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:51)
at  at ch.qos.logback.classic.Logger.appendLoopOnAppenders(Logger.java:270)
at  at ch.qos.logback.classic.Logger.callAppenders(Logger.java:257)
at  at ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:421)
at  at ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus(Logger.java:383)
at  at ch.qos.logback.classic.Logger.info(Logger.java:591)
at  at reactor.util.Loggers$Slf4JLogger.info(Loggers.java:255)
at  at reactor.netty.http.server.AccessLog.log(AccessLog.java:104)
at  at reactor.netty.http.server.AccessLogHandler.lambda$write$0(AccessLogHandler.java:77)
at  at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:511)
at  at io.netty.util.concurrent.DefaultPromise.notifyListeners0(DefaultPromise.java:504)
at  at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:483)
at  at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:424)
at  at io.netty.util.concurrent.DefaultPromise.trySuccess(DefaultPromise.java:103)
at  at io.netty.util.internal.PromiseNotificationUtil.trySuccess(PromiseNotificationUtil.java:48)
at  at io.netty.channel.ChannelOutboundBuffer.safeSuccess(ChannelOutboundBuffer.java:696)
at  at io.netty.channel.ChannelOutboundBuffer.remove(ChannelOutboundBuffer.java:258)
at  at io.netty.channel.nio.AbstractNioByteChannel.doWriteInternal(AbstractNioByteChannel.java:216)
at  at io.netty.channel.nio.AbstractNioByteChannel.doWrite0(AbstractNioByteChannel.java:209)
at  at io.netty.channel.socket.nio.NioSocketChannel.doWrite(NioSocketChannel.java:397)
at  at io.netty.channel.AbstractChannel$AbstractUnsafe.flush0(AbstractChannel.java:934)
at  at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.flush0(AbstractNioChannel.java:360)
at  at io.netty.channel.AbstractChannel$AbstractUnsafe.flush(AbstractChannel.java:901)
at  at io.netty.channel.DefaultChannelPipeline$HeadContext.flush(DefaultChannelPipeline.java:1396)
at  at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:776)
at  at io.netty.channel.AbstractChannelHandlerContext.invokeFlush(AbstractChannelHandlerContext.java:768)
at  at io.netty.channel.AbstractChannelHandlerContext.flush(AbstractChannelHandlerContext.java:749)
at  at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.flush(CombinedChannelDuplexHandler.java:533)
at  at io.netty.channel.ChannelOutboundHandlerAdapter.flush(ChannelOutboundHandlerAdapter.java:115)
at  at io.netty.channel.CombinedChannelDuplexHandler.flush(CombinedChannelDuplexHandler.java:358)
at  at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:776)
at  at io.netty.channel.AbstractChannelHandlerContext.invokeFlush(AbstractChannelHandlerContext.java:768)
at  at io.netty.channel.AbstractChannelHandlerContext.flush(AbstractChannelHandlerContext.java:749)
at  at io.netty.channel.ChannelDuplexHandler.flush(ChannelDuplexHandler.java:117)
at  at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:776)
at  at io.netty.channel.AbstractChannelHandlerContext.invokeFlush(AbstractChannelHandlerContext.java:768)
at  at io.netty.channel.AbstractChannelHandlerContext.flush(AbstractChannelHandlerContext.java:749)
at  at io.netty.channel.ChannelDuplexHandler.flush(ChannelDuplexHandler.java:117)
at  at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:776)
at  at io.netty.channel.AbstractChannelHandlerContext.invokeFlush(AbstractChannelHandlerContext.java:768)

我的配置相当简单:

<appender name="accessLog" class="ch.qos.logback.core.FileAppender">
    <file>${LOGS}/access_log.log</file>
    <encoder class="net.logstash.logback.encoder.LogstashAccessEncoder"/>
</appender>

<logger name="reactor.netty.http.server.AccessLog" level="DEBUG" additivity="false">
    <appender-ref ref="accessLog"/>
</logger>

在这一点上,我被卡住了。我一直在搜索互联网并查看 logback 代码,但我仍然不知道该怎么做才能让 AccessEvent 包含更多信息,而不是 LoggingEvent

4

1 回答 1

1

from logstash LogstashAccessEncoder-logback-encoder 需要logback-access,它提供了 AccessEvents。logback-access 仅适用于 jetty 和 tomcat。它不适用于 reactor-netty。

Reactor-nettyreactor.netty.http.server.AccessLog仅使用标准日志事件(不是 AccessEvent)。所以,如果你想使用 logstash-logback-encoder,你可以使用 aLogstashEncoder而不是 a LogstashAccessEncoder,像这样:

<appender name="accessLog" class="ch.qos.logback.core.FileAppender">
    <file>${LOGS}/access_log.log</file>
    <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>

<logger name="reactor.netty.http.server.AccessLog" level="DEBUG" additivity="false">
    <appender-ref ref="accessLog"/>
</logger>

缺点是LogstashEncoder对 HTTP 请求一无所知。它只知道通过Logger. 因此,您无法配置在使用时记录哪些 HTTP 详细信息,LogstashEncoder就像使用LogstashAccessEncoder. 相反,您的日志事件将仅显示reactor.netty.http.server.AccessLog作为日志消息的一部分提供的详细信息。详细信息将不会作为 JSON 输出中的单独字段提供。虽然,由于 logstash-logback-encoder 是高度可定制的,您可以编写一个自定义JsonProvider来解析日志消息reactor.netty.http.server.AccessLog并将其拆分为单独的 JSON 字段。

于 2019-03-23T23:28:33.307 回答