Jersey LoggingFeature无法记录完整响应体问题求助
Jersey LoggingFeature响应体截断问题排查与解决
问题描述
我正在构建一个调用外部API的端点,需要把所有请求体记录到终端,但遇到Jersey的LoggingFeature无法完整记录响应体的问题——日志里的响应体在中间被截断了。我试过调整日志级别、Verbosity参数,把maxEntitySize设成很大的值,也尝试过把日志输出到文件,但问题依然存在。我刚接触Kotlin/Java技术栈,可能漏了关键配置,求解决方案。
日志示例
INFO [2022-10-06 13:54:04,261] se.bla.bla.bla.clients.BlaClientImpl: 1 * Sending client request on thread dw-18 - GET /api/bla/log/98014384 1 > GET https://url.com/2574339575 1 > Accept: application/json 1 > Authorization: Bearer tokenstuff INFO [2022-10-06 13:54:04,475] se.bla.bla.bla.clients.BlaClientImpl: 1 * Client response received on thread dw-18 - GET /api/bla/log/98014384 1 < 200 1 < Cache-Control: no-cache 1 < Content-Type: application/json; charset=utf-8 1 < Date: Thu, 06 Oct 2022 13:54:04 GMT 1 < Etag: Yee 1 < Server-Response-Time: 169.44395400000002 1 < Transfer-Encoding: chunked 1 < Vary: Origin 1 < X-Request-Id: Woo 1 < X-Runtime: 0.169337 {example1: "2134123123",example2: "2134123123",example3: "2134123123",example4: "2134123123",example5: "2134123123",example6: "2134123123",example7: "2134123123",example8: "2134123123",example9: "2134123123",example10: "2134123123",example11: "2134123123",example12: "2134123123",example13: "2134123123",example14: "2134123123",example15: "2134123123",example16: "2134123123",example17: "2134123123",example18: "21341
当前Logger注册代码
val restlog = getLogger(BlaClientImpl::class.java.name) restlog.addHandler(FileHandler("rest.log", 83886080, 1)) val requestBuilder = client .register( LoggingFeature( restlog, Level.INFO, LoggingFeature.Verbosity.PAYLOAD_ANY, 83886080 ) )
解决方案
1. 调整FileHandler的日志格式化规则
默认的FileHandler可能存在单条日志长度限制,即使LoggingFeature的maxEntitySize设得足够大,也会被日志处理器截断。可以自定义格式化器,避免单行截断:
val customFormatter = object : SimpleFormatter() { override fun format(lr: LogRecord): String { val sb = StringBuilder() sb.append(String.format("%1$tb %1$td, %1$tY %1$tl:%1$tM:%1$tS %1$Tp ", lr.millis)) sb.append(String.format("%s%n", lr.loggerName)) sb.append(String.format("%s: %s%n", lr.level.localizedName, lr.message)) lr.thrown?.let { val sw = StringWriter() it.printStackTrace(PrintWriter(sw)) sb.append(sw.toString()) } return sb.toString() } } val fileHandler = FileHandler("rest.log", 83886080, 1) fileHandler.formatter = customFormatter restlog.addHandler(fileHandler)
2. 自定义拦截器处理分块响应
日志显示响应采用Transfer-Encoding: chunked,Jersey原生LoggingFeature处理分块流时可能因流提前关闭导致截断。可以注册自定义WriterInterceptor完整记录响应:
class FullLoggingInterceptor(private val logger: Logger) : WriterInterceptor { override fun aroundWriteContext(context: WriterInterceptorContext) { val loggingStream = LoggingOutputStream(context.outputStream, logger) context.outputStream = loggingStream try { context.proceed() } finally { loggingStream.flush() } } private inner class LoggingOutputStream( private val delegate: OutputStream, private val logger: Logger ) : OutputStream() { private val buffer = ByteArrayOutputStream() override fun write(b: Int) { buffer.write(b) delegate.write(b) } override fun flush() { logger.info(buffer.toString(StandardCharsets.UTF_8.name())) buffer.reset() delegate.flush() } override fun close() { flush() delegate.close() } } }
注册该拦截器:
client.register(FullLoggingInterceptor(restlog))
3. 检查日志框架全局限制
如果使用SLF4J+Logback等日志框架,全局配置可能限制了单条日志长度。比如修改logback.xml中的encoder配置,取消或调大长度限制:
<encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> <maxLength>1000000</maxLength> <!-- 设置足够大的值 --> </encoder>
内容的提问来源于stack exchange,提问作者Menyten
相关产品推荐
相关产品推荐

