Merge branch '3.0.11-release' into apache-3.0
diff --git a/.asf.yaml b/.asf.yaml
index 0ff567c..07e29ba 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -39,3 +39,6 @@
     3.0:
       # only disable force push
       foo: bar
+    3.1:
+      # only disable force push
+      foo: bar
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/AccessLogFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/AccessLogFilter.java
index 8826c37..283b993 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/AccessLogFilter.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/AccessLogFilter.java
@@ -21,6 +21,7 @@
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;
 import org.apache.dubbo.common.utils.ConfigUtils;
+import org.apache.dubbo.rpc.Constants;
 import org.apache.dubbo.rpc.Filter;
 import org.apache.dubbo.rpc.Invocation;
 import org.apache.dubbo.rpc.Invoker;
@@ -35,6 +36,7 @@
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Queue;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
@@ -102,17 +104,25 @@
                 .getBean(FrameworkExecutorRepository.class).getSharedScheduledExecutor()
                 .scheduleWithFixedDelay(this::writeLogToFile, LOG_OUTPUT_INTERVAL, LOG_OUTPUT_INTERVAL, TimeUnit.MILLISECONDS);
         }
+        Optional<AccessLogData> optionalAccessLogData = Optional.empty();
+        String accessLogKey = null;
         try {
-            String accessLogKey = invoker.getUrl().getParameter(ACCESS_LOG_KEY);
+            accessLogKey = invoker.getUrl().getParameter(Constants.ACCESS_LOG_KEY);
             if (ConfigUtils.isNotEmpty(accessLogKey)) {
-                AccessLogData logData = AccessLogData.newLogData();
-                logData.buildAccessLogData(invoker, inv);
-                log(accessLogKey, logData);
+                optionalAccessLogData = Optional.of(buildAccessLogData(invoker, inv));
             }
         } catch (Throwable t) {
             logger.warn("Exception in AccessLogFilter of service(" + invoker + " -> " + inv + ")", t);
         }
-        return invoker.invoke(inv);
+        try {
+            return invoker.invoke(inv);
+        } finally {
+            String finalAccessLogKey = accessLogKey;
+            optionalAccessLogData.ifPresent(logData -> {
+                logData.setOutTime(new Date());
+                log(finalAccessLogKey, logData);
+            });
+        }
     }
 
     private void log(String accessLog, AccessLogData accessLogData) {
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/AccessLogData.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/AccessLogData.java
index 482932d..f231ae9 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/AccessLogData.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/AccessLogData.java
@@ -38,13 +38,14 @@
  */
 public final class AccessLogData {
 
-    private static final String MESSAGE_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
+    private static final String MESSAGE_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSSSS";
     private static final DateTimeFormatter MESSAGE_DATE_FORMATTER = DateTimeFormatter.ofPattern(MESSAGE_DATE_FORMAT);
     private static final String VERSION = "version";
     private static final String GROUP = "group";
     private static final String SERVICE = "service";
     private static final String METHOD_NAME = "method-name";
     private static final String INVOCATION_TIME = "invocation-time";
+    private static final String OUT_TIME = "out-time";
     private static final String TYPES = "types";
     private static final String ARGUMENTS = "arguments";
     private static final String REMOTE_HOST = "remote-host";
@@ -116,6 +117,15 @@
     }
 
     /**
+     * Set the out date. As an argument it accept date string.
+     *
+     * @param outTime
+     */
+    public void setOutTime(Date outTime) {
+        set(OUT_TIME, outTime);
+    }
+
+    /**
      * Set caller remote host
      *
      * @param remoteHost
@@ -191,9 +201,13 @@
     public String getLogMessage() {
         StringBuilder sn = new StringBuilder();
 
-        sn.append('[')
+        sn.append("[")
             .append(LocalDateTime.ofInstant(getInvocationTime().toInstant(), ZoneId.systemDefault()).format(MESSAGE_DATE_FORMATTER))
             .append("] ")
+            .append("-> ")
+            .append("[")
+            .append(LocalDateTime.ofInstant(getOutTime().toInstant(), ZoneId.systemDefault()).format(MESSAGE_DATE_FORMATTER))
+            .append("] ")
             .append(get(REMOTE_HOST))
             .append(':')
             .append(get(REMOTE_PORT))
@@ -244,6 +258,10 @@
         return (Date) get(INVOCATION_TIME);
     }
 
+    private Date getOutTime() {
+        return (Date)get(OUT_TIME);
+    }
+
     /**
      * Return value of key
      *