This is an automated email from the ASF dual-hosted git repository.

Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new b9ef7d526a fix: defer access-log header serialization off the request 
thread (#6581) (#7527)
b9ef7d526a is described below

commit b9ef7d526ab0cc79a6874cb665c8add1f4df2989
Author: wy471x <[email protected]>
AuthorDate: Sun Oct 11 22:34:50 2026 +0800

    fix: defer access-log header serialization off the request thread (#6581) 
(#7527)
---
 .../logging/common/AbstractLoggingPlugin.java      |  2 +-
 .../common/body/LoggingServerHttpResponse.java     |  4 +-
 .../logging/common/entity/ShenyuRequestLog.java    | 47 ++++++++++++++++++++
 .../common/entity/ShenyuRequestLogTest.java        | 50 ++++++++++++++++++++++
 4 files changed, 100 insertions(+), 3 deletions(-)

diff --git 
a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-common/src/main/java/org/apache/shenyu/plugin/logging/common/AbstractLoggingPlugin.java
 
b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-common/src/main/java/org/apache/shenyu/plugin/logging/common/AbstractLoggingPlugin.java
index 75411631fa..3c9ad03be7 100644
--- 
a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-common/src/main/java/org/apache/shenyu/plugin/logging/common/AbstractLoggingPlugin.java
+++ 
b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-common/src/main/java/org/apache/shenyu/plugin/logging/common/AbstractLoggingPlugin.java
@@ -106,7 +106,7 @@ public abstract class AbstractLoggingPlugin<L extends 
ShenyuRequestLog> extends
         requestInfo.setRequestUri(request.getURI().toString());
         requestInfo.setMethod(request.getMethod().name());
         requestInfo.setRequestMethod(request.getMethod().name());
-        
requestInfo.setRequestHeader(LogCollectUtils.getHeaders(request.getHeaders()));
+        requestInfo.setRequestHeader(() -> 
LogCollectUtils.getHeaders(request.getHeaders()));
         requestInfo.setQueryParams(request.getURI().getQuery());
         requestInfo.setClientIp(HostAddressUtils.acquireIp(exchange));
         
requestInfo.setUserAgent(request.getHeaders().getFirst(GenericLoggingConstant.USER_AGENT));
diff --git 
a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-common/src/main/java/org/apache/shenyu/plugin/logging/common/body/LoggingServerHttpResponse.java
 
b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-common/src/main/java/org/apache/shenyu/plugin/logging/common/body/LoggingServerHttpResponse.java
index 28faf12c91..506cb6551d 100644
--- 
a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-common/src/main/java/org/apache/shenyu/plugin/logging/common/body/LoggingServerHttpResponse.java
+++ 
b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-common/src/main/java/org/apache/shenyu/plugin/logging/common/body/LoggingServerHttpResponse.java
@@ -147,7 +147,7 @@ public class LoggingServerHttpResponse<L extends 
ShenyuRequestLog> extends Serve
         if (Objects.nonNull(getStatusCode())) {
             logInfo.setStatus(getStatusCode().value());
         }
-        logInfo.setResponseHeader(LogCollectUtils.getHeaders(getHeaders()));
+        logInfo.setResponseHeader(() -> 
LogCollectUtils.getHeaders(getHeaders()));
         logInfo.setTraceId(getTraceId());
         final MediaType mediaType = 
exchange.getResponse().getHeaders().getContentType();
         if (MediaTypeUtils.isByteType(mediaType)) {
@@ -274,7 +274,7 @@ public class LoggingServerHttpResponse<L extends 
ShenyuRequestLog> extends Serve
         logInfo.setModule(shenyuContext.getModule());
         long costTime = 
DateUtils.acquireMillisBetween(shenyuContext.getStartDateTime(), 
LocalDateTime.now());
         logInfo.setUpstreamResponseTime(costTime);
-        
logInfo.setResponseHeader(LogCollectUtils.getHeaders(exchange.getResponse().getHeaders()));
+        logInfo.setResponseHeader(() -> 
LogCollectUtils.getHeaders(exchange.getResponse().getHeaders()));
         logInfo.setRpcType(shenyuContext.getRpcType());
         logInfo.setMethod(shenyuContext.getMethod());
         if (StringUtils.isNotBlank(shenyuContext.getRpcType())) {
diff --git 
a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-common/src/main/java/org/apache/shenyu/plugin/logging/common/entity/ShenyuRequestLog.java
 
b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-common/src/main/java/org/apache/shenyu/plugin/logging/common/entity/ShenyuRequestLog.java
index 2c5ccaeafb..6d0f9c7f57 100644
--- 
a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-common/src/main/java/org/apache/shenyu/plugin/logging/common/entity/ShenyuRequestLog.java
+++ 
b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-common/src/main/java/org/apache/shenyu/plugin/logging/common/entity/ShenyuRequestLog.java
@@ -17,6 +17,9 @@
 
 package org.apache.shenyu.plugin.logging.common.entity;
 
+import java.util.Objects;
+import java.util.function.Supplier;
+
 /**
  * shenyu gateway access log.
  */
@@ -34,6 +37,18 @@ public class ShenyuRequestLog {
 
     private String responseHeader;
 
+    /**
+     * Deferred source of the request header json, resolved on first read.
+     * Transient so the log clients never serialize it.
+     */
+    private transient Supplier<String> requestHeaderSupplier;
+
+    /**
+     * Deferred source of the response header json, resolved on first read.
+     * Transient so the log clients never serialize it.
+     */
+    private transient Supplier<String> responseHeaderSupplier;
+
     private String queryParams;
 
     private String requestBody;
@@ -224,6 +239,10 @@ public class ShenyuRequestLog {
      * @return requestHeader
      */
     public String getRequestHeader() {
+        if (Objects.nonNull(requestHeaderSupplier)) {
+            requestHeader = requestHeaderSupplier.get();
+            requestHeaderSupplier = null;
+        }
         return requestHeader;
     }
 
@@ -234,6 +253,18 @@ public class ShenyuRequestLog {
      */
     public void setRequestHeader(final String requestHeader) {
         this.requestHeader = requestHeader;
+        this.requestHeaderSupplier = null;
+    }
+
+    /**
+     * set requestHeader lazily, so the header json is built by whoever reads 
it instead of
+     * the request thread that produced the log entry.
+     *
+     * @param requestHeaderSupplier supplier of the serialized request header 
json
+     */
+    public void setRequestHeader(final Supplier<String> requestHeaderSupplier) 
{
+        this.requestHeaderSupplier = requestHeaderSupplier;
+        this.requestHeader = null;
     }
 
     /**
@@ -242,6 +273,10 @@ public class ShenyuRequestLog {
      * @return responseHeader
      */
     public String getResponseHeader() {
+        if (Objects.nonNull(responseHeaderSupplier)) {
+            responseHeader = responseHeaderSupplier.get();
+            responseHeaderSupplier = null;
+        }
         return responseHeader;
     }
 
@@ -252,6 +287,18 @@ public class ShenyuRequestLog {
      */
     public void setResponseHeader(final String responseHeader) {
         this.responseHeader = responseHeader;
+        this.responseHeaderSupplier = null;
+    }
+
+    /**
+     * set responseHeader lazily, so the header json is built by whoever reads 
it instead of
+     * the response thread that produced the log entry.
+     *
+     * @param responseHeaderSupplier supplier of the serialized response 
header json
+     */
+    public void setResponseHeader(final Supplier<String> 
responseHeaderSupplier) {
+        this.responseHeaderSupplier = responseHeaderSupplier;
+        this.responseHeader = null;
     }
 
     /**
diff --git 
a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-common/src/test/java/org/apache/shenyu/plugin/logging/common/entity/ShenyuRequestLogTest.java
 
b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-common/src/test/java/org/apache/shenyu/plugin/logging/common/entity/ShenyuRequestLogTest.java
index 21bcc69326..eda1a32121 100644
--- 
a/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-common/src/test/java/org/apache/shenyu/plugin/logging/common/entity/ShenyuRequestLogTest.java
+++ 
b/shenyu-plugin/shenyu-plugin-logging/shenyu-plugin-logging-common/src/test/java/org/apache/shenyu/plugin/logging/common/entity/ShenyuRequestLogTest.java
@@ -17,10 +17,12 @@
 
 package org.apache.shenyu.plugin.logging.common.entity;
 
+import org.apache.shenyu.common.utils.GsonUtils;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 import java.time.LocalDateTime;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * The Test Case For ShenyuRequestLog.
@@ -90,6 +92,54 @@ public class ShenyuRequestLogTest {
         Assertions.assertEquals(shenyuRequestLog.getRequestHeader(), "{}");
     }
 
+    @Test
+    public void testRequestHeaderIsSerializedLazily() {
+        AtomicInteger invocations = new AtomicInteger();
+        shenyuRequestLog.setRequestHeader(() -> {
+            invocations.incrementAndGet();
+            return "{\"X-source\":\"mock test\"}";
+        });
+        Assertions.assertEquals(0, invocations.get());
+        Assertions.assertEquals("{\"X-source\":\"mock test\"}", 
shenyuRequestLog.getRequestHeader());
+        Assertions.assertEquals(1, invocations.get());
+        Assertions.assertEquals("{\"X-source\":\"mock test\"}", 
shenyuRequestLog.getRequestHeader());
+        Assertions.assertEquals(1, invocations.get());
+    }
+
+    @Test
+    public void testResponseHeaderIsSerializedLazily() {
+        AtomicInteger invocations = new AtomicInteger();
+        shenyuRequestLog.setResponseHeader(() -> {
+            invocations.incrementAndGet();
+            return "{\"X-response\":\"mock test\"}";
+        });
+        Assertions.assertEquals(0, invocations.get());
+        Assertions.assertEquals("{\"X-response\":\"mock test\"}", 
shenyuRequestLog.getResponseHeader());
+        Assertions.assertEquals(1, invocations.get());
+    }
+
+    @Test
+    public void testResolvedHeaderIsNotSerializedTwice() {
+        AtomicInteger invocations = new AtomicInteger();
+        shenyuRequestLog.setRequestHeader(() -> {
+            invocations.incrementAndGet();
+            return "{}";
+        });
+        Assertions.assertEquals("{}", shenyuRequestLog.getRequestHeader());
+        shenyuRequestLog.setRequestHeader("{\"a\":\"b\"}");
+        Assertions.assertEquals("{\"a\":\"b\"}", 
shenyuRequestLog.getRequestHeader());
+        Assertions.assertEquals(1, invocations.get());
+    }
+
+    @Test
+    public void testDeferredHeaderSourceIsNotSerialized() {
+        shenyuRequestLog.setRequestHeader(() -> "{\"X-source\":\"mock 
test\"}");
+        shenyuRequestLog.setResponseHeader(() -> "{\"X-response\":\"mock 
test\"}");
+        String json = GsonUtils.getInstance().toJson(shenyuRequestLog);
+        Assertions.assertFalse(json.contains("Supplier"));
+        Assertions.assertFalse(json.contains("mock test"));
+    }
+
     @Test
     public void testQueryParams() {
         shenyuRequestLog.setQueryParams("{\"id\"=\"1\"}");

Reply via email to