You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by wu...@apache.org on 2018/06/05 07:29:48 UTC

[incubator-servicecomb-java-chassis] 06/06: [SCB-616] refactor access log extension

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

wujimin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-java-chassis.git

commit b6ec5487c573f90986faa8f314e2bdb9379fb8cc
Author: yaohaishi <ya...@huawei.com>
AuthorDate: Mon Jun 4 11:13:20 2018 +0800

    [SCB-616] refactor access log extension
---
 ...gItemCreator.java => AccessLogItemCreator.java} |  19 +--
 .../vertx/accesslog/parser/AccessLogItemMeta.java  |  43 ++++--
 ...va => CompositeVertxRestAccessLogItemMeta.java} |  42 ++----
 ...emMeta.java => VertxRestAccessLogItemMeta.java} |  38 ++----
 .../parser/impl/DefaultAccessLogItemCreator.java   | 137 -------------------
 ...DefaultCompositeVertxRestAccessLogItemMeta.java |  87 ++++++++++++
 .../impl/VertxRestAccessLogPatternParser.java      | 126 +++++++----------
 ...tx.accesslog.parser.VertxRestAccessLogItemMeta} |   2 +-
 .../element/impl/UserDefinedAccessLogItem.java}    |  42 ++----
 .../impl/UserDefinedAccessLogItemLowPriority.java} |  42 ++----
 .../vertx/accesslog/impl/AccessLogHandlerTest.java | 104 ++++++++++++++
 .../TestCompositeExtendedAccessLogItemMeta.java}   |  45 ++----
 .../impl/TestSingleExtendedAccessLogItemMeta.java} |  42 +-----
 .../impl/VertxRestAccessLogPatternParserTest.java  | 151 +++++++++------------
 ...tx.accesslog.parser.VertxRestAccessLogItemMeta} |   3 +-
 15 files changed, 405 insertions(+), 518 deletions(-)

diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/VertxRestAccessLogItemCreator.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemCreator.java
similarity index 66%
rename from transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/VertxRestAccessLogItemCreator.java
rename to transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemCreator.java
index f1917eb..ebd522b 100644
--- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/VertxRestAccessLogItemCreator.java
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemCreator.java
@@ -17,29 +17,18 @@
 
 package org.apache.servicecomb.transport.rest.vertx.accesslog.parser;
 
-import java.util.List;
-
 import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem;
 
-import io.vertx.ext.web.RoutingContext;
-
 /**
- * The {@linkplain VertxRestAccessLogItemCreator}s are able to instantiate a group of {@linkplain AccessLogItem}.
+ * The {@linkplain AccessLogItemCreator}s are able to instantiate a group of {@linkplain AccessLogItem}.
  */
-public interface VertxRestAccessLogItemCreator {
-  /**
-   * @return A list of {@linkplain AccessLogItemMeta} to show that what kinds of {@linkplain AccessLogItem}
-   * this creator is able to instantiate.
-   */
-  List<AccessLogItemMeta> getAccessLogItemMeta();
-
+public interface AccessLogItemCreator<T> {
   /**
-   * Create an instance of {@linkplain AccessLogItem} which is specified by {@linkplain AccessLogItemMeta} and config.
-   * @param accessLogItemMeta determine which kind of {@linkplain AccessLogItem} is created.
+   * Create an instance of {@linkplain AccessLogItem} which is specified by the config.
    * @param config
    * e.g. For {@linkplain org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.CookieItem CookieItem},
    * the pattern may be "%{varName}C", and it's config is "varName". Some {@linkplain AccessLogItem} with no configurable
    * pattern (like "%m") will receive {@code null} as config.
    */
-  AccessLogItem<RoutingContext> createItem(AccessLogItemMeta accessLogItemMeta, String config);
+  AccessLogItem<T> createItem(String config);
 }
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java
index 131743e..b47e5d1 100644
--- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java
@@ -22,36 +22,53 @@ import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogIt
 /**
  * The meta data of {@linkplain AccessLogItem}.
  */
-public class AccessLogItemMeta {
-  private String prefix;
+public class AccessLogItemMeta<T> {
+  protected String prefix;
 
-  private String suffix;
+  protected String suffix;
 
   /**
    * Used for sorting {@linkplain AccessLogItemMeta}. Default value is 0.
    * Smaller one has higher priority.
    */
-  private int order;
+  protected int order;
 
-  public AccessLogItemMeta(String prefix, String suffix, int order) {
-    this.prefix = prefix;
-    this.suffix = suffix;
-    this.order = order;
-  }
-
-  public AccessLogItemMeta(String prefix, String suffix) {
-    this(prefix, suffix, 0);
-  }
+  protected AccessLogItemCreator<T> accessLogItemCreator;
 
   public String getPrefix() {
     return prefix;
   }
 
+  public AccessLogItemMeta<T> setPrefix(String prefix) {
+    this.prefix = prefix;
+    return this;
+  }
+
   public String getSuffix() {
     return suffix;
   }
 
+  public AccessLogItemMeta<T> setSuffix(String suffix) {
+    this.suffix = suffix;
+    return this;
+  }
+
   public int getOrder() {
     return order;
   }
+
+  public AccessLogItemMeta<T> setOrder(int order) {
+    this.order = order;
+    return this;
+  }
+
+  public AccessLogItemCreator<T> getAccessLogItemCreator() {
+    return accessLogItemCreator;
+  }
+
+  public AccessLogItemMeta<T> setAccessLogItemCreator(
+      AccessLogItemCreator<T> accessLogItemCreator) {
+    this.accessLogItemCreator = accessLogItemCreator;
+    return this;
+  }
 }
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/CompositeVertxRestAccessLogItemMeta.java
similarity index 53%
copy from transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java
copy to transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/CompositeVertxRestAccessLogItemMeta.java
index 131743e..2ad687f 100644
--- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/CompositeVertxRestAccessLogItemMeta.java
@@ -17,41 +17,15 @@
 
 package org.apache.servicecomb.transport.rest.vertx.accesslog.parser;
 
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem;
+import java.util.List;
 
 /**
- * The meta data of {@linkplain AccessLogItem}.
+ * Hold a group of {@link VertxRestAccessLogItemMeta} so that user can define
+ * only one VertxRestAccessLogItemMeta in spi loading file and load a group of meta.
+ * <p/>
+ * Once the access log loading mechanism finds that a meta is CompositeVertxRestAccessLogItemMeta,
+ * the meta hold by it will be used in access log while this meta itself will be ignored.
  */
-public class AccessLogItemMeta {
-  private String prefix;
-
-  private String suffix;
-
-  /**
-   * Used for sorting {@linkplain AccessLogItemMeta}. Default value is 0.
-   * Smaller one has higher priority.
-   */
-  private int order;
-
-  public AccessLogItemMeta(String prefix, String suffix, int order) {
-    this.prefix = prefix;
-    this.suffix = suffix;
-    this.order = order;
-  }
-
-  public AccessLogItemMeta(String prefix, String suffix) {
-    this(prefix, suffix, 0);
-  }
-
-  public String getPrefix() {
-    return prefix;
-  }
-
-  public String getSuffix() {
-    return suffix;
-  }
-
-  public int getOrder() {
-    return order;
-  }
+public abstract class CompositeVertxRestAccessLogItemMeta extends VertxRestAccessLogItemMeta {
+  public abstract List<VertxRestAccessLogItemMeta> getAccessLogItemMetas();
 }
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/VertxRestAccessLogItemMeta.java
similarity index 56%
copy from transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java
copy to transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/VertxRestAccessLogItemMeta.java
index 131743e..7f7916f 100644
--- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/VertxRestAccessLogItemMeta.java
@@ -17,41 +17,29 @@
 
 package org.apache.servicecomb.transport.rest.vertx.accesslog.parser;
 
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem;
+import io.vertx.ext.web.RoutingContext;
 
 /**
- * The meta data of {@linkplain AccessLogItem}.
+ * For vertx-rest transport way.
  */
-public class AccessLogItemMeta {
-  private String prefix;
-
-  private String suffix;
-
-  /**
-   * Used for sorting {@linkplain AccessLogItemMeta}. Default value is 0.
-   * Smaller one has higher priority.
-   */
-  private int order;
+public class VertxRestAccessLogItemMeta extends AccessLogItemMeta<RoutingContext> {
+  public VertxRestAccessLogItemMeta() {
+  }
 
-  public AccessLogItemMeta(String prefix, String suffix, int order) {
+  public VertxRestAccessLogItemMeta(String prefix, String suffix,
+      AccessLogItemCreator<RoutingContext> accessLogItemCreator, int order) {
     this.prefix = prefix;
     this.suffix = suffix;
+    this.accessLogItemCreator = accessLogItemCreator;
     this.order = order;
   }
 
-  public AccessLogItemMeta(String prefix, String suffix) {
-    this(prefix, suffix, 0);
-  }
-
-  public String getPrefix() {
-    return prefix;
-  }
-
-  public String getSuffix() {
-    return suffix;
+  public VertxRestAccessLogItemMeta(String prefix, AccessLogItemCreator<RoutingContext> accessLogItemCreator) {
+    this(prefix, null, accessLogItemCreator, 0);
   }
 
-  public int getOrder() {
-    return order;
+  public VertxRestAccessLogItemMeta(String prefix, String suffix,
+      AccessLogItemCreator<RoutingContext> accessLogItemCreator) {
+    this(prefix, suffix, accessLogItemCreator, 0);
   }
 }
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/DefaultAccessLogItemCreator.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/DefaultAccessLogItemCreator.java
deleted file mode 100644
index 6a2a6fd..0000000
--- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/DefaultAccessLogItemCreator.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.servicecomb.transport.rest.vertx.accesslog.parser.impl;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.CookieItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.DatetimeConfigurableItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.DurationMillisecondItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.DurationSecondItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.FirstLineOfRequestItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.HttpMethodItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.HttpStatusItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.InvocationContextItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.LocalHostItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.LocalPortItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.QueryStringItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.RemoteHostItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.RequestHeaderItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.RequestProtocolItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.ResponseHeaderItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.ResponseSizeItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.TraceIdItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.UrlPathItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.UrlPathWithQueryItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogItemMeta;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemCreator;
-
-import io.vertx.ext.web.RoutingContext;
-
-public class DefaultAccessLogItemCreator implements VertxRestAccessLogItemCreator {
-  private static final Map<String, AccessLogItem<RoutingContext>> SIMPLE_ACCESS_LOG_ITEM_MAP = new HashMap<>();
-
-  private static final List<AccessLogItemMeta> SUPPORTED_META_LIST = new ArrayList<>();
-
-  static {
-    AccessLogItem<RoutingContext> item = new HttpMethodItem();
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("%m", item);
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("cs-method", item);
-    item = new HttpStatusItem();
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("%s", item);
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("sc-status", item);
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("%T", new DurationSecondItem());
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("%D", new DurationMillisecondItem());
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("%h", new RemoteHostItem());
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("%v", new LocalHostItem());
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("%p", new LocalPortItem());
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("%B", new ResponseSizeItem("0"));
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("%b", new ResponseSizeItem("-"));
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("%r", new FirstLineOfRequestItem());
-    item = new UrlPathItem();
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("%U", item);
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("cs-uri-stem", item);
-    item = new QueryStringItem();
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("%q", item);
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("cs-uri-query", item);
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("cs-uri", new UrlPathWithQueryItem());
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("%H", new RequestProtocolItem());
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("%t", new DatetimeConfigurableItem());
-    SIMPLE_ACCESS_LOG_ITEM_MAP.put("%SCB-traceId", new TraceIdItem());
-
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%m", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("cs-method", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%s", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("sc-status", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%T", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%D", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%h", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%v", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%p", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%B", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%b", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%r", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%U", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("cs-uri-stem", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%q", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("cs-uri-query", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("cs-uri", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%H", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%t", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%SCB-traceId", null));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%{", "}t"));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%{", "}i"));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%{", "}o"));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%{", "}C"));
-    SUPPORTED_META_LIST.add(new AccessLogItemMeta("%{", "}SCB-ctx"));
-  }
-
-  @Override
-  public AccessLogItem<RoutingContext> createItem(AccessLogItemMeta accessLogItemMeta, String config) {
-    if (null == accessLogItemMeta.getSuffix()) {
-      // For the simple AccessLogItem
-      return SIMPLE_ACCESS_LOG_ITEM_MAP.get(accessLogItemMeta.getPrefix());
-    }
-
-    // For the configurable AccessLogItem
-    switch (accessLogItemMeta.getSuffix()) {
-      case "}t":
-        return new DatetimeConfigurableItem(config);
-      case "}i":
-        return new RequestHeaderItem(config);
-      case "}o":
-        return new ResponseHeaderItem(config);
-      case "}C":
-        return new CookieItem(config);
-      case "}SCB-ctx":
-        return new InvocationContextItem(config);
-      default:
-        // unexpected situation
-        return null;
-    }
-  }
-
-  @Override
-  public List<AccessLogItemMeta> getAccessLogItemMeta() {
-    return SUPPORTED_META_LIST;
-  }
-}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/DefaultCompositeVertxRestAccessLogItemMeta.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/DefaultCompositeVertxRestAccessLogItemMeta.java
new file mode 100644
index 0000000..aaaf9f0
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/DefaultCompositeVertxRestAccessLogItemMeta.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.transport.rest.vertx.accesslog.parser.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.CookieItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.DatetimeConfigurableItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.DurationMillisecondItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.DurationSecondItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.FirstLineOfRequestItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.HttpMethodItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.HttpStatusItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.InvocationContextItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.LocalHostItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.LocalPortItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.QueryStringItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.RemoteHostItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.RequestHeaderItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.RequestProtocolItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.ResponseHeaderItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.ResponseSizeItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.TraceIdItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.UrlPathItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.UrlPathWithQueryItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.CompositeVertxRestAccessLogItemMeta;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta;
+
+import io.vertx.ext.web.RoutingContext;
+
+public class DefaultCompositeVertxRestAccessLogItemMeta extends CompositeVertxRestAccessLogItemMeta {
+  private static final List<VertxRestAccessLogItemMeta> SUPPORTED_META = new ArrayList<>();
+
+  static {
+    final AccessLogItem<RoutingContext> httpMethodItem = new HttpMethodItem();
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%m", config -> httpMethodItem));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("cs-method", config -> httpMethodItem));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%s", config -> new HttpStatusItem()));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("sc-status", config -> new HttpStatusItem()));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%T", config -> new DurationSecondItem()));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%D", config -> new DurationMillisecondItem()));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%h", config -> new RemoteHostItem()));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%v", config -> new LocalHostItem()));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%p", config -> new LocalPortItem()));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%B", config -> new ResponseSizeItem("0")));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%b", config -> new ResponseSizeItem("-")));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%r", config -> new FirstLineOfRequestItem()));
+    final AccessLogItem<RoutingContext> urlPathItem = new UrlPathItem();
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%U", config -> urlPathItem));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("cs-uri-stem", config -> urlPathItem));
+    final AccessLogItem<RoutingContext> queryStringItem = new QueryStringItem();
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%q", config -> queryStringItem));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("cs-uri-query", config -> queryStringItem));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("cs-uri", config -> new UrlPathWithQueryItem()));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%H", config -> new RequestProtocolItem()));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%t", config -> new DatetimeConfigurableItem()));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%SCB-traceId", config -> new TraceIdItem()));
+
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%{", "}t", DatetimeConfigurableItem::new));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%{", "}i", RequestHeaderItem::new));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%{", "}o", ResponseHeaderItem::new));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%{", "}C", CookieItem::new));
+    SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%{", "}SCB-ctx", InvocationContextItem::new));
+  }
+
+  @Override
+  public List<VertxRestAccessLogItemMeta> getAccessLogItemMetas() {
+    return SUPPORTED_META;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/VertxRestAccessLogPatternParser.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/VertxRestAccessLogPatternParser.java
index 69776cc..7fdb2f9 100644
--- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/VertxRestAccessLogPatternParser.java
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/VertxRestAccessLogPatternParser.java
@@ -27,7 +27,8 @@ import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogIt
 import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.PlainTextItem;
 import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogItemMeta;
 import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogPatternParser;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemCreator;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.CompositeVertxRestAccessLogItemMeta;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -39,55 +40,53 @@ import io.vertx.ext.web.RoutingContext;
 public class VertxRestAccessLogPatternParser implements AccessLogPatternParser<RoutingContext> {
   private static final Logger LOGGER = LoggerFactory.getLogger(VertxRestAccessLogPatternParser.class);
 
-  public static final Comparator<AccessLogItemMetaWrapper> accessLogItemMetaWrapperComparator = (w1, w2) -> {
-    AccessLogItemMeta meta1 = w1.getAccessLogItemMeta();
-    AccessLogItemMeta meta2 = w2.getAccessLogItemMeta();
-    int result = meta1.getOrder() - meta2.getOrder();
+  public static final Comparator<VertxRestAccessLogItemMeta> accessLogItemMetaComparator = (m1, m2) -> {
+    int result = m1.getOrder() - m2.getOrder();
     if (result != 0) {
       return result;
     }
 
-    // one of meta1 & meta2 has suffix, but the other one doesn't have
-    if (meta1.getSuffix() == null ^ meta2.getSuffix() == null) {
-      return meta1.getSuffix() == null ? 1 : -1;
+    // one of m1 & m2 has suffix, but the other one doesn't have
+    if (m1.getSuffix() == null ^ m2.getSuffix() == null) {
+      return m1.getSuffix() == null ? 1 : -1;
     }
 
-    if (null != meta1.getSuffix()) {
-      result = comparePlaceholderString(meta1.getSuffix(), meta2.getSuffix());
+    if (null != m1.getSuffix()) {
+      result = comparePlaceholderString(m1.getSuffix(), m2.getSuffix());
     }
 
     return 0 == result ?
-        comparePlaceholderString(meta1.getPrefix(), meta2.getPrefix())
+        comparePlaceholderString(m1.getPrefix(), m2.getPrefix())
         : result;
   };
 
-  private List<VertxRestAccessLogItemCreator> creators;
-
-  private List<AccessLogItemMetaWrapper> accessLogItemMetaWrappers = new ArrayList<>();
+  private List<VertxRestAccessLogItemMeta> metaList = new ArrayList<>();
 
   public VertxRestAccessLogPatternParser() {
-    List<VertxRestAccessLogItemCreator> creators = loadVertxRestAccessLogItemCreators();
-    this.creators = creators;
-    if (null == creators) {
-      LOGGER.error("cannot load VertxRestAccessLogItemCreator!");
+    List<VertxRestAccessLogItemMeta> loadedMeta = loadVertxRestAccessLogItemMeta();
+    if (null == loadedMeta || loadedMeta.isEmpty()) {
+      LOGGER.error("cannot load AccessLogItemMeta!");
+      throw new IllegalStateException("cannot load AccessLogItemMeta!");
     }
-    for (VertxRestAccessLogItemCreator creator : this.creators) {
-      for (AccessLogItemMeta accessLogItemMeta : creator.getAccessLogItemMeta()) {
-        accessLogItemMetaWrappers.add(new AccessLogItemMetaWrapper(accessLogItemMeta, creator));
+    for (VertxRestAccessLogItemMeta meta : loadedMeta) {
+      if (CompositeVertxRestAccessLogItemMeta.class.isAssignableFrom(meta.getClass())) {
+        this.metaList.addAll(((CompositeVertxRestAccessLogItemMeta) meta).getAccessLogItemMetas());
+      } else {
+        this.metaList.add(meta);
       }
     }
-    sortAccessLogItemMetaWrapper(accessLogItemMetaWrappers);
+    sortAccessLogItemMeta(this.metaList);
   }
 
-  private List<VertxRestAccessLogItemCreator> loadVertxRestAccessLogItemCreators() {
-    return SPIServiceUtils.getOrLoadSortedService(VertxRestAccessLogItemCreator.class);
+  private List<VertxRestAccessLogItemMeta> loadVertxRestAccessLogItemMeta() {
+    return SPIServiceUtils.getOrLoadSortedService(VertxRestAccessLogItemMeta.class);
   }
 
   /**
    * Behavior of this compare:
    * 1. comparePlaceholderString("abc","bbc") < 0
    * 2. comparePlaceholderString("abc","ab") < 0
-   * 3. comparePlaceholderString("abc","abc) = 0
+   * 3. comparePlaceholderString("abc","abc") = 0
    */
   public static int comparePlaceholderString(String s1, String s2) {
     int result = s1.compareTo(s2);
@@ -105,7 +104,7 @@ public class VertxRestAccessLogPatternParser implements AccessLogPatternParser<R
   }
 
   /**
-   * Sort all of the {@link AccessLogItemMetaWrapper}, the wrapper that is in front of the others has higher priority.
+   * Sort all of the {@link AccessLogItemMeta}, the meta that is in front of the others has higher priority.
    * <p/>
    * Sort rule(priority decreased):
    * <ol>
@@ -138,8 +137,8 @@ public class VertxRestAccessLogPatternParser implements AccessLogPatternParser<R
    * <li>(%b,)</li>
    * </ol>
    */
-  public static void sortAccessLogItemMetaWrapper(List<AccessLogItemMetaWrapper> accessLogItemMetaWrapperList) {
-    accessLogItemMetaWrapperList.sort(accessLogItemMetaWrapperComparator);
+  public static void sortAccessLogItemMeta(List<VertxRestAccessLogItemMeta> accessLogItemMetaList) {
+    accessLogItemMetaList.sort(accessLogItemMetaComparator);
   }
 
   /**
@@ -156,7 +155,7 @@ public class VertxRestAccessLogPatternParser implements AccessLogPatternParser<R
   }
 
   /**
-   * Use the {@link #accessLogItemMetaWrappers} to match rawPattern.
+   * Use the {@link #metaList} to match rawPattern.
    * Return a list of {@link AccessLogItemLocation}.
    * Plain text is ignored.
    */
@@ -165,8 +164,8 @@ public class VertxRestAccessLogPatternParser implements AccessLogPatternParser<R
     int cursor = 0;
     while (cursor < rawPattern.length()) {
       AccessLogItemLocation candidate = null;
-      for (AccessLogItemMetaWrapper wrapper : accessLogItemMetaWrappers) {
-        if (null != candidate && null == wrapper.getSuffix()) {
+      for (VertxRestAccessLogItemMeta meta : metaList) {
+        if (null != candidate && null == meta.getSuffix()) {
           // TODO:
           // if user define item("%{","}ab") and item("%{_","}abc") and the pattern is "%{_var}ab}abc"
           // currently the result is item("%{","_var","}ab"), plaintext("}abc")
@@ -177,10 +176,10 @@ public class VertxRestAccessLogPatternParser implements AccessLogPatternParser<R
           cursor = candidate.tail;
           break;
         }
-        if (rawPattern.startsWith(wrapper.getPrefix(), cursor)) {
-          if (null == wrapper.getSuffix()) {
+        if (rawPattern.startsWith(meta.getPrefix(), cursor)) {
+          if (null == meta.getSuffix()) {
             // for simple type AccessLogItem, there is no need to try to match the next item.
-            candidate = new AccessLogItemLocation(cursor, wrapper);
+            candidate = new AccessLogItemLocation(cursor, meta);
             cursor = candidate.tail;
             break;
           }
@@ -188,12 +187,12 @@ public class VertxRestAccessLogPatternParser implements AccessLogPatternParser<R
           // e.g. "%{varName1}o ${varName2}i" should be divided into
           // ResponseHeaderItem with varName="varName1" and RequestHeaderItem with varName="varName2"
           // INSTEAD OF RequestHeaderItem with varName="varName1}o ${varName2"
-          int rear = rawPattern.indexOf(wrapper.getSuffix(), cursor);
+          int rear = rawPattern.indexOf(meta.getSuffix(), cursor);
           if (rear < 0) {
             continue;
           }
           if (null == candidate || rear < candidate.suffixIndex) {
-            candidate = new AccessLogItemLocation(cursor, rear, wrapper);
+            candidate = new AccessLogItemLocation(cursor, rear, meta);
           }
           // There is a matched item which is in front of this item, so this item is ignored.
         }
@@ -258,8 +257,8 @@ public class VertxRestAccessLogPatternParser implements AccessLogPatternParser<R
     List<AccessLogItem<RoutingContext>> itemList = new ArrayList<>();
 
     for (AccessLogItemLocation accessLogItemLocation : locationList) {
-      AccessLogItemMetaWrapper accessLogItemMetaWrapper = accessLogItemLocation.accessLogItemMetaWrapper;
-      if (null == accessLogItemMetaWrapper) {
+      VertxRestAccessLogItemMeta accessLogItemMeta = accessLogItemLocation.accessLogItemMeta;
+      if (null == accessLogItemMeta) {
         // a PlainTextItem location
         itemList.add(new PlainTextItem(rawPattern.substring(
             accessLogItemLocation.prefixIndex, accessLogItemLocation.tail
@@ -268,8 +267,7 @@ public class VertxRestAccessLogPatternParser implements AccessLogPatternParser<R
       }
 
       itemList.add(
-          accessLogItemMetaWrapper.getVertxRestAccessLogItemCreator().createItem(
-              accessLogItemMetaWrapper.getAccessLogItemMeta(),
+          accessLogItemMeta.getAccessLogItemCreator().createItem(
               getConfigString(rawPattern, accessLogItemLocation))
       );
     }
@@ -304,7 +302,7 @@ public class VertxRestAccessLogPatternParser implements AccessLogPatternParser<R
      */
     int tail;
 
-    AccessLogItemMetaWrapper accessLogItemMetaWrapper;
+    VertxRestAccessLogItemMeta accessLogItemMeta;
 
     /**
      * for {@link PlainTextItem} only
@@ -318,62 +316,34 @@ public class VertxRestAccessLogPatternParser implements AccessLogPatternParser<R
     /**
      * for configurable type AccessLogItem
      */
-    AccessLogItemLocation(int prefixIndex, int suffixIndex, AccessLogItemMetaWrapper accessLogItemMetaWrapper) {
+    AccessLogItemLocation(int prefixIndex, int suffixIndex, VertxRestAccessLogItemMeta accessLogItemMeta) {
       this.prefixIndex = prefixIndex;
       this.suffixIndex = suffixIndex;
-      this.tail = suffixIndex + accessLogItemMetaWrapper.getSuffix().length();
-      this.accessLogItemMetaWrapper = accessLogItemMetaWrapper;
+      this.tail = suffixIndex + accessLogItemMeta.getSuffix().length();
+      this.accessLogItemMeta = accessLogItemMeta;
     }
 
     /**
      * for simple type AccessLogItem
      */
-    AccessLogItemLocation(int prefixIndex, AccessLogItemMetaWrapper accessLogItemMetaWrapper) {
+    AccessLogItemLocation(int prefixIndex, VertxRestAccessLogItemMeta accessLogItemMeta) {
       this.prefixIndex = prefixIndex;
-      this.suffixIndex = prefixIndex + accessLogItemMetaWrapper.getPrefix().length();
+      this.suffixIndex = prefixIndex + accessLogItemMeta.getPrefix().length();
       this.tail = this.suffixIndex;
-      this.accessLogItemMetaWrapper = accessLogItemMetaWrapper;
+      this.accessLogItemMeta = accessLogItemMeta;
     }
 
     public String getPrefix() {
-      if (null == accessLogItemMetaWrapper) {
+      if (null == accessLogItemMeta) {
         return null;
       }
-      return accessLogItemMetaWrapper.getPrefix();
+      return accessLogItemMeta.getPrefix();
     }
 
     public String getSuffix() {
-      if (null == accessLogItemMetaWrapper) {
+      if (null == accessLogItemMeta) {
         return null;
       }
-      return accessLogItemMetaWrapper.getSuffix();
-    }
-  }
-
-  public static class AccessLogItemMetaWrapper {
-    private AccessLogItemMeta accessLogItemMeta;
-
-    private VertxRestAccessLogItemCreator vertxRestAccessLogItemCreator;
-
-    public AccessLogItemMetaWrapper(AccessLogItemMeta accessLogItemMeta,
-        VertxRestAccessLogItemCreator vertxRestAccessLogItemCreator) {
-      this.accessLogItemMeta = accessLogItemMeta;
-      this.vertxRestAccessLogItemCreator = vertxRestAccessLogItemCreator;
-    }
-
-    public AccessLogItemMeta getAccessLogItemMeta() {
-      return accessLogItemMeta;
-    }
-
-    public VertxRestAccessLogItemCreator getVertxRestAccessLogItemCreator() {
-      return vertxRestAccessLogItemCreator;
-    }
-
-    public String getPrefix() {
-      return accessLogItemMeta.getPrefix();
-    }
-
-    public String getSuffix() {
       return accessLogItemMeta.getSuffix();
     }
   }
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemCreator b/transports/transport-rest/transport-rest-vertx/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta
similarity index 95%
copy from transports/transport-rest/transport-rest-vertx/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemCreator
copy to transports/transport-rest/transport-rest-vertx/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta
index 92e596a..7a9f86c 100644
--- a/transports/transport-rest/transport-rest-vertx/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemCreator
+++ b/transports/transport-rest/transport-rest-vertx/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta
@@ -15,4 +15,4 @@
 # limitations under the License.
 #
 
-org.apache.servicecomb.transport.rest.vertx.accesslog.parser.impl.DefaultAccessLogItemCreator
\ No newline at end of file
+org.apache.servicecomb.transport.rest.vertx.accesslog.parser.impl.DefaultCompositeVertxRestAccessLogItemMeta
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UserDefinedAccessLogItem.java
similarity index 55%
copy from transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java
copy to transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UserDefinedAccessLogItem.java
index 131743e..a2559c6 100644
--- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UserDefinedAccessLogItem.java
@@ -15,43 +15,25 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.transport.rest.vertx.accesslog.parser;
+package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl;
 
+import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
 import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem;
 
+import io.vertx.ext.web.RoutingContext;
+
 /**
- * The meta data of {@linkplain AccessLogItem}.
+ * For access log extension test
  */
-public class AccessLogItemMeta {
-  private String prefix;
-
-  private String suffix;
-
-  /**
-   * Used for sorting {@linkplain AccessLogItemMeta}. Default value is 0.
-   * Smaller one has higher priority.
-   */
-  private int order;
-
-  public AccessLogItemMeta(String prefix, String suffix, int order) {
-    this.prefix = prefix;
-    this.suffix = suffix;
-    this.order = order;
-  }
-
-  public AccessLogItemMeta(String prefix, String suffix) {
-    this(prefix, suffix, 0);
-  }
-
-  public String getPrefix() {
-    return prefix;
-  }
+public class UserDefinedAccessLogItem implements AccessLogItem<RoutingContext> {
+  private String config;
 
-  public String getSuffix() {
-    return suffix;
+  public UserDefinedAccessLogItem(String config) {
+    this.config = config;
   }
 
-  public int getOrder() {
-    return order;
+  @Override
+  public String getFormattedItem(AccessLogParam<RoutingContext> accessLogParam) {
+    return "user-defined-" + config;
   }
 }
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UserDefinedAccessLogItemLowPriority.java
similarity index 54%
copy from transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java
copy to transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UserDefinedAccessLogItemLowPriority.java
index 131743e..eec7b29 100644
--- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UserDefinedAccessLogItemLowPriority.java
@@ -15,43 +15,21 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.transport.rest.vertx.accesslog.parser;
+package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl;
 
+import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
 import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem;
 
+import io.vertx.ext.web.RoutingContext;
+
 /**
- * The meta data of {@linkplain AccessLogItem}.
+ * For access log extension test, will be overridden by {@link RemoteHostItem}("%h"),
+ * and takes no effect.
  */
-public class AccessLogItemMeta {
-  private String prefix;
-
-  private String suffix;
-
-  /**
-   * Used for sorting {@linkplain AccessLogItemMeta}. Default value is 0.
-   * Smaller one has higher priority.
-   */
-  private int order;
-
-  public AccessLogItemMeta(String prefix, String suffix, int order) {
-    this.prefix = prefix;
-    this.suffix = suffix;
-    this.order = order;
-  }
-
-  public AccessLogItemMeta(String prefix, String suffix) {
-    this(prefix, suffix, 0);
-  }
-
-  public String getPrefix() {
-    return prefix;
-  }
-
-  public String getSuffix() {
-    return suffix;
-  }
+public class UserDefinedAccessLogItemLowPriority implements AccessLogItem<RoutingContext> {
 
-  public int getOrder() {
-    return order;
+  @Override
+  public String getFormattedItem(AccessLogParam<RoutingContext> accessLogParam) {
+    return "OverriddenItem";
   }
 }
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/impl/AccessLogHandlerTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/impl/AccessLogHandlerTest.java
new file mode 100644
index 0000000..ce96d49
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/impl/AccessLogHandlerTest.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.transport.rest.vertx.accesslog.impl;
+
+import java.util.HashSet;
+
+import javax.xml.ws.Holder;
+
+import org.apache.log4j.Level;
+import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.vertx.core.Handler;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.http.HttpServerResponse;
+import io.vertx.core.net.SocketAddress;
+import io.vertx.ext.web.Cookie;
+import io.vertx.ext.web.RoutingContext;
+import mockit.Mock;
+import mockit.MockUp;
+
+public class AccessLogHandlerTest {
+  private static final AccessLogHandler ACCESS_LOG_HANDLER = new AccessLogHandler(
+      "%h - - %s durationMillisecond=[%D] %{test-config}user-defined %{cookie-name}C");
+
+  private LogCollector logCollector;
+
+  @Before
+  public void setUp() {
+    logCollector = new LogCollector();
+    logCollector.setLogLevel("accesslog", Level.INFO);
+  }
+
+  @After
+  public void tearDown() {
+    logCollector.teardown();
+  }
+
+  @Test
+  public void testHandle() {
+    RoutingContext routingContext = Mockito.mock(RoutingContext.class);
+    HashSet<Cookie> cookies = new HashSet<>();
+    Cookie cookie = Mockito.mock(Cookie.class);
+    HttpServerResponse httpServerResponse = new MockUp<HttpServerResponse>() {
+      @Mock
+      public HttpServerResponse endHandler(Handler<Void> handler) {
+        handler.handle(null);
+        return null;
+      }
+
+      @Mock
+      public int getStatusCode() {
+        return 200;
+      }
+    }.getMockInstance();
+    HttpServerRequest httpServerRequest = Mockito.mock(HttpServerRequest.class);
+    SocketAddress socketAddress = Mockito.mock(SocketAddress.class);
+
+    Holder<Integer> counter = new Holder<>();
+    counter.value = 0;
+    new MockUp<System>() {
+      @Mock
+      long currentTimeMillis() {
+        if (counter.value < 1) {
+          ++counter.value;
+          return 1L;
+        }
+        return 123L;
+      }
+    };
+    cookies.add(cookie);
+    Mockito.when(cookie.getName()).thenReturn("cookie-name");
+    Mockito.when(cookie.getValue()).thenReturn("cookie-value");
+    Mockito.when(routingContext.cookies()).thenReturn(cookies);
+    Mockito.when(routingContext.response()).thenReturn(httpServerResponse);
+    Mockito.when(routingContext.request()).thenReturn(httpServerRequest);
+    Mockito.when(httpServerRequest.remoteAddress()).thenReturn(socketAddress);
+    Mockito.when(socketAddress.host()).thenReturn("localhost");
+
+    ACCESS_LOG_HANDLER.handle(routingContext);
+
+    Assert.assertEquals("localhost - - 200 durationMillisecond=[122] user-defined-test-config cookie-value",
+        logCollector.getEvents().get(0).getMessage());
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/TestCompositeExtendedAccessLogItemMeta.java
similarity index 57%
copy from transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java
copy to transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/TestCompositeExtendedAccessLogItemMeta.java
index 131743e..c226bab 100644
--- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/TestCompositeExtendedAccessLogItemMeta.java
@@ -15,43 +15,24 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.transport.rest.vertx.accesslog.parser;
+package org.apache.servicecomb.transport.rest.vertx.accesslog.parser.impl;
 
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem;
+import java.util.ArrayList;
+import java.util.List;
 
-/**
- * The meta data of {@linkplain AccessLogItem}.
- */
-public class AccessLogItemMeta {
-  private String prefix;
-
-  private String suffix;
-
-  /**
-   * Used for sorting {@linkplain AccessLogItemMeta}. Default value is 0.
-   * Smaller one has higher priority.
-   */
-  private int order;
-
-  public AccessLogItemMeta(String prefix, String suffix, int order) {
-    this.prefix = prefix;
-    this.suffix = suffix;
-    this.order = order;
-  }
-
-  public AccessLogItemMeta(String prefix, String suffix) {
-    this(prefix, suffix, 0);
-  }
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.UserDefinedAccessLogItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.CompositeVertxRestAccessLogItemMeta;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta;
 
-  public String getPrefix() {
-    return prefix;
-  }
+public class TestCompositeExtendedAccessLogItemMeta extends CompositeVertxRestAccessLogItemMeta {
+  private static final List<VertxRestAccessLogItemMeta> META_LIST = new ArrayList<>();
 
-  public String getSuffix() {
-    return suffix;
+  static {
+    META_LIST.add(new VertxRestAccessLogItemMeta("%{", "}user-defined", UserDefinedAccessLogItem::new));
   }
 
-  public int getOrder() {
-    return order;
+  @Override
+  public List<VertxRestAccessLogItemMeta> getAccessLogItemMetas() {
+    return META_LIST;
   }
 }
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/TestSingleExtendedAccessLogItemMeta.java
similarity index 56%
copy from transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java
copy to transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/TestSingleExtendedAccessLogItemMeta.java
index 131743e..9a2a1c7 100644
--- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/TestSingleExtendedAccessLogItemMeta.java
@@ -15,43 +15,13 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.transport.rest.vertx.accesslog.parser;
+package org.apache.servicecomb.transport.rest.vertx.accesslog.parser.impl;
 
-import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.UserDefinedAccessLogItemLowPriority;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta;
 
-/**
- * The meta data of {@linkplain AccessLogItem}.
- */
-public class AccessLogItemMeta {
-  private String prefix;
-
-  private String suffix;
-
-  /**
-   * Used for sorting {@linkplain AccessLogItemMeta}. Default value is 0.
-   * Smaller one has higher priority.
-   */
-  private int order;
-
-  public AccessLogItemMeta(String prefix, String suffix, int order) {
-    this.prefix = prefix;
-    this.suffix = suffix;
-    this.order = order;
-  }
-
-  public AccessLogItemMeta(String prefix, String suffix) {
-    this(prefix, suffix, 0);
-  }
-
-  public String getPrefix() {
-    return prefix;
-  }
-
-  public String getSuffix() {
-    return suffix;
-  }
-
-  public int getOrder() {
-    return order;
+public class TestSingleExtendedAccessLogItemMeta extends VertxRestAccessLogItemMeta {
+  public TestSingleExtendedAccessLogItemMeta() {
+    super("%h", null, config -> new UserDefinedAccessLogItemLowPriority(), 1);
   }
 }
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/VertxRestAccessLogPatternParserTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/VertxRestAccessLogPatternParserTest.java
index 57e9100..cf31d15 100644
--- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/VertxRestAccessLogPatternParserTest.java
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/VertxRestAccessLogPatternParserTest.java
@@ -25,7 +25,6 @@ import java.util.Comparator;
 import java.util.List;
 import java.util.Locale;
 import java.util.TimeZone;
-import java.util.function.Function;
 
 import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem;
 import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.CookieItem;
@@ -47,9 +46,8 @@ import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.Respon
 import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.TraceIdItem;
 import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.UrlPathItem;
 import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.UrlPathWithQueryItem;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogItemMeta;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemCreator;
-import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.impl.VertxRestAccessLogPatternParser.AccessLogItemMetaWrapper;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.CompositeVertxRestAccessLogItemMeta;
+import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -169,10 +167,7 @@ public class VertxRestAccessLogPatternParserTest {
     assertEquals(UrlPathWithQueryItem.class, result.get(11).getClass());
   }
 
-  Comparator<AccessLogItemMetaWrapper> comparator = VertxRestAccessLogPatternParser.accessLogItemMetaWrapperComparator;
-
-  Function<AccessLogItemMeta, AccessLogItemMetaWrapper> wrapper =
-      accessLogItemMeta -> new AccessLogItemMetaWrapper(accessLogItemMeta, null);
+  Comparator<VertxRestAccessLogItemMeta> comparator = VertxRestAccessLogPatternParser.accessLogItemMetaComparator;
 
   /**
    * one factor test
@@ -181,43 +176,43 @@ public class VertxRestAccessLogPatternParserTest {
   public void testCompareMetaSimple() {
     Assert.assertTrue(
         comparator.compare(
-            wrapper.apply(new AccessLogItemMeta(null, null, 0)),
-            wrapper.apply(new AccessLogItemMeta(null, null, 1))
+            new VertxRestAccessLogItemMeta(null, null, null, 0),
+            new VertxRestAccessLogItemMeta(null, null, null, 1)
         ) < 0
     );
     Assert.assertTrue(
         comparator.compare(
-            wrapper.apply(new AccessLogItemMeta(null, "}abc")),
-            wrapper.apply(new AccessLogItemMeta(null, null))
+            new VertxRestAccessLogItemMeta(null, "}abc", null, 0),
+            new VertxRestAccessLogItemMeta(null, null, null, 0)
         ) < 0
     );
     Assert.assertTrue(
         comparator.compare(
-            wrapper.apply(new AccessLogItemMeta(null, "}abc")),
-            wrapper.apply(new AccessLogItemMeta(null, "}de"))
+            new VertxRestAccessLogItemMeta(null, "}abc", null, 0),
+            new VertxRestAccessLogItemMeta(null, "}de", null, 0)
         ) < 0
     );
     Assert.assertTrue(
         comparator.compare(
-            wrapper.apply(new AccessLogItemMeta(null, "}abc")),
-            wrapper.apply(new AccessLogItemMeta(null, "}ab"))
+            new VertxRestAccessLogItemMeta(null, "}abc", null, 0),
+            new VertxRestAccessLogItemMeta(null, "}ab", null, 0)
         ) < 0
     );
     Assert.assertTrue(
         comparator.compare(
-            wrapper.apply(new AccessLogItemMeta("%abc", null)),
-            wrapper.apply(new AccessLogItemMeta("%de", null))
+            new VertxRestAccessLogItemMeta("%abc", null, null, 0),
+            new VertxRestAccessLogItemMeta("%de", null, null, 0)
         ) < 0
     );
     Assert.assertTrue(
         comparator.compare(
-            wrapper.apply(new AccessLogItemMeta("%abc", null)),
-            wrapper.apply(new AccessLogItemMeta("%ab", null))
+            new VertxRestAccessLogItemMeta("%abc", null, null, 0),
+            new VertxRestAccessLogItemMeta("%ab", null, null, 0)
         ) < 0
     );
     Assert.assertEquals(0, comparator.compare(
-        wrapper.apply(new AccessLogItemMeta("%abc", null)),
-        wrapper.apply(new AccessLogItemMeta("%abc", null))
+        new VertxRestAccessLogItemMeta("%abc", null, null, 0),
+        new VertxRestAccessLogItemMeta("%abc", null, null, 0)
     ));
   }
 
@@ -228,26 +223,26 @@ public class VertxRestAccessLogPatternParserTest {
   public void testCompareMetaComplex() {
     Assert.assertTrue(
         comparator.compare(
-            wrapper.apply(new AccessLogItemMeta("%bcd", "}ab", 0)),
-            wrapper.apply(new AccessLogItemMeta("%abc", "}abc", 0))
+            new VertxRestAccessLogItemMeta("%bcd", "}ab", null, 0),
+            new VertxRestAccessLogItemMeta("%abc", "}abc", null, 0)
         ) > 0
     );
     Assert.assertTrue(
         comparator.compare(
-            wrapper.apply(new AccessLogItemMeta("%abc", null, 0)),
-            wrapper.apply(new AccessLogItemMeta("%bcd", "}ab", 0))
+            new VertxRestAccessLogItemMeta("%abc", null, null, 0),
+            new VertxRestAccessLogItemMeta("%bcd", "}ab", null, 0)
         ) > 0
     );
     Assert.assertTrue(
         comparator.compare(
-            wrapper.apply(new AccessLogItemMeta("%bcd", "}abc")),
-            wrapper.apply(new AccessLogItemMeta("%abc", "}abc"))
+            new VertxRestAccessLogItemMeta("%bcd", "}abc", null, 0),
+            new VertxRestAccessLogItemMeta("%abc", "}abc", null, 0)
         ) > 0
     );
     Assert.assertTrue(
         comparator.compare(
-            wrapper.apply(new AccessLogItemMeta("%abc", "}abc", 1)),
-            wrapper.apply(new AccessLogItemMeta("%ab", "}ab", 0))
+            new VertxRestAccessLogItemMeta("%abc", "}abc", null, 1),
+            new VertxRestAccessLogItemMeta("%ab", "}ab", null, 0)
         ) > 0
     );
   }
@@ -271,69 +266,57 @@ public class VertxRestAccessLogPatternParserTest {
 
   @Test
   public void testExtendedVertxRestAccessLogItemCreator() {
-    final List<AccessLogItemMeta> metaList0 = new ArrayList<>();
-    metaList0.add(new AccessLogItemMeta("%{", "}abc"));
-    metaList0.add(new AccessLogItemMeta("%{", "}a"));
-    metaList0.add(new AccessLogItemMeta("%{", null));
-    metaList0.add(new AccessLogItemMeta("%_", null, -1));
-
-    final List<AccessLogItemMeta> metaList1 = new ArrayList<>();
-    metaList0.add(new AccessLogItemMeta("%a", "}abc"));
-    metaList0.add(new AccessLogItemMeta("%0", "}abc", 1));
-    metaList0.add(new AccessLogItemMeta("%m", null));
-
-    final VertxRestAccessLogItemCreator accessLogItemCreator0 = new VertxRestAccessLogItemCreator() {
-      @Override
-      public List<AccessLogItemMeta> getAccessLogItemMeta() {
-        return metaList0;
-      }
+    final List<VertxRestAccessLogItemMeta> metaList0 = new ArrayList<>();
+    metaList0.add(new VertxRestAccessLogItemMeta("%{", "}abc", null));
+    metaList0.add(new VertxRestAccessLogItemMeta("%{", "}a", null));
+    metaList0.add(new VertxRestAccessLogItemMeta("%_", null, null, -1));
 
-      @Override
-      public AccessLogItem<RoutingContext> createItem(AccessLogItemMeta accessLogItemMeta, String config) {
-        return null;
-      }
-    };
-
-    final VertxRestAccessLogItemCreator accessLogItemCreator1 = new VertxRestAccessLogItemCreator() {
-      @Override
-      public List<AccessLogItemMeta> getAccessLogItemMeta() {
-        return metaList1;
-      }
-
-      @Override
-      public AccessLogItem<RoutingContext> createItem(AccessLogItemMeta accessLogItemMeta, String config) {
-        return null;
-      }
-    };
+    final List<VertxRestAccessLogItemMeta> metaList1 = new ArrayList<>();
+    metaList0.add(new VertxRestAccessLogItemMeta("%a", "}abc", null));
+    metaList0.add(new VertxRestAccessLogItemMeta("%0", "}abc", null, 1));
+    metaList0.add(new VertxRestAccessLogItemMeta("%m", null, null));
 
     new MockUp<VertxRestAccessLogPatternParser>() {
       @Mock
-      List<VertxRestAccessLogItemCreator> loadVertxRestAccessLogItemCreators() {
-        List<VertxRestAccessLogItemCreator> creators = new ArrayList<>(1);
-        creators.add(accessLogItemCreator0);
-        creators.add(accessLogItemCreator1);
-        return creators;
+      List<VertxRestAccessLogItemMeta> loadVertxRestAccessLogItemMeta() {
+        List<VertxRestAccessLogItemMeta> metaList = new ArrayList<>(1);
+        CompositeVertxRestAccessLogItemMeta compositeMeta0 = new CompositeVertxRestAccessLogItemMeta() {
+          @Override
+          public List<VertxRestAccessLogItemMeta> getAccessLogItemMetas() {
+            return metaList0;
+          }
+        };
+        CompositeVertxRestAccessLogItemMeta compositeMeta1 = new CompositeVertxRestAccessLogItemMeta() {
+          @Override
+          public List<VertxRestAccessLogItemMeta> getAccessLogItemMetas() {
+            return metaList1;
+          }
+        };
+        metaList.add(compositeMeta0);
+        metaList.add(compositeMeta1);
+        metaList.add(new VertxRestAccessLogItemMeta("%{", null, null));
+        return metaList;
       }
     };
 
     VertxRestAccessLogPatternParser parser = new VertxRestAccessLogPatternParser();
 
-    List<AccessLogItemMetaWrapper> accessLogItemMetaWrappers =
-        Deencapsulation.getField(parser, "accessLogItemMetaWrappers");
+    List<VertxRestAccessLogItemMeta> accessLogItemMetaList =
+        Deencapsulation.getField(parser, "metaList");
 
-    assertEquals(7, accessLogItemMetaWrappers.size());
-    assertEquals("%_", accessLogItemMetaWrappers.get(0).getPrefix());
-    assertEquals("%a", accessLogItemMetaWrappers.get(1).getPrefix());
-    assertEquals("}abc", accessLogItemMetaWrappers.get(1).getSuffix());
-    assertEquals("%{", accessLogItemMetaWrappers.get(2).getPrefix());
-    assertEquals("}abc", accessLogItemMetaWrappers.get(2).getSuffix());
-    assertEquals("%{", accessLogItemMetaWrappers.get(3).getPrefix());
-    assertEquals("}a", accessLogItemMetaWrappers.get(3).getSuffix());
-    assertEquals("%m", accessLogItemMetaWrappers.get(4).getPrefix());
-    assertNull(accessLogItemMetaWrappers.get(4).getSuffix());
-    assertEquals("%{", accessLogItemMetaWrappers.get(5).getPrefix());
-    assertNull(accessLogItemMetaWrappers.get(5).getSuffix());
-    assertEquals("%0", accessLogItemMetaWrappers.get(6).getPrefix());
-    assertEquals("}abc", accessLogItemMetaWrappers.get(6).getSuffix());
+    assertEquals(7, accessLogItemMetaList.size());
+    assertEquals("%_", accessLogItemMetaList.get(0).getPrefix());
+    assertEquals("%a", accessLogItemMetaList.get(1).getPrefix());
+    assertEquals("}abc", accessLogItemMetaList.get(1).getSuffix());
+    assertEquals("%{", accessLogItemMetaList.get(2).getPrefix());
+    assertEquals("}abc", accessLogItemMetaList.get(2).getSuffix());
+    assertEquals("%{", accessLogItemMetaList.get(3).getPrefix());
+    assertEquals("}a", accessLogItemMetaList.get(3).getSuffix());
+    assertEquals("%m", accessLogItemMetaList.get(4).getPrefix());
+    assertNull(accessLogItemMetaList.get(4).getSuffix());
+    assertEquals("%{", accessLogItemMetaList.get(5).getPrefix());
+    assertNull(accessLogItemMetaList.get(5).getSuffix());
+    assertEquals("%0", accessLogItemMetaList.get(6).getPrefix());
+    assertEquals("}abc", accessLogItemMetaList.get(6).getSuffix());
   }
 }
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemCreator b/transports/transport-rest/transport-rest-vertx/src/test/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta
similarity index 85%
rename from transports/transport-rest/transport-rest-vertx/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemCreator
rename to transports/transport-rest/transport-rest-vertx/src/test/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta
index 92e596a..b539f7c 100644
--- a/transports/transport-rest/transport-rest-vertx/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemCreator
+++ b/transports/transport-rest/transport-rest-vertx/src/test/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta
@@ -15,4 +15,5 @@
 # limitations under the License.
 #
 
-org.apache.servicecomb.transport.rest.vertx.accesslog.parser.impl.DefaultAccessLogItemCreator
\ No newline at end of file
+org.apache.servicecomb.transport.rest.vertx.accesslog.parser.impl.TestSingleExtendedAccessLogItemMeta
+org.apache.servicecomb.transport.rest.vertx.accesslog.parser.impl.TestCompositeExtendedAccessLogItemMeta
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
wujimin@apache.org.