You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@servicecomb.apache.org by GitBox <gi...@apache.org> on 2017/12/22 03:37:19 UTC

[GitHub] WillemJiang closed pull request #441: [JAV-561] provide access log handler component

WillemJiang closed pull request #441: [JAV-561] provide access log handler component
URL: https://github.com/apache/incubator-servicecomb-java-chassis/pull/441
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/RestServerVerticle.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/RestServerVerticle.java
index cc887f78a..908439ff1 100644
--- a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/RestServerVerticle.java
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/RestServerVerticle.java
@@ -1,11 +1,12 @@
 /*
- * Copyright 2017 Huawei Technologies Co., Ltd
+ * 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
  *
- * Licensed 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
+ *     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,
@@ -29,6 +30,9 @@
 import io.servicecomb.foundation.ssl.SSLOption;
 import io.servicecomb.foundation.ssl.SSLOptionFactory;
 import io.servicecomb.foundation.vertx.VertxTLSBuilder;
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogConfiguration;
+import io.servicecomb.transport.rest.vertx.accesslog.impl.AccessLogHandler;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.impl.DefaultAccessLogPatternParser;
 import io.vertx.core.AbstractVerticle;
 import io.vertx.core.Context;
 import io.vertx.core.Future;
@@ -71,6 +75,7 @@ public void start(Future<Void> startFuture) throws Exception {
     }
 
     Router mainRouter = Router.router(vertx);
+    mountAccessLogHandler(mainRouter);
     initDispatcher(mainRouter);
 
     HttpServer httpServer = createHttpServer();
@@ -79,6 +84,17 @@ public void start(Future<Void> startFuture) throws Exception {
     startListen(httpServer, startFuture);
   }
 
+  private void mountAccessLogHandler(Router mainRouter) {
+    if (AccessLogConfiguration.INSTANCE.getAccessLogEnabled()) {
+      String pattern = AccessLogConfiguration.INSTANCE.getAccesslogPattern();
+      LOGGER.info("access log enabled, pattern = {}", pattern);
+      mainRouter.route()
+          .handler(new AccessLogHandler(
+              pattern,
+              new DefaultAccessLogPatternParser()));
+    }
+  }
+
   private void initDispatcher(Router mainRouter) {
     List<VertxHttpDispatcher> dispatchers = SPIServiceUtils.getSortedService(VertxHttpDispatcher.class);
     for (VertxHttpDispatcher dispatcher : dispatchers) {
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/AccessLogConfiguration.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/AccessLogConfiguration.java
new file mode 100644
index 000000000..dddbef123
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/AccessLogConfiguration.java
@@ -0,0 +1,50 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog;
+
+import com.netflix.config.DynamicPropertyFactory;
+
+public final class AccessLogConfiguration {
+  private static final String BASE = "servicecomb.accesslog.";
+
+  private static final String ACCESSLOG_ENABLED = BASE + "enabled";
+
+  private static final String ACCESSLOG_PATTERN = BASE + "pattern";
+
+  public static final AccessLogConfiguration INSTANCE = new AccessLogConfiguration();
+
+  private AccessLogConfiguration() {
+
+  }
+
+  public boolean getAccessLogEnabled() {
+    return getBooleanProperty(false, ACCESSLOG_ENABLED);
+  }
+
+  public String getAccesslogPattern() {
+    return getProperty("%h - - %t %r %s %B", ACCESSLOG_PATTERN);
+  }
+
+  private String getProperty(String defaultValue, String key) {
+    return DynamicPropertyFactory.getInstance().getStringProperty(key, defaultValue).get();
+  }
+
+  private boolean getBooleanProperty(boolean defaultValue, String key) {
+    return DynamicPropertyFactory.getInstance().getBooleanProperty(key, defaultValue).get();
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/AccessLogParam.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/AccessLogParam.java
new file mode 100644
index 000000000..8eb96f2d4
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/AccessLogParam.java
@@ -0,0 +1,65 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog;
+
+import io.vertx.ext.web.RoutingContext;
+
+public class AccessLogParam {
+  private RoutingContext routingContext;
+
+  private long startMillisecond;
+
+  private long endMillisecond;
+
+  public RoutingContext getRoutingContext() {
+    return routingContext;
+  }
+
+  public AccessLogParam setRoutingContext(RoutingContext routingContext) {
+    this.routingContext = routingContext;
+    return this;
+  }
+
+  public long getStartMillisecond() {
+    return startMillisecond;
+  }
+
+  public AccessLogParam setStartMillisecond(long startMillisecond) {
+    this.startMillisecond = startMillisecond;
+    return this;
+  }
+
+  public long getEndMillisecond() {
+    return endMillisecond;
+  }
+
+  public AccessLogParam setEndMillisecond(long endMillisecond) {
+    this.endMillisecond = endMillisecond;
+    return this;
+  }
+
+  @Override
+  public String toString() {
+    final StringBuilder sb = new StringBuilder("AccessLogParam{");
+    sb.append("routingContext=").append(routingContext);
+    sb.append(", startMillisecond=").append(startMillisecond);
+    sb.append(", endMillisecond=").append(endMillisecond);
+    sb.append('}');
+    return sb.toString();
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/README.md b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/README.md
new file mode 100644
index 000000000..d62c61b2e
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/README.md
@@ -0,0 +1,61 @@
+# transport-rest-vertx Access Log
+
+## Enable access log printing
+
+To enable access log printing, you can config access log in microservice.yaml like below:
+```yaml
+servicecomb:
+  accesslog:
+    enabled: true
+    pattern: "%h - - %t %r %s %B"
+```
+
+***Access Log Configurations in microservice.yaml***
+
+| Config Item | Range of Value | Default Value | Meaning |
+| :---------- | :------------- | :------------ | :------ |
+| servicecomb.accesslog.enabled | true/false | false | print access log if true |
+| servicecomb.accesslog.pattern | a string field representing log pattern | "%h - - %t %r %s %B" | see details of ***Currently Supported Elements*** below |
+
+> ***Caution:***
+> - all of the configuration items above can be omitted, in this case, default value will take effect.
+
+## Supported log elements
+
+***Currently Supported Elements***
+
+| Element | Apache | W3C | Comment |
+| ----|------|------------| --------|
+| Method | %m  | cs-method | |
+| Status | %s  | sc-status | |
+| Duration s | %T  | - |  |
+| Duration ms | %D  | - | |
+| Remote Host | %h  | - |  |
+| Local Host | %v  | - |  |
+| Local port | %p  | - |  |
+| Bytes Written v1 | %B | - | Zero Bytes written as 0 |
+| Bytes Written v2 | %b | - | Zero Bytes written as - |
+| First line of request | %r  | - | |
+| URI path only | %U | cs-uri-stem | |
+| Query only | %q | cs-uri-query | |
+| URI path incl query | - | cs-uri | |
+| Version / Protocol | %H | - | |
+| Datetime Apache | %t | - | Logs by default the request timestamp using format 'EEE, dd MMM yyyy HH:mm:ss zzz', Locale English and Timezone GMT  |
+| Datetime Apache Configurable v1 | %{PATTERN}t | - | Specify the format pattern, by default it is used Locale English and Timezone GMT |
+| Datetime Apache Configurable v2 | %{PATTERN\|TIMEZONE\|LOCALE}t | - | Specify format pattern, timezone and locale |
+| Incoming Headers | %{IDENTIFIER}i  | - | If not found - will be logged |
+| Outgoing Response Headers | %{IDENTIFIER}o  | - | If not found - will be logged |
+| Cookie | %{IDENTIFIER}c  | - | If not found - will be logged |
+
+## Access log file settings
+
+Access log will be written in a separate log file named `access.log` located in the same directory with common logs.
+
+Default access log printer is based on Log4j, users can override access log file configuration in their `log4j.properties` file.
+
+***Common access log file configuration items***
+
+| Configuration Item | Default Value | Meaning |
+| :----------------- | :------------ | :------ |
+| paas.logs.accesslog.dir | ${paas.logs.dir} | access log output directory |
+| paas.logs.accesslog.file | access.log | access log file name |
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/AccessLogElement.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/AccessLogElement.java
new file mode 100644
index 000000000..a4cadb674
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/AccessLogElement.java
@@ -0,0 +1,33 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+
+/**
+ * element should be printed into access log.
+ */
+public interface AccessLogElement {
+  /**
+   * find out specified content from {@link AccessLogParam}, format the content and return it.
+   *
+   * @param accessLogParam
+   * @return
+   */
+  String getFormattedElement(AccessLogParam accessLogParam);
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/BytesWrittenV1Element.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/BytesWrittenV1Element.java
new file mode 100644
index 000000000..ef849118e
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/BytesWrittenV1Element.java
@@ -0,0 +1,42 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.vertx.core.http.HttpServerResponse;
+
+/**
+ * Zero bytes written as 0
+ */
+public class BytesWrittenV1Element implements AccessLogElement {
+
+  public static final String ZERO_BYTES = "0";
+
+  @Override
+  public String getFormattedElement(AccessLogParam accessLogParam) {
+    HttpServerResponse response = accessLogParam.getRoutingContext().response();
+    if (null == response) {
+      return ZERO_BYTES;
+    }
+
+    long bytesWritten = response.bytesWritten();
+
+    return String.valueOf(bytesWritten);
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/BytesWrittenV2Element.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/BytesWrittenV2Element.java
new file mode 100644
index 000000000..f220bc958
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/BytesWrittenV2Element.java
@@ -0,0 +1,45 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.vertx.core.http.HttpServerResponse;
+
+/**
+ * Zero bytes written as -
+ */
+public class BytesWrittenV2Element implements AccessLogElement {
+
+  public static final String ZERO_BYTES = "-";
+
+  @Override
+  public String getFormattedElement(AccessLogParam accessLogParam) {
+    HttpServerResponse response = accessLogParam.getRoutingContext().response();
+    if (null == response) {
+      return ZERO_BYTES;
+    }
+
+    long bytesWritten = response.bytesWritten();
+    if (0 == bytesWritten) {
+      return ZERO_BYTES;
+    } else {
+      return String.valueOf(bytesWritten);
+    }
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/CookieElement.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/CookieElement.java
new file mode 100644
index 000000000..43bfeb4d5
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/CookieElement.java
@@ -0,0 +1,60 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import java.util.Set;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.vertx.ext.web.Cookie;
+
+public class CookieElement implements AccessLogElement {
+
+  public static final String RESULT_NOT_FOUND = "-";
+
+  private final String identifier;
+
+  public CookieElement(String identifier) {
+    this.identifier = identifier;
+  }
+
+  @Override
+  public String getFormattedElement(AccessLogParam accessLogParam) {
+    Set<Cookie> cookieSet = accessLogParam.getRoutingContext().cookies();
+    if (null == cookieSet) {
+      return RESULT_NOT_FOUND;
+    }
+
+    String result = null;
+    for (Cookie cookie : cookieSet) {
+      if (identifier.equals(cookie.getName())) {
+        result = cookie.getValue();
+      }
+    }
+
+    if (null == result) {
+      return RESULT_NOT_FOUND;
+    }
+
+    return result;
+  }
+
+  public String getIdentifier() {
+    return identifier;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/DatetimeConfigurableElement.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/DatetimeConfigurableElement.java
new file mode 100644
index 000000000..442b2cfd8
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/DatetimeConfigurableElement.java
@@ -0,0 +1,114 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.springframework.util.StringUtils;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+
+/**
+ * Configurable datetime element.
+ */
+public class DatetimeConfigurableElement implements AccessLogElement {
+
+  public static final String DEFAULT_DATETIME_PATTERN = "EEE, dd MMM yyyy HH:mm:ss zzz";
+
+  public static final Locale DEFAULT_LOCALE = Locale.US;
+
+  private final ThreadLocal<SimpleDateFormat> datetimeFormatHolder = new ThreadLocal<>();
+
+  private String pattern;
+
+  private TimeZone timezone;
+
+  private Locale locale;
+
+  /**
+   * all config is set to default value.
+   */
+  public DatetimeConfigurableElement() {
+    this(DEFAULT_DATETIME_PATTERN);
+  }
+
+  /**
+   * the configurations not specified will get a default value.
+   * @param config the format of config is "PATTERN|TIMEZONE|LOCALE" or "PATTERN". It depends on whether the config contains the separator "|"
+   */
+  public DatetimeConfigurableElement(String config) {
+    String[] configArr = null;
+    if (config.contains("|")) {
+      configArr = splitConfig(config);
+    } else {
+      // if there is no seperator "|", regard config as pattern.
+      configArr = new String[3];
+      configArr[0] = config;
+    }
+    if (3 != configArr.length) {
+      throw new IllegalArgumentException(
+          "wrong format of configuration, \"PATTERN|TIMEZONE|LOCALE\" is expected, but actually is \"" + config + "\"");
+    }
+
+    setConfigruations(configArr);
+  }
+
+  private String[] splitConfig(String config) {
+    return config.split("\\|{1}?", -1);
+  }
+
+  private void setConfigruations(String[] configArr) {
+    this.pattern = StringUtils.isEmpty(configArr[0]) ? DEFAULT_DATETIME_PATTERN : configArr[0];
+    this.timezone = StringUtils.isEmpty(configArr[1]) ? TimeZone.getDefault() : TimeZone.getTimeZone(configArr[1]);
+    this.locale = StringUtils.isEmpty(configArr[2]) ? DEFAULT_LOCALE : Locale.forLanguageTag(configArr[2]);
+  }
+
+  @Override
+  public String getFormattedElement(AccessLogParam accessLogParam) {
+    SimpleDateFormat dateFormat = getDatetimeFormat();
+    return dateFormat.format(new Date(accessLogParam.getStartMillisecond()));
+  }
+
+  private SimpleDateFormat getDatetimeFormat() {
+    SimpleDateFormat dateFormat = datetimeFormatHolder.get();
+    if (null == dateFormat) {
+      dateFormat = new SimpleDateFormat(pattern, locale);
+      dateFormat.setTimeZone(timezone);
+
+      datetimeFormatHolder.set(dateFormat);
+    }
+
+    return dateFormat;
+  }
+
+  public String getPattern() {
+    return pattern;
+  }
+
+  public TimeZone getTimezone() {
+    return timezone;
+  }
+
+  public Locale getLocale() {
+    return locale;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationMillisecondElement.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationMillisecondElement.java
new file mode 100644
index 000000000..0a2f882ac
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationMillisecondElement.java
@@ -0,0 +1,28 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+
+public class DurationMillisecondElement implements AccessLogElement {
+  @Override
+  public String getFormattedElement(AccessLogParam accessLogParam) {
+    return String.valueOf(accessLogParam.getEndMillisecond() - accessLogParam.getStartMillisecond());
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationSecondElement.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationSecondElement.java
new file mode 100644
index 000000000..e2b287423
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationSecondElement.java
@@ -0,0 +1,28 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+
+public class DurationSecondElement implements AccessLogElement {
+  @Override
+  public String getFormattedElement(AccessLogParam accessLogParam) {
+    return String.valueOf((accessLogParam.getEndMillisecond() - accessLogParam.getStartMillisecond()) / 1000);
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/FirstLineOfRequestElement.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/FirstLineOfRequestElement.java
new file mode 100644
index 000000000..929e4fe14
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/FirstLineOfRequestElement.java
@@ -0,0 +1,43 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+
+public class FirstLineOfRequestElement implements AccessLogElement {
+  private static final MethodElement METHOD_ELEMENT = new MethodElement();
+
+  private static final UriPathOnlyElement URI_PATH_ONLY_ELEMENT = new UriPathOnlyElement();
+
+  private static final VersionOrProtocolElement VERSION_OR_PROTOCOL_ELEMENT = new VersionOrProtocolElement();
+
+  @Override
+  public String getFormattedElement(AccessLogParam accessLogParam) {
+    StringBuilder result = new StringBuilder(64)
+        .append("\"")
+        .append(METHOD_ELEMENT.getFormattedElement(accessLogParam))
+        .append(" ")
+        .append(URI_PATH_ONLY_ELEMENT.getFormattedElement(accessLogParam))
+        .append(" ")
+        .append(VERSION_OR_PROTOCOL_ELEMENT.getFormattedElement(accessLogParam))
+        .append("\"");
+
+    return result.toString();
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalHostElement.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalHostElement.java
new file mode 100644
index 000000000..6ce423e33
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalHostElement.java
@@ -0,0 +1,49 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import org.springframework.util.StringUtils;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.net.SocketAddress;
+
+public class LocalHostElement implements AccessLogElement {
+
+  public static final String EMPTY_RESULT = "-";
+
+  @Override
+  public String getFormattedElement(AccessLogParam accessLogParam) {
+    HttpServerRequest request = accessLogParam.getRoutingContext().request();
+    if (null == request) {
+      return EMPTY_RESULT;
+    }
+
+    SocketAddress localAddress = request.localAddress();
+    if (null == localAddress) {
+      return EMPTY_RESULT;
+    }
+
+    String localHost = localAddress.host();
+    if (StringUtils.isEmpty(localHost)) {
+      return EMPTY_RESULT;
+    }
+    return localHost;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalPortElement.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalPortElement.java
new file mode 100644
index 000000000..75a6696cb
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalPortElement.java
@@ -0,0 +1,43 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.net.SocketAddress;
+
+public class LocalPortElement implements AccessLogElement {
+
+  public static final String EMPTY_RESULT = "-";
+
+  @Override
+  public String getFormattedElement(AccessLogParam accessLogParam) {
+    HttpServerRequest request = accessLogParam.getRoutingContext().request();
+    if (null == request) {
+      return EMPTY_RESULT;
+    }
+
+    SocketAddress localAddress = request.localAddress();
+    if (null == localAddress) {
+      return EMPTY_RESULT;
+    }
+
+    return String.valueOf(localAddress.port());
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/MethodElement.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/MethodElement.java
new file mode 100644
index 000000000..af95bf2b5
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/MethodElement.java
@@ -0,0 +1,45 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.vertx.core.http.HttpMethod;
+import io.vertx.core.http.HttpServerRequest;
+
+/**
+ * HTTP method
+ */
+public class MethodElement implements AccessLogElement {
+
+  public static final String EMPTY_RESULT = "-";
+
+  @Override
+  public String getFormattedElement(AccessLogParam accessLogParam) {
+    HttpServerRequest request = accessLogParam.getRoutingContext().request();
+    if (null == request) {
+      return EMPTY_RESULT;
+    }
+
+    HttpMethod method = request.method();
+    if (null == method) {
+      return EMPTY_RESULT;
+    }
+    return method.toString();
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/PlainTextElement.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/PlainTextElement.java
new file mode 100644
index 000000000..87a7dba91
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/PlainTextElement.java
@@ -0,0 +1,37 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+
+/**
+ * Print content as it is.
+ */
+public class PlainTextElement implements AccessLogElement {
+  private final String content;
+
+  public PlainTextElement(String content) {
+    this.content = content;
+  }
+
+  @Override
+  public String getFormattedElement(AccessLogParam accessLogParam) {
+    return content;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/QueryOnlyElement.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/QueryOnlyElement.java
new file mode 100644
index 000000000..4e700f8d0
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/QueryOnlyElement.java
@@ -0,0 +1,43 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import org.springframework.util.StringUtils;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.vertx.core.http.HttpServerRequest;
+
+public class QueryOnlyElement implements AccessLogElement {
+
+  public static final String EMPTY_RESULT = "-";
+
+  @Override
+  public String getFormattedElement(AccessLogParam accessLogParam) {
+    HttpServerRequest request = accessLogParam.getRoutingContext().request();
+    if (null == request) {
+      return EMPTY_RESULT;
+    }
+
+    String query = request.query();
+    if (StringUtils.isEmpty(query)) {
+      return EMPTY_RESULT;
+    }
+    return query;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/RemoteHostElement.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/RemoteHostElement.java
new file mode 100644
index 000000000..4f260ce4e
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/RemoteHostElement.java
@@ -0,0 +1,49 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import org.springframework.util.StringUtils;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.net.SocketAddress;
+
+public class RemoteHostElement implements AccessLogElement {
+
+  public static final String EMPTY_RESULT = "-";
+
+  @Override
+  public String getFormattedElement(AccessLogParam accessLogParam) {
+    HttpServerRequest request = accessLogParam.getRoutingContext().request();
+    if (null == request) {
+      return EMPTY_RESULT;
+    }
+
+    SocketAddress remoteAddress = request.remoteAddress();
+    if (null == remoteAddress) {
+      return EMPTY_RESULT;
+    }
+
+    String remoteHost = remoteAddress.host();
+    if (StringUtils.isEmpty(remoteHost)) {
+      return EMPTY_RESULT;
+    }
+    return remoteHost;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/RequestHeaderElement.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/RequestHeaderElement.java
new file mode 100644
index 000000000..0c09e5388
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/RequestHeaderElement.java
@@ -0,0 +1,53 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.vertx.core.MultiMap;
+
+public class RequestHeaderElement implements AccessLogElement {
+
+  public static final String RESULT_NOT_FOUND = "-";
+
+  private final String identifier;
+
+  public RequestHeaderElement(String identifier) {
+    this.identifier = identifier;
+  }
+
+  @Override
+  public String getFormattedElement(AccessLogParam accessLogParam) {
+    MultiMap headers = accessLogParam.getRoutingContext().request().headers();
+    if (null == headers) {
+      return "-";
+    }
+
+    String result = headers.get(identifier);
+
+    if (null == result) {
+      return RESULT_NOT_FOUND;
+    }
+
+    return result;
+  }
+
+  public String getIdentifier() {
+    return identifier;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/ResponseHeaderElement.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/ResponseHeaderElement.java
new file mode 100644
index 000000000..17df10cc7
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/ResponseHeaderElement.java
@@ -0,0 +1,58 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.vertx.core.MultiMap;
+import io.vertx.core.http.HttpServerResponse;
+
+public class ResponseHeaderElement implements AccessLogElement {
+
+  public static final String RESULT_NOT_FOUND = "-";
+
+  private final String identifier;
+
+  public ResponseHeaderElement(String identifier) {
+    this.identifier = identifier;
+  }
+
+  @Override
+  public String getFormattedElement(AccessLogParam accessLogParam) {
+    HttpServerResponse response = accessLogParam.getRoutingContext().response();
+    if (null == response) {
+      return RESULT_NOT_FOUND;
+    }
+
+    MultiMap headers = response.headers();
+    if (null == headers) {
+      return RESULT_NOT_FOUND;
+    }
+
+    String result = headers.get(identifier);
+    if (null == result) {
+      return RESULT_NOT_FOUND;
+    }
+
+    return result;
+  }
+
+  public String getIdentifier() {
+    return identifier;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/StatusElement.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/StatusElement.java
new file mode 100644
index 000000000..63927f1da
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/StatusElement.java
@@ -0,0 +1,37 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.vertx.core.http.HttpServerResponse;
+
+public class StatusElement implements AccessLogElement {
+
+  public static final String EMPTY_RESULT = "-";
+
+  @Override
+  public String getFormattedElement(AccessLogParam accessLogParam) {
+    HttpServerResponse response = accessLogParam.getRoutingContext().response();
+    if (null == response) {
+      return EMPTY_RESULT;
+    }
+
+    return String.valueOf(response.getStatusCode());
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/UriPathIncludeQueryElement.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/UriPathIncludeQueryElement.java
new file mode 100644
index 000000000..9ab7713fb
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/UriPathIncludeQueryElement.java
@@ -0,0 +1,44 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import org.springframework.util.StringUtils;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.vertx.core.http.HttpServerRequest;
+
+public class UriPathIncludeQueryElement implements AccessLogElement {
+
+  public static final String EMPTY_RESULT = "-";
+
+  @Override
+  public String getFormattedElement(AccessLogParam accessLogParam) {
+    HttpServerRequest request = accessLogParam.getRoutingContext().request();
+    if (null == request) {
+      return EMPTY_RESULT;
+    }
+
+    String uri = request.uri();
+    if (StringUtils.isEmpty(uri)) {
+      return EMPTY_RESULT;
+    }
+
+    return uri;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/UriPathOnlyElement.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/UriPathOnlyElement.java
new file mode 100644
index 000000000..aadba4071
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/UriPathOnlyElement.java
@@ -0,0 +1,43 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.vertx.core.http.HttpServerRequest;
+
+public class UriPathOnlyElement implements AccessLogElement {
+
+  public static final String EMPTY_RESULT = "-";
+
+  @Override
+  public String getFormattedElement(AccessLogParam accessLogParam) {
+    HttpServerRequest request = accessLogParam.getRoutingContext().request();
+
+    if (null == request) {
+      return EMPTY_RESULT;
+    }
+
+    String uri = request.path();
+    if (null == uri) {
+      return EMPTY_RESULT;
+    }
+
+    return uri;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/VersionOrProtocolElement.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/VersionOrProtocolElement.java
new file mode 100644
index 000000000..59ecec0a3
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/VersionOrProtocolElement.java
@@ -0,0 +1,53 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.http.HttpVersion;
+
+public class VersionOrProtocolElement implements AccessLogElement {
+
+  public static final String EMPTY_RESULT = "-";
+
+  @Override
+  public String getFormattedElement(AccessLogParam accessLogParam) {
+    HttpServerRequest request = accessLogParam.getRoutingContext().request();
+    if (null == request) {
+      return EMPTY_RESULT;
+    }
+    if (null == request.version()) {
+      return EMPTY_RESULT;
+    }
+    return getStringVersion(request.version());
+  }
+
+  private String getStringVersion(HttpVersion version) {
+    switch (version) {
+      case HTTP_2:
+        return "HTTP/2.0";
+      case HTTP_1_0:
+        return "HTTP/1.0";
+      case HTTP_1_1:
+        return "HTTP/1.1";
+      default:
+        return EMPTY_RESULT;
+    }
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/impl/AccessLogHandler.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/impl/AccessLogHandler.java
new file mode 100644
index 000000000..7fdd47089
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/impl/AccessLogHandler.java
@@ -0,0 +1,71 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.impl;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogPatternParser;
+import io.vertx.core.Handler;
+import io.vertx.ext.web.RoutingContext;
+
+public class AccessLogHandler implements Handler<RoutingContext> {
+  private static Logger LOGGER = LoggerFactory.getLogger("accesslog");
+
+  private static AccessLogElement[] accessLogElements;
+
+  public AccessLogHandler(String rawPattern, AccessLogPatternParser accessLogPatternParser) {
+    List<AccessLogElementExtraction> extractionList = accessLogPatternParser.parsePattern(rawPattern);
+
+    accessLogElements = new AccessLogElement[extractionList.size()];
+    for (int i = 0; i < extractionList.size(); ++i) {
+      accessLogElements[i] = extractionList.get(i).getAccessLogElement();
+    }
+  }
+
+  @Override
+  public void handle(RoutingContext context) {
+    AccessLogParam accessLogParam = new AccessLogParam().setStartMillisecond(System.currentTimeMillis())
+        .setRoutingContext(context);
+
+    context.addBodyEndHandler(v -> log(accessLogParam));
+
+    context.next();
+  }
+
+  private void log(AccessLogParam accessLogParam) {
+    StringBuilder log = new StringBuilder(128);
+    accessLogParam.setEndMillisecond(System.currentTimeMillis());
+
+    AccessLogElement[] accessLogElements = getAccessLogElements();
+    for (int i = 0; i < accessLogElements.length; ++i) {
+      log.append(accessLogElements[i].getFormattedElement(accessLogParam));
+    }
+
+    LOGGER.info(log.toString());
+  }
+
+  private AccessLogElement[] getAccessLogElements() {
+    return accessLogElements;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogElementExtraction.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogElementExtraction.java
new file mode 100644
index 000000000..f71a57572
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogElementExtraction.java
@@ -0,0 +1,77 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+
+public class AccessLogElementExtraction {
+  private int start;
+
+  private int end;
+
+  private AccessLogElement accessLogElement;
+
+  public AccessLogElementExtraction() {
+
+  }
+
+  public AccessLogElementExtraction(int start, int end,
+      AccessLogElement accessLogElement) {
+    this.start = start;
+    this.end = end;
+    this.accessLogElement = accessLogElement;
+  }
+
+  public int getStart() {
+    return start;
+  }
+
+  public AccessLogElementExtraction setStart(int start) {
+    this.start = start;
+    return this;
+  }
+
+  public int getEnd() {
+    return end;
+  }
+
+  public AccessLogElementExtraction setEnd(int end) {
+    this.end = end;
+    return this;
+  }
+
+  public AccessLogElement getAccessLogElement() {
+    return accessLogElement;
+  }
+
+  public AccessLogElementExtraction setAccessLogElement(
+      AccessLogElement accessLogElement) {
+    this.accessLogElement = accessLogElement;
+    return this;
+  }
+
+  @Override
+  public String toString() {
+    final StringBuilder sb = new StringBuilder("AccessLogElementExtraction{");
+    sb.append("start=").append(start);
+    sb.append(", end=").append(end);
+    sb.append(", accessLogElement=").append(accessLogElement);
+    sb.append('}');
+    return sb.toString();
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogPatternParser.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogPatternParser.java
new file mode 100644
index 000000000..d3c68d3cc
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogPatternParser.java
@@ -0,0 +1,24 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser;
+
+import java.util.List;
+
+public interface AccessLogPatternParser {
+  List<AccessLogElementExtraction> parsePattern(String rawPattern);
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/impl/DefaultAccessLogPatternParser.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/impl/DefaultAccessLogPatternParser.java
new file mode 100644
index 000000000..9a7f7a1cf
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/impl/DefaultAccessLogPatternParser.java
@@ -0,0 +1,127 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.impl;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.PlainTextElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogPatternParser;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.AccessLogElementMatcher;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl.BytesWrittenV1Matcher;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl.BytesWrittenV2Matcher;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl.CookieElementMatcher;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl.DatetimeConfigurableMatcher;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl.DatetimeMatcher;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl.DurationMillisecondMatcher;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl.DurationSecondMatcher;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl.FirstLineOfRequestMatcher;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl.LocalHostMatcher;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl.LocalPortMatcher;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl.MethodMatcher;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl.QueryOnlyMatcher;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl.RemoteHostMatcher;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl.RequestHeaderElementMatcher;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl.ResponseHeaderElementMatcher;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl.StatusMatcher;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl.UriPathIncludeQueryMatcher;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl.UriPathOnlyMatcher;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl.VersionOrProtocolMatcher;
+
+public class DefaultAccessLogPatternParser implements AccessLogPatternParser {
+  private static final List<AccessLogElementMatcher> MATCHER_LIST = Arrays.asList(
+      new RequestHeaderElementMatcher(),
+      new DatetimeConfigurableMatcher(),
+      new CookieElementMatcher(),
+      new ResponseHeaderElementMatcher(),
+      new DurationSecondMatcher(),
+      new VersionOrProtocolMatcher(),
+      new BytesWrittenV1Matcher(),
+      new BytesWrittenV2Matcher(),
+      new DurationMillisecondMatcher(),
+      new LocalPortMatcher(),
+      new LocalHostMatcher(),
+      new UriPathIncludeQueryMatcher(),
+      new FirstLineOfRequestMatcher(),
+      new DatetimeMatcher(),
+      new RemoteHostMatcher(),
+      new MethodMatcher(),
+      new QueryOnlyMatcher(),
+      new UriPathOnlyMatcher(),
+      new StatusMatcher()
+  );
+
+  public static final Comparator<AccessLogElementExtraction> ACCESS_LOG_ELEMENT_EXTRACTION_COMPARATOR = Comparator
+      .comparingInt(AccessLogElementExtraction::getStart);
+
+  @Override
+  public List<AccessLogElementExtraction> parsePattern(String rawPattern) {
+    List<AccessLogElementExtraction> extractionList = new ArrayList<>();
+    for (AccessLogElementMatcher matcher : MATCHER_LIST) {
+      List<AccessLogElementExtraction> extractions = matcher.extractElementPlaceholder(rawPattern);
+      if (null != extractions) {
+        extractionList.addAll(extractions);
+      }
+    }
+
+    extractionList.sort(ACCESS_LOG_ELEMENT_EXTRACTION_COMPARATOR);
+    checkExtractionList(extractionList);
+    fillInPlainTextElement(rawPattern, extractionList);
+
+    return extractionList;
+  }
+
+  private void checkExtractionList(List<AccessLogElementExtraction> extractionList) {
+    int preEnd = -1;
+    for (AccessLogElementExtraction extraction : extractionList) {
+      if (preEnd > extraction.getStart()) {
+        throw new IllegalArgumentException("access log pattern contains illegal placeholder, please check it.");
+      }
+
+      preEnd = extraction.getEnd();
+    }
+  }
+
+  /**
+   * The content not matched in rawPattern will be printed as it is, so should be converted to {@link PlainTextElement}
+   * @param rawPattern
+   * @param extractionList
+   */
+  private void fillInPlainTextElement(String rawPattern, List<AccessLogElementExtraction> extractionList) {
+    int cursor = 0;
+    List<AccessLogElementExtraction> plainTextExtractionList = new ArrayList<>();
+    for (AccessLogElementExtraction extraction : extractionList) {
+      if (cursor < extraction.getStart()) {
+        plainTextExtractionList.add(
+            new AccessLogElementExtraction()
+                .setStart(cursor)
+                .setEnd(extraction.getStart())
+                .setAccessLogElement(
+                    new PlainTextElement(rawPattern.substring(cursor, extraction.getStart()))
+                ));
+      }
+      cursor = extraction.getEnd();
+    }
+
+    extractionList.addAll(plainTextExtractionList);
+    extractionList.sort(ACCESS_LOG_ELEMENT_EXTRACTION_COMPARATOR);
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/AccessLogElementMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/AccessLogElementMatcher.java
new file mode 100644
index 000000000..ed5fa887f
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/AccessLogElementMatcher.java
@@ -0,0 +1,35 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher;
+
+import java.util.List;
+
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+
+/**
+ * match placeholder in raw pattern
+ */
+public interface AccessLogElementMatcher {
+  /**
+   * extract placeholders from rawPattern that match this element.
+   *
+   * @param rawPattern
+   * @return
+   */
+  List<AccessLogElementExtraction> extractElementPlaceholder(String rawPattern);
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/BytesWrittenV1Matcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/BytesWrittenV1Matcher.java
new file mode 100644
index 000000000..781c378e8
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/BytesWrittenV1Matcher.java
@@ -0,0 +1,36 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.BytesWrittenV1Element;
+
+public class BytesWrittenV1Matcher extends SinglePatternImmutableElementMatcher {
+
+  public static final BytesWrittenV1Element ELEMENT = new BytesWrittenV1Element();
+
+  @Override
+  protected String getPlaceholderPattern() {
+    return "%B";
+  }
+
+  @Override
+  protected AccessLogElement getAccessLogElement() {
+    return ELEMENT;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/BytesWrittenV2Matcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/BytesWrittenV2Matcher.java
new file mode 100644
index 000000000..b25181765
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/BytesWrittenV2Matcher.java
@@ -0,0 +1,36 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.BytesWrittenV2Element;
+
+public class BytesWrittenV2Matcher extends SinglePatternImmutableElementMatcher {
+
+  public static final BytesWrittenV2Element ELEMENT = new BytesWrittenV2Element();
+
+  @Override
+  protected String getPlaceholderPattern() {
+    return "%b";
+  }
+
+  @Override
+  protected AccessLogElement getAccessLogElement() {
+    return ELEMENT;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/ConfigurableAccessLogElementMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/ConfigurableAccessLogElementMatcher.java
new file mode 100644
index 000000000..0f18af9dd
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/ConfigurableAccessLogElementMatcher.java
@@ -0,0 +1,73 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.AccessLogElementMatcher;
+
+public abstract class ConfigurableAccessLogElementMatcher implements AccessLogElementMatcher {
+
+  @Override
+  public List<AccessLogElementExtraction> extractElementPlaceholder(String rawPattern) {
+    List<AccessLogElementExtraction> extractionList = new ArrayList<>();
+    int begin = -1;
+    int end = 0;
+    int cursor = 0;
+
+    while (true) {
+      end = rawPattern.indexOf(getPlaceholderSuffix(), cursor);
+      if (end < 0) {
+        break;
+      }
+      begin = locateBeginIndex(rawPattern, end, cursor);
+      if (begin < 0) {
+        break;
+      }
+
+      String identifier = rawPattern.substring(begin + getPlaceholderSuffix().length(), end);
+      extractionList.add(new AccessLogElementExtraction(begin, end + getPlaceholderSuffix().length(),
+          getAccessLogElement(identifier)));
+
+      cursor = end + 1;
+    }
+    return extractionList;
+  }
+
+  private int locateBeginIndex(String rawPattern, int end, int cursor) {
+    int preBegin = rawPattern.indexOf(getPlaceholderPrefix(), cursor);
+    int begin = rawPattern.indexOf(getPlaceholderPrefix(), preBegin + 1);
+    while (begin >= 0 && begin < end) {
+      if (begin < end) {
+        preBegin = begin;
+      }
+      begin = rawPattern.indexOf(getPlaceholderPrefix(), preBegin + 1);
+    }
+    return preBegin;
+  }
+
+
+  protected abstract String getPlaceholderSuffix();
+
+  protected abstract String getPlaceholderPrefix();
+
+  protected abstract AccessLogElement getAccessLogElement(String identifier);
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/CookieElementMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/CookieElementMatcher.java
new file mode 100644
index 000000000..187c1e565
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/CookieElementMatcher.java
@@ -0,0 +1,42 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.CookieElement;
+
+public class CookieElementMatcher extends ConfigurableAccessLogElementMatcher {
+  public static final String PLACEHOLDER_PREFIX = "%{";
+
+  public static final String PLACEHOLDER_SUFFIX = "}c";
+
+  @Override
+  protected String getPlaceholderSuffix() {
+    return PLACEHOLDER_SUFFIX;
+  }
+
+  @Override
+  protected String getPlaceholderPrefix() {
+    return PLACEHOLDER_PREFIX;
+  }
+
+  @Override
+  protected AccessLogElement getAccessLogElement(String identifier) {
+    return new CookieElement(identifier);
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DatetimeConfigurableMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DatetimeConfigurableMatcher.java
new file mode 100644
index 000000000..036e4c96d
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DatetimeConfigurableMatcher.java
@@ -0,0 +1,51 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.DatetimeConfigurableElement;
+
+/**
+ * Compatible with two kinds of configurable datetime placeholder:
+ * <ul>
+ *   <li>v1: %{PATTERN}t</li>
+ *   <li>v2: %{PATTERN|TIMEZONE|LOCALE}t</li>
+ * </ul>
+ */
+public class DatetimeConfigurableMatcher extends ConfigurableAccessLogElementMatcher {
+
+  public static final String PLACEHOLDER_PREFIX = "%{";
+
+  public static final String PLACEHOLDER_SUFFIX = "}t";
+
+
+  @Override
+  protected String getPlaceholderSuffix() {
+    return PLACEHOLDER_SUFFIX;
+  }
+
+  @Override
+  protected String getPlaceholderPrefix() {
+    return PLACEHOLDER_PREFIX;
+  }
+
+  @Override
+  protected AccessLogElement getAccessLogElement(String identifier) {
+    return new DatetimeConfigurableElement(identifier);
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DatetimeMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DatetimeMatcher.java
new file mode 100644
index 000000000..4cba3c1a8
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DatetimeMatcher.java
@@ -0,0 +1,36 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.DatetimeConfigurableElement;
+
+public class DatetimeMatcher extends SinglePatternImmutableElementMatcher {
+
+  public static final DatetimeConfigurableElement ELEMENT = new DatetimeConfigurableElement();
+
+  @Override
+  protected String getPlaceholderPattern() {
+    return "%t";
+  }
+
+  @Override
+  protected AccessLogElement getAccessLogElement() {
+    return ELEMENT;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DurationMillisecondMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DurationMillisecondMatcher.java
new file mode 100644
index 000000000..c22d9cdaa
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DurationMillisecondMatcher.java
@@ -0,0 +1,36 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.DurationMillisecondElement;
+
+public class DurationMillisecondMatcher extends SinglePatternImmutableElementMatcher {
+
+  public static final DurationMillisecondElement ELEMENT = new DurationMillisecondElement();
+
+  @Override
+  protected String getPlaceholderPattern() {
+    return "%D";
+  }
+
+  @Override
+  protected AccessLogElement getAccessLogElement() {
+    return ELEMENT;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DurationSecondMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DurationSecondMatcher.java
new file mode 100644
index 000000000..fd9488577
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DurationSecondMatcher.java
@@ -0,0 +1,36 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.DurationSecondElement;
+
+public class DurationSecondMatcher extends SinglePatternImmutableElementMatcher {
+
+  public static final DurationSecondElement ELEMENT = new DurationSecondElement();
+
+  @Override
+  protected String getPlaceholderPattern() {
+    return "%T";
+  }
+
+  @Override
+  protected AccessLogElement getAccessLogElement() {
+    return ELEMENT;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/FirstLineOfRequestMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/FirstLineOfRequestMatcher.java
new file mode 100644
index 000000000..172e5e795
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/FirstLineOfRequestMatcher.java
@@ -0,0 +1,36 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.FirstLineOfRequestElement;
+
+public class FirstLineOfRequestMatcher extends SinglePatternImmutableElementMatcher {
+
+  public static final FirstLineOfRequestElement ELEMENT = new FirstLineOfRequestElement();
+
+  @Override
+  protected String getPlaceholderPattern() {
+    return "%r";
+  }
+
+  @Override
+  protected AccessLogElement getAccessLogElement() {
+    return ELEMENT;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/ImmutableAccessLogElementMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/ImmutableAccessLogElementMatcher.java
new file mode 100644
index 000000000..66503af0b
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/ImmutableAccessLogElementMatcher.java
@@ -0,0 +1,53 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import java.util.List;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.AccessLogElementMatcher;
+
+/**
+ * There are log elements that have no configuration parameter, so these elements can be immutable (and singleton).
+ * <br/>
+ * Therefore, the matching algorithm implementation of these elements can be extracted into a universal method.
+ */
+public abstract class ImmutableAccessLogElementMatcher implements AccessLogElementMatcher {
+
+  protected void matchElementPlaceholder(String rawPattern, String pattern,
+      List<AccessLogElementExtraction> extractionList) {
+    int start = -1;
+    int cursor = 0;
+    while (true) {
+      start = rawPattern.indexOf(pattern, cursor);
+
+      if (start < 0) {
+        break;
+      } else {
+        AccessLogElementExtraction extraction = new AccessLogElementExtraction(start, start + pattern.length(),
+            getAccessLogElement());
+        extractionList.add(extraction);
+      }
+
+      cursor = start + pattern.length();
+    }
+  }
+
+  protected abstract AccessLogElement getAccessLogElement();
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/LocalHostMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/LocalHostMatcher.java
new file mode 100644
index 000000000..eb0b41318
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/LocalHostMatcher.java
@@ -0,0 +1,36 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.LocalHostElement;
+
+public class LocalHostMatcher extends SinglePatternImmutableElementMatcher {
+
+  public static final LocalHostElement ELEMENT = new LocalHostElement();
+
+  @Override
+  protected String getPlaceholderPattern() {
+    return "%v";
+  }
+
+  @Override
+  protected AccessLogElement getAccessLogElement() {
+    return ELEMENT;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/LocalPortMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/LocalPortMatcher.java
new file mode 100644
index 000000000..55f904cd3
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/LocalPortMatcher.java
@@ -0,0 +1,36 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.LocalPortElement;
+
+public class LocalPortMatcher extends SinglePatternImmutableElementMatcher {
+
+  public static final LocalPortElement ELEMENT = new LocalPortElement();
+
+  @Override
+  protected String getPlaceholderPattern() {
+    return "%p";
+  }
+
+  @Override
+  protected AccessLogElement getAccessLogElement() {
+    return ELEMENT;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/MethodMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/MethodMatcher.java
new file mode 100644
index 000000000..5d26b4c97
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/MethodMatcher.java
@@ -0,0 +1,37 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.MethodElement;
+
+public class MethodMatcher extends MultiPatternImmutableElementMatcher {
+  public static final String[] PLACEHOLDER_PATTERNS = {"%m", "cs-method"};
+
+  public static final MethodElement ELEMENT = new MethodElement();
+
+  @Override
+  protected String[] getPlaceholderPatterns() {
+    return PLACEHOLDER_PATTERNS;
+  }
+
+  @Override
+  protected AccessLogElement getAccessLogElement() {
+    return ELEMENT;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/MultiPatternImmutableElementMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/MultiPatternImmutableElementMatcher.java
new file mode 100644
index 000000000..006b43cad
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/MultiPatternImmutableElementMatcher.java
@@ -0,0 +1,39 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+
+public abstract class MultiPatternImmutableElementMatcher extends ImmutableAccessLogElementMatcher {
+  @Override
+  public List<AccessLogElementExtraction> extractElementPlaceholder(String rawPattern) {
+    List<AccessLogElementExtraction> extractionList = new ArrayList<>();
+
+    String[] patterns = getPlaceholderPatterns();
+    for (String pattern : patterns) {
+      matchElementPlaceholder(rawPattern, pattern, extractionList);
+    }
+
+    return extractionList;
+  }
+
+  protected abstract String[] getPlaceholderPatterns();
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/QueryOnlyMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/QueryOnlyMatcher.java
new file mode 100644
index 000000000..71b009608
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/QueryOnlyMatcher.java
@@ -0,0 +1,36 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.QueryOnlyElement;
+
+public class QueryOnlyMatcher extends MultiPatternImmutableElementMatcher {
+
+  public static final String[] PLACEHOLDER_PATTERNS = {"%q", "cs-uri-query"};
+
+  @Override
+  protected String[] getPlaceholderPatterns() {
+    return PLACEHOLDER_PATTERNS;
+  }
+
+  @Override
+  protected AccessLogElement getAccessLogElement() {
+    return new QueryOnlyElement();
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/RemoteHostMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/RemoteHostMatcher.java
new file mode 100644
index 000000000..e2e991e66
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/RemoteHostMatcher.java
@@ -0,0 +1,36 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.RemoteHostElement;
+
+public class RemoteHostMatcher extends SinglePatternImmutableElementMatcher {
+
+  public static final RemoteHostElement ELEMENT = new RemoteHostElement();
+
+  @Override
+  protected String getPlaceholderPattern() {
+    return "%h";
+  }
+
+  @Override
+  protected AccessLogElement getAccessLogElement() {
+    return ELEMENT;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/RequestHeaderElementMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/RequestHeaderElementMatcher.java
new file mode 100644
index 000000000..12bcd86f8
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/RequestHeaderElementMatcher.java
@@ -0,0 +1,42 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.RequestHeaderElement;
+
+public class RequestHeaderElementMatcher extends ConfigurableAccessLogElementMatcher {
+  public static final String PLACEHOLDER_PREFIX = "%{";
+
+  public static final String PLACEHOLDER_SUFFIX = "}i";
+
+  @Override
+  protected String getPlaceholderSuffix() {
+    return PLACEHOLDER_SUFFIX;
+  }
+
+  @Override
+  protected String getPlaceholderPrefix() {
+    return PLACEHOLDER_PREFIX;
+  }
+
+  @Override
+  protected AccessLogElement getAccessLogElement(String identifier) {
+    return new RequestHeaderElement(identifier);
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/ResponseHeaderElementMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/ResponseHeaderElementMatcher.java
new file mode 100644
index 000000000..0f701838d
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/ResponseHeaderElementMatcher.java
@@ -0,0 +1,42 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.ResponseHeaderElement;
+
+public class ResponseHeaderElementMatcher extends ConfigurableAccessLogElementMatcher {
+  public static final String PLACEHOLDER_PREFIX = "%{";
+
+  public static final String PLACEHOLDER_SUFFIX = "}o";
+
+  @Override
+  protected String getPlaceholderSuffix() {
+    return PLACEHOLDER_SUFFIX;
+  }
+
+  @Override
+  protected String getPlaceholderPrefix() {
+    return PLACEHOLDER_PREFIX;
+  }
+
+  @Override
+  protected AccessLogElement getAccessLogElement(String identifier) {
+    return new ResponseHeaderElement(identifier);
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/SinglePatternImmutableElementMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/SinglePatternImmutableElementMatcher.java
new file mode 100644
index 000000000..fe931e047
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/SinglePatternImmutableElementMatcher.java
@@ -0,0 +1,37 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+
+public abstract class SinglePatternImmutableElementMatcher extends ImmutableAccessLogElementMatcher {
+  @Override
+  public List<AccessLogElementExtraction> extractElementPlaceholder(String rawPattern) {
+    final String pattern = getPlaceholderPattern();
+    List<AccessLogElementExtraction> extractionList = new ArrayList<>();
+
+    matchElementPlaceholder(rawPattern, pattern, extractionList);
+
+    return extractionList;
+  }
+
+  protected abstract String getPlaceholderPattern();
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/StatusMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/StatusMatcher.java
new file mode 100644
index 000000000..54d6731b2
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/StatusMatcher.java
@@ -0,0 +1,36 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.StatusElement;
+
+public class StatusMatcher extends MultiPatternImmutableElementMatcher {
+
+  public static final String[] PLACEHOLDER_PATTERNS = {"%s", "cs-status"};
+
+  @Override
+  protected String[] getPlaceholderPatterns() {
+    return PLACEHOLDER_PATTERNS;
+  }
+
+  @Override
+  protected AccessLogElement getAccessLogElement() {
+    return new StatusElement();
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/UriPathIncludeQueryMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/UriPathIncludeQueryMatcher.java
new file mode 100644
index 000000000..8c87797ad
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/UriPathIncludeQueryMatcher.java
@@ -0,0 +1,72 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.UriPathIncludeQueryElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.AccessLogElementMatcher;
+
+public class UriPathIncludeQueryMatcher implements AccessLogElementMatcher {
+
+  public static final UriPathIncludeQueryElement ELEMENT = new UriPathIncludeQueryElement();
+
+  public static final String PLACEHOLDER_PATTERN = "cs-uri";
+
+  public static final String[] EXCLUDE_PATTERNS = new String[] {"cs-uri-stem", "cs-uri-query"};
+
+  @Override
+  public List<AccessLogElementExtraction> extractElementPlaceholder(String rawPattern) {
+    List<AccessLogElementExtraction> extractionList = new ArrayList<>();
+
+    int start = -1;
+    int cursor = 0;
+    while (true) {
+      start = rawPattern.indexOf(PLACEHOLDER_PATTERN, cursor);
+      if (start < 0) {
+        break;
+      }
+
+      if (shouldExclude(rawPattern, start, cursor)) {
+        cursor += PLACEHOLDER_PATTERN.length();
+        continue;
+      }
+
+      AccessLogElementExtraction extraction = new AccessLogElementExtraction(start,
+          start + PLACEHOLDER_PATTERN.length(),
+          ELEMENT);
+      extractionList.add(extraction);
+
+      cursor = start + PLACEHOLDER_PATTERN.length();
+    }
+
+    return extractionList;
+  }
+
+  private boolean shouldExclude(String rawPattern, final int start, final int cursor) {
+    for (String exclude : EXCLUDE_PATTERNS) {
+      if (start == rawPattern.indexOf(exclude, cursor)) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/UriPathOnlyMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/UriPathOnlyMatcher.java
new file mode 100644
index 000000000..579dca0a1
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/UriPathOnlyMatcher.java
@@ -0,0 +1,36 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.UriPathOnlyElement;
+
+public class UriPathOnlyMatcher extends MultiPatternImmutableElementMatcher {
+
+  public static final String[] PLACEHOLDER_PATTERNS = {"%U", "cs-uri-stem"};
+
+  @Override
+  protected String[] getPlaceholderPatterns() {
+    return PLACEHOLDER_PATTERNS;
+  }
+
+  @Override
+  protected AccessLogElement getAccessLogElement() {
+    return new UriPathOnlyElement();
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/VersionOrProtocolMatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/VersionOrProtocolMatcher.java
new file mode 100644
index 000000000..485d746a0
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/VersionOrProtocolMatcher.java
@@ -0,0 +1,36 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.VersionOrProtocolElement;
+
+public class VersionOrProtocolMatcher extends SinglePatternImmutableElementMatcher {
+
+  public static final VersionOrProtocolElement ELEMENT = new VersionOrProtocolElement();
+
+  @Override
+  protected String getPlaceholderPattern() {
+    return "%H";
+  }
+
+  @Override
+  protected AccessLogElement getAccessLogElement() {
+    return ELEMENT;
+  }
+}
diff --git a/transports/transport-rest/transport-rest-vertx/src/main/resources/config/base/log4j.properties b/transports/transport-rest/transport-rest-vertx/src/main/resources/config/base/log4j.properties
new file mode 100644
index 000000000..b42356173
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/main/resources/config/base/log4j.properties
@@ -0,0 +1,13 @@
+# access log default configuration
+paas.logs.accesslog.dir=${paas.logs.dir}
+paas.logs.accesslog.file=access.log
+# access log File appender
+log4j.logger.accesslog=INFO,access
+log4j.appender.access=io.servicecomb.foundation.common.utils.RollingFileAppenderExt
+log4j.appender.access.MaxBackupIndex=10
+log4j.appender.access.MaxFileSize=20MB
+log4j.appender.access.file=${paas.logs.accesslog.dir}${paas.logs.accesslog.file}
+log4j.appender.access.layout=org.apache.log4j.PatternLayout
+log4j.appender.access.layout.ConversionPattern=%m%n
+log4j.appender.access.logPermission=rw-------
+log4j.additivity.accesslog=false
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/TestRestServerVerticle.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/TestRestServerVerticle.java
index 96190b4e4..c78ea1f44 100644
--- a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/TestRestServerVerticle.java
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/TestRestServerVerticle.java
@@ -1,11 +1,12 @@
 /*
- * Copyright 2017 Huawei Technologies Co., Ltd
+ * 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
  *
- * Licensed 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
+ *     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,
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/AccessLogConfigurationTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/AccessLogConfigurationTest.java
new file mode 100644
index 000000000..e8a0cdf17
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/AccessLogConfigurationTest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import org.junit.Test;
+
+public class AccessLogConfigurationTest {
+
+  @Test
+  public void getAccessLogEnabled() {
+    boolean result = AccessLogConfiguration.INSTANCE.getAccessLogEnabled();
+    assertFalse(result);
+  }
+
+  @Test
+  public void getAccesslogPattern() {
+    String result = AccessLogConfiguration.INSTANCE.getAccesslogPattern();
+    assertEquals("%h - - %t %r %s %B", result);
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/BytesWrittenV1ElementTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/BytesWrittenV1ElementTest.java
new file mode 100644
index 000000000..d67017dc5
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/BytesWrittenV1ElementTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.vertx.core.http.HttpServerResponse;
+import io.vertx.ext.web.RoutingContext;
+
+public class BytesWrittenV1ElementTest {
+
+  private static final BytesWrittenV1Element ELEMENT = new BytesWrittenV1Element();
+
+  @Test
+  public void getFormattedElement() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext mockContext = Mockito.mock(RoutingContext.class);
+    HttpServerResponse mockResponse = Mockito.mock(HttpServerResponse.class);
+    long bytesWritten = 16l;
+
+    param.setRoutingContext(mockContext);
+    Mockito.when(mockContext.response()).thenReturn(mockResponse);
+    Mockito.when(mockResponse.bytesWritten()).thenReturn(bytesWritten);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals(String.valueOf(bytesWritten), result);
+  }
+
+
+  @Test
+  public void getFormattedElementOnResponseIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext mockContext = Mockito.mock(RoutingContext.class);
+
+    param.setRoutingContext(mockContext);
+    Mockito.when(mockContext.response()).thenReturn(null);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("0", result);
+  }
+
+
+  @Test
+  public void getFormattedElementOnBytesWrittenIsZero() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext mockContext = Mockito.mock(RoutingContext.class);
+    HttpServerResponse mockResponse = Mockito.mock(HttpServerResponse.class);
+    long bytesWritten = 0l;
+
+    param.setRoutingContext(mockContext);
+    Mockito.when(mockContext.response()).thenReturn(mockResponse);
+    Mockito.when(mockResponse.bytesWritten()).thenReturn(bytesWritten);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("0", result);
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/BytesWrittenV2ElementTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/BytesWrittenV2ElementTest.java
new file mode 100644
index 000000000..b7c567fff
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/BytesWrittenV2ElementTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.vertx.core.http.HttpServerResponse;
+import io.vertx.ext.web.RoutingContext;
+
+public class BytesWrittenV2ElementTest {
+
+  public static final BytesWrittenV2Element ELEMENT = new BytesWrittenV2Element();
+
+  @Test
+  public void getFormattedElement() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext mockContext = Mockito.mock(RoutingContext.class);
+    HttpServerResponse mockResponse = Mockito.mock(HttpServerResponse.class);
+    long bytesWritten = 16L;
+
+    param.setRoutingContext(mockContext);
+    Mockito.when(mockContext.response()).thenReturn(mockResponse);
+    Mockito.when(mockResponse.bytesWritten()).thenReturn(bytesWritten);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals(String.valueOf(bytesWritten), result);
+  }
+
+
+  @Test
+  public void getFormattedElementOnResponseIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext mockContext = Mockito.mock(RoutingContext.class);
+
+    param.setRoutingContext(mockContext);
+    Mockito.when(mockContext.response()).thenReturn(null);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+
+
+  @Test
+  public void getFormattedElementOnBytesWrittenIsZero() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext mockContext = Mockito.mock(RoutingContext.class);
+    HttpServerResponse mockResponse = Mockito.mock(HttpServerResponse.class);
+    long bytesWritten = 0l;
+
+    param.setRoutingContext(mockContext);
+    Mockito.when(mockContext.response()).thenReturn(mockResponse);
+    Mockito.when(mockResponse.bytesWritten()).thenReturn(bytesWritten);
+
+    String result = ELEMENT.getFormattedElement(param);
+    assertEquals("-", result);
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/CookieElementTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/CookieElementTest.java
new file mode 100644
index 000000000..37d525ed3
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/CookieElementTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import java.util.HashSet;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.vertx.ext.web.Cookie;
+import io.vertx.ext.web.RoutingContext;
+import io.vertx.ext.web.impl.CookieImpl;
+
+public class CookieElementTest {
+
+  public static final String COOKIE_NAME = "cookieName";
+
+  private static final CookieElement ELEMENT = new CookieElement(COOKIE_NAME);
+
+  @Test
+  public void getFormattedElement() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext mockContext = Mockito.mock(RoutingContext.class);
+    HashSet<Cookie> cookieSet = new HashSet<>();
+    String cookieValue = "cookieValue";
+    CookieImpl cookie = new CookieImpl(COOKIE_NAME, cookieValue);
+
+    cookieSet.add(cookie);
+    Mockito.when(mockContext.cookieCount()).thenReturn(1);
+    Mockito.when(mockContext.cookies()).thenReturn(cookieSet);
+    param.setRoutingContext(mockContext);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    Assert.assertEquals(cookieValue, result);
+  }
+
+  @Test
+  public void getFormattedElementOnCookieCountIsZero() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext mockContext = Mockito.mock(RoutingContext.class);
+    HashSet<Cookie> cookieSet = new HashSet<>();
+
+    Mockito.when(mockContext.cookieCount()).thenReturn(0);
+    Mockito.when(mockContext.cookies()).thenReturn(cookieSet);
+    param.setRoutingContext(mockContext);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    Assert.assertEquals("-", result);
+  }
+
+  @Test
+  public void getFormattedElementOnCookieSetIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext mockContext = Mockito.mock(RoutingContext.class);
+
+    Mockito.when(mockContext.cookieCount()).thenReturn(1);
+    Mockito.when(mockContext.cookies()).thenReturn(null);
+    param.setRoutingContext(mockContext);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    Assert.assertEquals("-", result);
+  }
+
+  @Test
+  public void getFormattedElementOnNotFound() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext mockContext = Mockito.mock(RoutingContext.class);
+    HashSet<Cookie> cookieSet = new HashSet<>();
+    String cookieValue = "cookieValue";
+    CookieImpl cookie = new CookieImpl("anotherCookieName", cookieValue);
+
+    cookieSet.add(cookie);
+    Mockito.when(mockContext.cookieCount()).thenReturn(1);
+    Mockito.when(mockContext.cookies()).thenReturn(cookieSet);
+    param.setRoutingContext(mockContext);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    Assert.assertEquals("-", result);
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/DatetimeConfigurableElementTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/DatetimeConfigurableElementTest.java
new file mode 100644
index 000000000..214094565
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/DatetimeConfigurableElementTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import java.text.SimpleDateFormat;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+
+public class DatetimeConfigurableElementTest {
+
+  private static final long START_MILLISECOND = 1416863450581L;
+
+  @Test
+  public void getFormattedElement() {
+    DatetimeConfigurableElement element = new DatetimeConfigurableElement(
+        "EEE, yyyy MMM dd HH:mm:ss zzz|GMT-08|zh-CN");
+
+    AccessLogParam accessLogParam = new AccessLogParam().setStartMillisecond(START_MILLISECOND);
+
+    String result = element.getFormattedElement(accessLogParam);
+
+    assertEquals("???, 2014 ??? 24 13:10:50 GMT-08:00", result);
+  }
+
+  @Test
+  public void getFormattedElementOnNoPattern() {
+    DatetimeConfigurableElement element = new DatetimeConfigurableElement(
+        "|GMT+08|zh-CN");
+
+    AccessLogParam accessLogParam = new AccessLogParam().setStartMillisecond(START_MILLISECOND);
+
+    String result = element.getFormattedElement(accessLogParam);
+
+    assertEquals("???, 25 ??? 2014 05:10:50 GMT+08:00", result);
+  }
+
+  @Test
+  public void getFormattedElementOnNoTimezone() {
+    DatetimeConfigurableElement element = new DatetimeConfigurableElement(
+        "yyyy/MM/dd zzz||zh-CN");
+    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd zzz", Locale.forLanguageTag("zh-CN"));
+    simpleDateFormat.setTimeZone(TimeZone.getDefault());
+
+    AccessLogParam accessLogParam = new AccessLogParam().setStartMillisecond(START_MILLISECOND);
+
+    String result = element.getFormattedElement(accessLogParam);
+
+    assertEquals(simpleDateFormat.format(START_MILLISECOND), result);
+  }
+
+  @Test
+  public void getFormattedElementOnNoLocale() {
+    DatetimeConfigurableElement element = new DatetimeConfigurableElement(
+        "EEE, dd MMM yyyy HH:mm:ss zzz|GMT+08|");
+
+    AccessLogParam accessLogParam = new AccessLogParam().setStartMillisecond(START_MILLISECOND);
+
+    String result = element.getFormattedElement(accessLogParam);
+
+    assertEquals("Tue, 25 Nov 2014 05:10:50 GMT+08:00", result);
+  }
+
+  @Test
+  public void getFormattedElementOnNoConfig() {
+    DatetimeConfigurableElement element = new DatetimeConfigurableElement(
+        "||");
+    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DatetimeConfigurableElement.DEFAULT_DATETIME_PATTERN,
+        Locale.US);
+    simpleDateFormat.setTimeZone(TimeZone.getDefault());
+    AccessLogParam accessLogParam = new AccessLogParam().setStartMillisecond(START_MILLISECOND);
+
+    String result = element.getFormattedElement(accessLogParam);
+
+    assertEquals(simpleDateFormat.format(START_MILLISECOND), result);
+  }
+
+  @Test
+  public void testConstructorWithNoArg() {
+    DatetimeConfigurableElement element = new DatetimeConfigurableElement();
+    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
+    simpleDateFormat.setTimeZone(TimeZone.getDefault());
+    AccessLogParam accessLogParam = new AccessLogParam().setStartMillisecond(START_MILLISECOND);
+
+    String result = element.getFormattedElement(accessLogParam);
+
+    assertEquals("EEE, dd MMM yyyy HH:mm:ss zzz", element.getPattern());
+    assertEquals(Locale.US, element.getLocale());
+    assertEquals(TimeZone.getDefault(), element.getTimezone());
+    assertEquals(simpleDateFormat.format(START_MILLISECOND), result);
+  }
+
+  @Test
+  public void testConstructorWithNoSeparator() {
+    DatetimeConfigurableElement element = new DatetimeConfigurableElement("yyyy/MM/dd HH:mm:ss zzz");
+    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss zzz", Locale.US);
+    simpleDateFormat.setTimeZone(TimeZone.getDefault());
+    AccessLogParam accessLogParam = new AccessLogParam().setStartMillisecond(START_MILLISECOND);
+
+    String result = element.getFormattedElement(accessLogParam);
+
+    assertEquals("yyyy/MM/dd HH:mm:ss zzz", element.getPattern());
+    assertEquals(Locale.US, element.getLocale());
+    assertEquals(TimeZone.getDefault(), element.getTimezone());
+    assertEquals(simpleDateFormat.format(START_MILLISECOND), result);
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationMillisecondElementTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationMillisecondElementTest.java
new file mode 100644
index 000000000..6ccbbdcad
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationMillisecondElementTest.java
@@ -0,0 +1,38 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+
+public class DurationMillisecondElementTest {
+
+  public static final DurationMillisecondElement ELEMENT = new DurationMillisecondElement();
+
+  @Test
+  public void getFormattedElement() {
+    AccessLogParam param = new AccessLogParam().setStartMillisecond(1L).setEndMillisecond(2L);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("1", result);
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationSecondElementTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationSecondElementTest.java
new file mode 100644
index 000000000..c805e29e8
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationSecondElementTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+
+public class DurationSecondElementTest {
+
+  public static final DurationSecondElement ELEMENT = new DurationSecondElement();
+
+  @Test
+  public void getFormattedElementOn999ms() {
+    AccessLogParam param = new AccessLogParam().setStartMillisecond(1L).setEndMillisecond(1000L);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("0", result);
+  }
+
+  @Test
+  public void getFormattedElementOn1000ms() {
+    AccessLogParam param = new AccessLogParam().setStartMillisecond(1L).setEndMillisecond(1001L);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("1", result);
+  }
+
+  @Test
+  public void getFormattedElementOn1001ms() {
+    AccessLogParam param = new AccessLogParam().setStartMillisecond(1L).setEndMillisecond(1002L);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("1", result);
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/FirstLineOfRequestElementTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/FirstLineOfRequestElementTest.java
new file mode 100644
index 000000000..f82460ec5
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/FirstLineOfRequestElementTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.vertx.core.http.HttpMethod;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.http.HttpVersion;
+import io.vertx.ext.web.RoutingContext;
+
+public class FirstLineOfRequestElementTest {
+
+  public static final FirstLineOfRequestElement ELEMENT = new FirstLineOfRequestElement();
+
+  @Test
+  public void getFormattedElement() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext mockContext = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+    String uri = "/test/uri";
+
+    param.setRoutingContext(mockContext);
+    Mockito.when(mockContext.request()).thenReturn(request);
+    Mockito.when(request.method()).thenReturn(HttpMethod.DELETE);
+    Mockito.when(request.path()).thenReturn(uri);
+    Mockito.when(request.version()).thenReturn(HttpVersion.HTTP_1_1);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("\"DELETE " + uri + " HTTP/1.1\"", result);
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalHostElementTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalHostElementTest.java
new file mode 100644
index 000000000..e661a0ef9
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalHostElementTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.net.SocketAddress;
+import io.vertx.ext.web.RoutingContext;
+
+public class LocalHostElementTest {
+
+  public static final LocalHostElement ELEMENT = new LocalHostElement();
+
+  @Test
+  public void getFormattedElement() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+    SocketAddress localAddress = Mockito.mock(SocketAddress.class);
+    String localHost = "testHost";
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.localAddress()).thenReturn(localAddress);
+    Mockito.when(localAddress.host()).thenReturn(localHost);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals(localHost, result);
+  }
+
+  @Test
+  public void getFormattedElementOnRequestIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(null);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+
+  @Test
+  public void getFormattedElementOnLocalAddressIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.localAddress()).thenReturn(null);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+
+  @Test
+  public void getFormattedElementOnHostIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+    SocketAddress localAddress = Mockito.mock(SocketAddress.class);
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.localAddress()).thenReturn(localAddress);
+    Mockito.when(localAddress.host()).thenReturn(null);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+
+  @Test
+  public void getFormattedElementIsEmpty() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+    SocketAddress localAddress = Mockito.mock(SocketAddress.class);
+    String localHost = "";
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.localAddress()).thenReturn(localAddress);
+    Mockito.when(localAddress.host()).thenReturn(localHost);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalPortElementTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalPortElementTest.java
new file mode 100644
index 000000000..4ac95e36b
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalPortElementTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.net.SocketAddress;
+import io.vertx.ext.web.RoutingContext;
+
+public class LocalPortElementTest {
+
+  @Test
+  public void getFormattedElement() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+    SocketAddress localAddress = Mockito.mock(SocketAddress.class);
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.localAddress()).thenReturn(localAddress);
+    Mockito.when(localAddress.port()).thenReturn(8080);
+
+    String result = new LocalPortElement().getFormattedElement(param);
+
+    assertEquals("8080", result);
+  }
+
+  @Test
+  public void getFormattedElementOnRequestIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(null);
+
+    String result = new LocalPortElement().getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+
+  @Test
+  public void getFormattedElementOnLocalAddressIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.localAddress()).thenReturn(null);
+
+    String result = new LocalPortElement().getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/MethodElementTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/MethodElementTest.java
new file mode 100644
index 000000000..31a0d109d
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/MethodElementTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.vertx.core.http.HttpMethod;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.ext.web.RoutingContext;
+
+public class MethodElementTest {
+
+  @Test
+  public void getFormattedElement() {
+    RoutingContext routingContext = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+    Mockito.when(routingContext.request()).thenReturn(request);
+    Mockito.when(request.method()).thenReturn(HttpMethod.DELETE);
+    AccessLogParam param = new AccessLogParam().setRoutingContext(routingContext);
+
+    Assert.assertEquals("DELETE", new MethodElement().getFormattedElement(param));
+  }
+
+  @Test
+  public void getFormattedElementOnRequestIsNull() {
+    RoutingContext routingContext = Mockito.mock(RoutingContext.class);
+    AccessLogParam param = new AccessLogParam().setRoutingContext(routingContext);
+
+    Mockito.when(routingContext.request()).thenReturn(null);
+
+    Assert.assertEquals("-", new MethodElement().getFormattedElement(param));
+  }
+
+  @Test
+  public void getFormattedElementOnMethodIsNull() {
+    RoutingContext routingContext = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+    AccessLogParam param = new AccessLogParam().setRoutingContext(routingContext);
+
+    Mockito.when(routingContext.request()).thenReturn(request);
+    Mockito.when(request.method()).thenReturn(null);
+
+    Assert.assertEquals("-", new MethodElement().getFormattedElement(param));
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/PlainTextElementTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/PlainTextElementTest.java
new file mode 100644
index 000000000..638c85211
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/PlainTextElementTest.java
@@ -0,0 +1,31 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class PlainTextElementTest {
+
+  @Test
+  public void getFormattedElement() {
+    PlainTextElement element = new PlainTextElement("contentTest");
+    assertEquals("contentTest", element.getFormattedElement(null));
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/QueryOnlyElementTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/QueryOnlyElementTest.java
new file mode 100644
index 000000000..6c4f855f5
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/QueryOnlyElementTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.ext.web.RoutingContext;
+
+public class QueryOnlyElementTest {
+
+  @Test
+  public void getFormattedElement() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+    String query = "?status=up";
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.query()).thenReturn(query);
+
+    String result = new QueryOnlyElement().getFormattedElement(param);
+
+    assertEquals(query, result);
+  }
+
+  @Test
+  public void getFormattedElementOnRequestIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(null);
+
+    String result = new QueryOnlyElement().getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+
+  @Test
+  public void getFormattedElementOnQueryIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.query()).thenReturn(null);
+
+    String result = new QueryOnlyElement().getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+
+  @Test
+  public void getFormattedElementOnQueryIsEmpty() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+    String query = "";
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.query()).thenReturn(query);
+
+    String result = new QueryOnlyElement().getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/RemoteHostElementTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/RemoteHostElementTest.java
new file mode 100644
index 000000000..6a32034e5
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/RemoteHostElementTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.net.SocketAddress;
+import io.vertx.ext.web.RoutingContext;
+
+public class RemoteHostElementTest {
+
+  public static final RemoteHostElement ELEMENT = new RemoteHostElement();
+
+  @Test
+  public void getFormattedElement() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+    SocketAddress address = Mockito.mock(SocketAddress.class);
+    String remoteHost = "remoteHost";
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.remoteAddress()).thenReturn(address);
+    Mockito.when(address.host()).thenReturn(remoteHost);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals(remoteHost, result);
+  }
+
+  @Test
+  public void getFormattedElementOnRequestIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(null);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+
+
+  @Test
+  public void getFormattedElementOnRemoteAddressIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.remoteAddress()).thenReturn(null);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+
+
+  @Test
+  public void getFormattedElementOnHostIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+    SocketAddress address = Mockito.mock(SocketAddress.class);
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.remoteAddress()).thenReturn(address);
+    Mockito.when(address.host()).thenReturn(null);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+
+
+  @Test
+  public void getFormattedElementOnHostIsEmpty() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+    SocketAddress address = Mockito.mock(SocketAddress.class);
+    String remoteHost = "";
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.remoteAddress()).thenReturn(address);
+    Mockito.when(address.host()).thenReturn(remoteHost);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/RequestHeaderElementTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/RequestHeaderElementTest.java
new file mode 100644
index 000000000..16cc0e07f
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/RequestHeaderElementTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.http.impl.headers.VertxHttpHeaders;
+import io.vertx.ext.web.RoutingContext;
+
+public class RequestHeaderElementTest {
+
+  private static final String HEADER_IDENTIFIER = "headerIdentifier";
+
+  private static final RequestHeaderElement ELEMENT = new RequestHeaderElement(HEADER_IDENTIFIER);
+
+  @Test
+  public void getFormattedElement() {
+    RoutingContext mockContext = Mockito.mock(RoutingContext.class);
+    AccessLogParam param = new AccessLogParam().setRoutingContext(mockContext);
+    HttpServerRequest mockRequest = Mockito.mock(HttpServerRequest.class);
+    VertxHttpHeaders headers = new VertxHttpHeaders();
+    String testValue = "testValue";
+    headers.add(HEADER_IDENTIFIER, testValue);
+
+    Mockito.when(mockContext.request()).thenReturn(mockRequest);
+    Mockito.when(mockRequest.headers()).thenReturn(headers);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals(testValue, result);
+    assertEquals(ELEMENT.getIdentifier(), HEADER_IDENTIFIER);
+  }
+
+  @Test
+  public void getFormattedElementIfHeaderIsNull() {
+    RoutingContext mockContext = Mockito.mock(RoutingContext.class);
+    AccessLogParam param = new AccessLogParam().setRoutingContext(mockContext);
+    HttpServerRequest mockRequest = Mockito.mock(HttpServerRequest.class);
+
+    Mockito.when(mockContext.request()).thenReturn(mockRequest);
+    Mockito.when(mockRequest.headers()).thenReturn(null);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+
+  @Test
+  public void getFormattedElementIfNotFound() {
+    RoutingContext mockContext = Mockito.mock(RoutingContext.class);
+    AccessLogParam param = new AccessLogParam().setRoutingContext(mockContext);
+    HttpServerRequest mockRequest = Mockito.mock(HttpServerRequest.class);
+    VertxHttpHeaders headers = new VertxHttpHeaders();
+    String testValue = "testValue";
+    headers.add("anotherHeader", testValue);
+
+    Mockito.when(mockContext.request()).thenReturn(mockRequest);
+    Mockito.when(mockRequest.headers()).thenReturn(headers);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/ResponseHeaderElementTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/ResponseHeaderElementTest.java
new file mode 100644
index 000000000..48199794d
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/ResponseHeaderElementTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.vertx.core.http.HttpServerResponse;
+import io.vertx.core.http.impl.headers.VertxHttpHeaders;
+import io.vertx.ext.web.RoutingContext;
+
+public class ResponseHeaderElementTest {
+
+  private static final String IDENTIFIER = "identifier";
+
+  private static final ResponseHeaderElement ELEMENT = new ResponseHeaderElement(IDENTIFIER);
+
+  @Test
+  public void getFormattedElement() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext mockContext = Mockito.mock(RoutingContext.class);
+    HttpServerResponse mockResponse = Mockito.mock(HttpServerResponse.class);
+    VertxHttpHeaders headers = new VertxHttpHeaders();
+    String headerValue = "headerValue";
+
+    param.setRoutingContext(mockContext);
+    headers.add(IDENTIFIER, headerValue);
+
+    Mockito.when(mockContext.response()).thenReturn(mockResponse);
+    Mockito.when(mockResponse.headers()).thenReturn(headers);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals(headerValue, result);
+    assertEquals(ELEMENT.getIdentifier(), IDENTIFIER);
+  }
+
+  @Test
+  public void getFormattedElementOnHeadersIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext mockContext = Mockito.mock(RoutingContext.class);
+    HttpServerResponse mockResponse = Mockito.mock(HttpServerResponse.class);
+
+    param.setRoutingContext(mockContext);
+
+    Mockito.when(mockContext.response()).thenReturn(mockResponse);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+
+  @Test
+  public void getFormattedElementOnResponseIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext mockContext = Mockito.mock(RoutingContext.class);
+
+    param.setRoutingContext(mockContext);
+
+    Mockito.when(mockContext.response()).thenReturn(null);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+
+  @Test
+  public void getFormattedElementOnNotFound() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext mockContext = Mockito.mock(RoutingContext.class);
+    HttpServerResponse mockResponse = Mockito.mock(HttpServerResponse.class);
+    VertxHttpHeaders headers = new VertxHttpHeaders();
+    String headerValue = "headerValue";
+
+    param.setRoutingContext(mockContext);
+    headers.add("anotherHeader", headerValue);
+
+    Mockito.when(mockContext.response()).thenReturn(mockResponse);
+    Mockito.when(mockResponse.headers()).thenReturn(headers);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/StatusElementTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/StatusElementTest.java
new file mode 100644
index 000000000..4ef2c6ca4
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/StatusElementTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.vertx.core.http.HttpServerResponse;
+import io.vertx.ext.web.RoutingContext;
+
+public class StatusElementTest {
+
+  public static final StatusElement STATUS_ELEMENT = new StatusElement();
+
+  @Test
+  public void getFormattedElement() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerResponse response = Mockito.mock(HttpServerResponse.class);
+    int statusCode = 200;
+
+    param.setRoutingContext(context);
+    Mockito.when(context.response()).thenReturn(response);
+    Mockito.when(response.getStatusCode()).thenReturn(statusCode);
+
+    String result = STATUS_ELEMENT.getFormattedElement(param);
+
+    assertEquals("200", result);
+  }
+
+
+  @Test
+  public void getFormattedElementOnResponseIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+
+    param.setRoutingContext(context);
+    Mockito.when(context.response()).thenReturn(null);
+
+    String result = STATUS_ELEMENT.getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/UriPathIncludeQueryElementTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/UriPathIncludeQueryElementTest.java
new file mode 100644
index 000000000..b72bb242c
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/UriPathIncludeQueryElementTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.ext.web.RoutingContext;
+
+public class UriPathIncludeQueryElementTest {
+
+  public static final UriPathIncludeQueryElement ELEMENT = new UriPathIncludeQueryElement();
+
+  @Test
+  public void getFormattedElement() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+    String uri = "uriTest";
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.uri()).thenReturn(uri);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals(uri, result);
+  }
+
+
+  @Test
+  public void getFormattedElementOnRequestIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(null);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+
+  @Test
+  public void getFormattedElementOnUriIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.uri()).thenReturn(null);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+
+
+  @Test
+  public void getFormattedElementOnUriIsEmpty() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+    String uri = "";
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.uri()).thenReturn(uri);
+
+    String result = ELEMENT.getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/UriPathOnlyElementTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/UriPathOnlyElementTest.java
new file mode 100644
index 000000000..ca90bd908
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/UriPathOnlyElementTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.ext.web.RoutingContext;
+
+public class UriPathOnlyElementTest {
+
+  @Test
+  public void getFormattedElement() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+    String uri = "/uri/test";
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.path()).thenReturn(uri);
+
+    String result = new UriPathOnlyElement().getFormattedElement(param);
+
+    Assert.assertEquals(uri, result);
+  }
+
+  @Test
+  public void getFormattedElementOnRequestIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(null);
+
+    String result = new UriPathOnlyElement().getFormattedElement(param);
+
+    Assert.assertEquals("-", result);
+  }
+
+  @Test
+  public void getFormattedElementOnMethodIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.path()).thenReturn(null);
+
+    String result = new UriPathOnlyElement().getFormattedElement(param);
+
+    Assert.assertEquals("-", result);
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/VersionOrProtocolElementTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/VersionOrProtocolElementTest.java
new file mode 100644
index 000000000..e756286d8
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/element/impl/VersionOrProtocolElementTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.element.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.http.HttpVersion;
+import io.vertx.ext.web.RoutingContext;
+
+public class VersionOrProtocolElementTest {
+
+  @Test
+  public void getFormattedElement() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.version()).thenReturn(HttpVersion.HTTP_1_1);
+
+    String result = new VersionOrProtocolElement().getFormattedElement(param);
+    assertEquals("HTTP/1.1", result);
+
+    Mockito.when(request.version()).thenReturn(HttpVersion.HTTP_1_0);
+    result = new VersionOrProtocolElement().getFormattedElement(param);
+    assertEquals("HTTP/1.0", result);
+
+    Mockito.when(request.version()).thenReturn(HttpVersion.HTTP_2);
+    result = new VersionOrProtocolElement().getFormattedElement(param);
+    assertEquals("HTTP/2.0", result);
+  }
+
+  @Test
+  public void getFormattedElementOnRequestIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(null);
+
+    String result = new VersionOrProtocolElement().getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+
+
+  @Test
+  public void getFormattedElementOnVersionIsNull() {
+    AccessLogParam param = new AccessLogParam();
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+
+    param.setRoutingContext(context);
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.version()).thenReturn(null);
+
+    String result = new VersionOrProtocolElement().getFormattedElement(param);
+
+    assertEquals("-", result);
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/impl/AccessLogHandlerTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/impl/AccessLogHandlerTest.java
new file mode 100644
index 000000000..8c189f0d3
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/impl/AccessLogHandlerTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.TimeZone;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.slf4j.Logger;
+
+import io.servicecomb.transport.rest.vertx.accesslog.AccessLogParam;
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.DatetimeConfigurableElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.MethodElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.PlainTextElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+import io.vertx.core.http.HttpMethod;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.ext.web.RoutingContext;
+import mockit.Deencapsulation;
+
+public class AccessLogHandlerTest {
+
+  private static final AccessLogElement methodElement = new MethodElement();
+
+  private static final AccessLogElement datetimeElement = new DatetimeConfigurableElement();
+
+  private static final AccessLogElement plainTextElement = new PlainTextElement(" - ");
+
+  private static final Logger logger = Mockito.mock(Logger.class);
+
+  private static final AccessLogHandler ACCESS_LOG_HANDLER = new AccessLogHandler("rawPattern", s -> {
+    assertEquals("rawPattern", s);
+    return Arrays.asList(new AccessLogElementExtraction().setAccessLogElement(methodElement),
+        new AccessLogElementExtraction().setAccessLogElement(plainTextElement),
+        new AccessLogElementExtraction().setAccessLogElement(datetimeElement));
+  });
+
+  @BeforeClass
+  public static void init() {
+    Deencapsulation.setField(AccessLogHandler.class, "LOGGER", logger);
+  }
+
+  @Test
+  public void testConstructor() {
+    AccessLogElement[] elements = Deencapsulation.getField(ACCESS_LOG_HANDLER, "accessLogElements");
+    assertEquals(3, elements.length);
+    assertEquals(methodElement, elements[0]);
+    assertEquals(plainTextElement, elements[1]);
+    assertEquals(datetimeElement, elements[2]);
+  }
+
+  @Test
+  public void handle() {
+    RoutingContext testContext = Mockito.mock(RoutingContext.class);
+    ACCESS_LOG_HANDLER.handle(testContext);
+  }
+
+  @Test
+  public void testLog() {
+    RoutingContext context = Mockito.mock(RoutingContext.class);
+    HttpServerRequest request = Mockito.mock(HttpServerRequest.class);
+    long startMillisecond = 1416863450581L;
+    AccessLogParam accessLogParam = new AccessLogParam().setStartMillisecond(startMillisecond)
+        .setRoutingContext(context);
+    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DatetimeConfigurableElement.DEFAULT_DATETIME_PATTERN,
+        DatetimeConfigurableElement.DEFAULT_LOCALE);
+    simpleDateFormat.setTimeZone(TimeZone.getDefault());
+
+    Mockito.when(context.request()).thenReturn(request);
+    Mockito.when(request.method()).thenReturn(HttpMethod.DELETE);
+
+    Deencapsulation.invoke(ACCESS_LOG_HANDLER, "log", accessLogParam);
+
+    Mockito.verify(logger).info("DELETE" + " - " + simpleDateFormat.format(startMillisecond));
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/impl/DefaultAccessLogPatternParserTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/impl/DefaultAccessLogPatternParserTest.java
new file mode 100644
index 000000000..304ce8466
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/impl/DefaultAccessLogPatternParserTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.BytesWrittenV1Element;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.BytesWrittenV2Element;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.CookieElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.DatetimeConfigurableElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.DurationMillisecondElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.DurationSecondElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.FirstLineOfRequestElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.LocalHostElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.LocalPortElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.MethodElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.PlainTextElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.QueryOnlyElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.RemoteHostElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.RequestHeaderElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.ResponseHeaderElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.StatusElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.UriPathIncludeQueryElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.UriPathOnlyElement;
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.VersionOrProtocolElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+import mockit.Deencapsulation;
+
+public class DefaultAccessLogPatternParserTest {
+  private static final String ROW_PATTERN = "[cs-method] %m %s%T%D%h%v%p%B%b%r%U%q"
+      + "cs-uri-stemcs-uri-querycs-uri%H%t%{yyyy MM dd HH:mm:ss zzz}t"
+      + "%{yyyy MM dd HH:mm:ss|GMT+0|en-US}t"
+      + "%{incoming-header}i"
+      + "%{outgoing-header}o"
+      + "%{cookie}c";
+
+  private static DefaultAccessLogPatternParser accessLogPatternParser = new DefaultAccessLogPatternParser();
+
+  @Test
+  public void testParsePattern() {
+    List<AccessLogElementExtraction> result = accessLogPatternParser.parsePattern(ROW_PATTERN);
+    assertEquals(26, result.size());
+    assertEquals(PlainTextElement.class, result.get(0).getAccessLogElement().getClass());
+    assertEquals(MethodElement.class, result.get(1).getAccessLogElement().getClass());
+    assertEquals(PlainTextElement.class, result.get(2).getAccessLogElement().getClass());
+    assertEquals(MethodElement.class, result.get(3).getAccessLogElement().getClass());
+    assertEquals(PlainTextElement.class, result.get(4).getAccessLogElement().getClass());
+    assertEquals(StatusElement.class, result.get(5).getAccessLogElement().getClass());
+    assertEquals(DurationSecondElement.class, result.get(6).getAccessLogElement().getClass());
+    assertEquals(DurationMillisecondElement.class, result.get(7).getAccessLogElement().getClass());
+    assertEquals(RemoteHostElement.class, result.get(8).getAccessLogElement().getClass());
+    assertEquals(LocalHostElement.class, result.get(9).getAccessLogElement().getClass());
+    assertEquals(LocalPortElement.class, result.get(10).getAccessLogElement().getClass());
+    assertEquals(BytesWrittenV1Element.class, result.get(11).getAccessLogElement().getClass());
+    assertEquals(BytesWrittenV2Element.class, result.get(12).getAccessLogElement().getClass());
+    assertEquals(FirstLineOfRequestElement.class, result.get(13).getAccessLogElement().getClass());
+    assertEquals(UriPathOnlyElement.class, result.get(14).getAccessLogElement().getClass());
+    assertEquals(QueryOnlyElement.class, result.get(15).getAccessLogElement().getClass());
+    assertEquals(UriPathOnlyElement.class, result.get(16).getAccessLogElement().getClass());
+    assertEquals(QueryOnlyElement.class, result.get(17).getAccessLogElement().getClass());
+    assertEquals(UriPathIncludeQueryElement.class, result.get(18).getAccessLogElement().getClass());
+    assertEquals(VersionOrProtocolElement.class, result.get(19).getAccessLogElement().getClass());
+    assertEquals(DatetimeConfigurableElement.class, result.get(20).getAccessLogElement().getClass());
+    assertEquals(DatetimeConfigurableElement.class, result.get(21).getAccessLogElement().getClass());
+    assertEquals(DatetimeConfigurableElement.class, result.get(22).getAccessLogElement().getClass());
+    assertEquals(RequestHeaderElement.class, result.get(23).getAccessLogElement().getClass());
+    assertEquals(ResponseHeaderElement.class, result.get(24).getAccessLogElement().getClass());
+    assertEquals(CookieElement.class, result.get(25).getAccessLogElement().getClass());
+  }
+
+  @Test
+  public void testCheckExtractionList() {
+    List<AccessLogElementExtraction> extractionList = new ArrayList<>(3);
+    extractionList.add(new AccessLogElementExtraction().setStart(0).setEnd(3));
+    extractionList.add(new AccessLogElementExtraction().setStart(3).setEnd(6));
+    extractionList.add(new AccessLogElementExtraction().setStart(5).setEnd(9));
+
+    try {
+      Deencapsulation.invoke(new DefaultAccessLogPatternParser(), "checkExtractionList", extractionList);
+      fail("expect an exception");
+    } catch (Exception e) {
+      assertEquals(IllegalArgumentException.class, e.getClass());
+      assertEquals("access log pattern contains illegal placeholder, please check it.", e.getMessage());
+    }
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/BytesWrittenV1MatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/BytesWrittenV1MatcherTest.java
new file mode 100644
index 000000000..f255ffa54
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/BytesWrittenV1MatcherTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.BytesWrittenV1Element;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+
+public class BytesWrittenV1MatcherTest {
+  private static final BytesWrittenV1Matcher MATCHER = new BytesWrittenV1Matcher();
+
+  private static final String RAW_PATTERN = "%B %h %{PATTERN}t %B%B %H %B";
+
+  @Test
+  public void testExtractElementPlaceHolder() {
+    List<AccessLogElementExtraction> extractionList = MATCHER.extractElementPlaceholder(RAW_PATTERN);
+
+    assertEquals(4, extractionList.size());
+    assertEquals(0, extractionList.get(0).getStart());
+    assertEquals(2, extractionList.get(0).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(0).getAccessLogElement());
+    assertEquals(18, extractionList.get(1).getStart());
+    assertEquals(20, extractionList.get(1).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(1).getAccessLogElement());
+    assertEquals(20, extractionList.get(2).getStart());
+    assertEquals(22, extractionList.get(2).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(2).getAccessLogElement());
+    assertEquals(26, extractionList.get(3).getStart());
+    assertEquals(28, extractionList.get(3).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(3).getAccessLogElement());
+  }
+
+  @Test
+  public void testGetPlaceholderPattern() {
+    assertEquals("%B", MATCHER.getPlaceholderPattern());
+  }
+
+  @Test
+  public void getAccessLogElement() {
+    assertTrue(BytesWrittenV1Element.class.equals(MATCHER.getAccessLogElement().getClass()));
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/BytesWrittenV2MatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/BytesWrittenV2MatcherTest.java
new file mode 100644
index 000000000..2e4d6f304
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/BytesWrittenV2MatcherTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.BytesWrittenV2Element;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+
+public class BytesWrittenV2MatcherTest {
+  private static final BytesWrittenV2Matcher MATCHER = new BytesWrittenV2Matcher();
+
+  private static final String RAW_PATTERN = "%b %h %{PATTERN}t %b%b %H %b";
+
+  @Test
+  public void testExtractElementPlaceHolder() {
+    List<AccessLogElementExtraction> extractionList = MATCHER.extractElementPlaceholder(RAW_PATTERN);
+
+    assertEquals(4, extractionList.size());
+    assertEquals(0, extractionList.get(0).getStart());
+    assertEquals(2, extractionList.get(0).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(0).getAccessLogElement());
+    assertEquals(18, extractionList.get(1).getStart());
+    assertEquals(20, extractionList.get(1).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(1).getAccessLogElement());
+    assertEquals(20, extractionList.get(2).getStart());
+    assertEquals(22, extractionList.get(2).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(2).getAccessLogElement());
+    assertEquals(26, extractionList.get(3).getStart());
+    assertEquals(28, extractionList.get(3).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(3).getAccessLogElement());
+  }
+
+  @Test
+  public void testGetPlaceholderPattern() {
+    assertEquals("%b", MATCHER.getPlaceholderPattern());
+  }
+
+  @Test
+  public void getAccessLogElement() {
+    assertTrue(BytesWrittenV2Element.class.equals(MATCHER.getAccessLogElement().getClass()));
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/CookieElementMatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/CookieElementMatcherTest.java
new file mode 100644
index 000000000..9ac704908
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/CookieElementMatcherTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.CookieElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+
+public class CookieElementMatcherTest {
+
+  private static final CookieElementMatcher MATCHER = new CookieElementMatcher();
+
+  @Test
+  public void extractElementPlaceholder() {
+    List<AccessLogElementExtraction> extractionList = MATCHER
+        .extractElementPlaceholder("%{header0}c %h %{yyyyMMdd HH:mm:ss zzz}t %{header1}c %b%b %H %{header2}c");
+
+    assertEquals(3, extractionList.size());
+    assertEquals(0, extractionList.get(0).getStart());
+    assertEquals(11, extractionList.get(0).getEnd());
+    assertEquals(41, extractionList.get(1).getStart());
+    assertEquals(52, extractionList.get(1).getEnd());
+    assertEquals(61, extractionList.get(2).getStart());
+    assertEquals(72, extractionList.get(2).getEnd());
+
+    assertEquals(CookieElement.class, extractionList.get(0).getAccessLogElement().getClass());
+    assertEquals(CookieElement.class, extractionList.get(1).getAccessLogElement().getClass());
+    assertEquals(CookieElement.class, extractionList.get(2).getAccessLogElement().getClass());
+
+    assertEquals("header0",
+        ((CookieElement) (extractionList.get(0).getAccessLogElement())).getIdentifier());
+    assertEquals("header1",
+        ((CookieElement) (extractionList.get(1).getAccessLogElement())).getIdentifier());
+    assertEquals("header2",
+        ((CookieElement) (extractionList.get(2).getAccessLogElement())).getIdentifier());
+  }
+
+  @Test
+  public void extractElementPlaceholderOnNotMatched() {
+    List<AccessLogElementExtraction> extractionList = MATCHER
+        .extractElementPlaceholder("%{header0}i %h %{yyyyMMdd HH:mm:ss zzz}t %{header1}i %b%b %H %{header2}i");
+
+    assertEquals(0, extractionList.size());
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DatetimeConfigurableMatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DatetimeConfigurableMatcherTest.java
new file mode 100644
index 000000000..1b3619879
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DatetimeConfigurableMatcherTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.DatetimeConfigurableElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+import mockit.Deencapsulation;
+
+public class DatetimeConfigurableMatcherTest {
+  private static final DatetimeConfigurableMatcher MATCHER = new DatetimeConfigurableMatcher();
+
+  @Test
+  public void extractElementPlaceholderOnOnlyV1() {
+    List<AccessLogElementExtraction> extractionList = MATCHER
+        .extractElementPlaceholder("%{yyyyMMdd}t %h %{yyyyMMdd HH:mm:ss zzz}t %b%b %H %{yyyyMMdd}t");
+
+    assertEquals(3, extractionList.size());
+    assertEquals(0, extractionList.get(0).getStart());
+    assertEquals(12, extractionList.get(0).getEnd());
+    assertEquals(16, extractionList.get(1).getStart());
+    assertEquals(41, extractionList.get(1).getEnd());
+    assertEquals(50, extractionList.get(2).getStart());
+    assertEquals(62, extractionList.get(2).getEnd());
+
+    assertEquals(DatetimeConfigurableElement.class, extractionList.get(0).getAccessLogElement().getClass());
+    assertEquals(DatetimeConfigurableElement.class, extractionList.get(1).getAccessLogElement().getClass());
+    assertEquals(DatetimeConfigurableElement.class, extractionList.get(2).getAccessLogElement().getClass());
+
+    assertEquals("yyyyMMdd",
+        ((DatetimeConfigurableElement) (extractionList.get(0).getAccessLogElement())).getPattern());
+    assertEquals("yyyyMMdd HH:mm:ss zzz",
+        ((DatetimeConfigurableElement) (extractionList.get(1).getAccessLogElement())).getPattern());
+    assertEquals("yyyyMMdd",
+        ((DatetimeConfigurableElement) (extractionList.get(2).getAccessLogElement())).getPattern());
+  }
+
+  @Test
+  public void extractElementPlaceholderOnOnlyV2() {
+    List<AccessLogElementExtraction> extractionList = MATCHER
+        .extractElementPlaceholder(
+            "%{EEE, dd MMM yyyy HH:mm:ss zzz||zh-CN}t %h %{EEE, yy/MM/dd HH:mm:ss zzz|GMT+08|zh-CN}t %b%b %H %{EEE, dd MMM yyyy HH:mm:ss zzz|GMT-08|}t");
+
+    assertEquals(3, extractionList.size());
+    assertEquals(0, extractionList.get(0).getStart());
+    assertEquals(40, extractionList.get(0).getEnd());
+    assertEquals(44, extractionList.get(1).getStart());
+    assertEquals(87, extractionList.get(1).getEnd());
+    assertEquals(96, extractionList.get(2).getStart());
+    assertEquals(137, extractionList.get(2).getEnd());
+
+    assertEquals(DatetimeConfigurableElement.class, extractionList.get(0).getAccessLogElement().getClass());
+    assertEquals(DatetimeConfigurableElement.class, extractionList.get(1).getAccessLogElement().getClass());
+    assertEquals(DatetimeConfigurableElement.class, extractionList.get(2).getAccessLogElement().getClass());
+
+    assertEquals("EEE, dd MMM yyyy HH:mm:ss zzz",
+        Deencapsulation.getField(extractionList.get(0).getAccessLogElement(), "pattern"));
+    assertEquals(TimeZone.getDefault(),
+        Deencapsulation.getField(extractionList.get(0).getAccessLogElement(), "timezone"));
+    assertEquals(Locale.SIMPLIFIED_CHINESE,
+        Deencapsulation.getField(extractionList.get(0).getAccessLogElement(), "locale"));
+
+    assertEquals("EEE, yy/MM/dd HH:mm:ss zzz",
+        Deencapsulation.getField(extractionList.get(1).getAccessLogElement(), "pattern"));
+    assertEquals(TimeZone.getTimeZone("GMT+08"),
+        Deencapsulation.getField(extractionList.get(1).getAccessLogElement(), "timezone"));
+    assertEquals(Locale.SIMPLIFIED_CHINESE,
+        Deencapsulation.getField(extractionList.get(1).getAccessLogElement(), "locale"));
+
+    assertEquals("EEE, dd MMM yyyy HH:mm:ss zzz",
+        Deencapsulation.getField(extractionList.get(2).getAccessLogElement(), "pattern"));
+    assertEquals(TimeZone.getTimeZone("GMT-08"),
+        Deencapsulation.getField(extractionList.get(2).getAccessLogElement(), "timezone"));
+    assertEquals(Locale.US, Deencapsulation.getField(extractionList.get(2).getAccessLogElement(), "locale"));
+  }
+
+  @Test
+  public void extractElementPlaceholderOnV1V2Mixed() {
+    List<AccessLogElementExtraction> extractionList = MATCHER
+        .extractElementPlaceholder(
+            "%{yyyyMMdd}t %h %{yyyyMMdd HH:mm:ss zzz}t %{EEE, dd MMM yyyy HH:mm:ss zzz|GMT+08|zh-CN}t %b%b %H %{yyyyMMdd}t");
+
+    assertEquals(4, extractionList.size());
+    assertEquals(0, extractionList.get(0).getStart());
+    assertEquals(12, extractionList.get(0).getEnd());
+    assertEquals(16, extractionList.get(1).getStart());
+    assertEquals(41, extractionList.get(1).getEnd());
+    assertEquals(42, extractionList.get(2).getStart());
+    assertEquals(88, extractionList.get(2).getEnd());
+    assertEquals(97, extractionList.get(3).getStart());
+    assertEquals(109, extractionList.get(3).getEnd());
+
+    assertEquals(DatetimeConfigurableElement.class, extractionList.get(0).getAccessLogElement().getClass());
+    assertEquals(DatetimeConfigurableElement.class, extractionList.get(1).getAccessLogElement().getClass());
+    assertEquals(DatetimeConfigurableElement.class, extractionList.get(2).getAccessLogElement().getClass());
+    assertEquals(DatetimeConfigurableElement.class, extractionList.get(3).getAccessLogElement().getClass());
+    assertEquals("yyyyMMdd",
+        ((DatetimeConfigurableElement) (extractionList.get(0).getAccessLogElement())).getPattern());
+    assertEquals("yyyyMMdd HH:mm:ss zzz",
+        ((DatetimeConfigurableElement) (extractionList.get(1).getAccessLogElement())).getPattern());
+    assertEquals("EEE, dd MMM yyyy HH:mm:ss zzz",
+        ((DatetimeConfigurableElement) (extractionList.get(2).getAccessLogElement())).getPattern());
+    assertEquals("yyyyMMdd",
+        ((DatetimeConfigurableElement) (extractionList.get(3).getAccessLogElement())).getPattern());
+  }
+
+  @Test
+  public void extractElementPlaceholderOnNotFound() {
+    List<AccessLogElementExtraction> extractionList = MATCHER
+        .extractElementPlaceholder(
+            "%{identifier}i %h %b%b %H %{identifier}o");
+
+    assertEquals(0, extractionList.size());
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DatetimeMatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DatetimeMatcherTest.java
new file mode 100644
index 000000000..f71edbcab
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DatetimeMatcherTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.DatetimeConfigurableElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+
+public class DatetimeMatcherTest {
+  private static final DatetimeMatcher MATCHER = new DatetimeMatcher();
+
+  private static final String RAW_PATTERN = "%t %h %{PATTERN}t %t%t %H %t";
+
+  @Test
+  public void testExtractElementPlaceHolder() {
+    List<AccessLogElementExtraction> extractionList = MATCHER.extractElementPlaceholder(RAW_PATTERN);
+
+    assertEquals(4, extractionList.size());
+    assertEquals(0, extractionList.get(0).getStart());
+    assertEquals(2, extractionList.get(0).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(0).getAccessLogElement());
+    assertEquals(18, extractionList.get(1).getStart());
+    assertEquals(20, extractionList.get(1).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(1).getAccessLogElement());
+    assertEquals(20, extractionList.get(2).getStart());
+    assertEquals(22, extractionList.get(2).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(2).getAccessLogElement());
+    assertEquals(26, extractionList.get(3).getStart());
+    assertEquals(28, extractionList.get(3).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(3).getAccessLogElement());
+  }
+
+  @Test
+  public void testGetPlaceholderPattern() {
+    assertEquals("%t", MATCHER.getPlaceholderPattern());
+  }
+
+  @Test
+  public void getAccessLogElement() {
+    assertTrue(DatetimeConfigurableElement.class.equals(MATCHER.getAccessLogElement().getClass()));
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DurationMillisecondMatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DurationMillisecondMatcherTest.java
new file mode 100644
index 000000000..46d88535c
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DurationMillisecondMatcherTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.DurationMillisecondElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+
+public class DurationMillisecondMatcherTest {
+  private static final DurationMillisecondMatcher MATCHER = new DurationMillisecondMatcher();
+
+  private static final String RAW_PATTERN = "%D %h %{PATTERN}t %D%D %H %D";
+
+  @Test
+  public void testExtractElementPlaceHolder() {
+    List<AccessLogElementExtraction> extractionList = MATCHER.extractElementPlaceholder(RAW_PATTERN);
+
+    assertEquals(4, extractionList.size());
+    assertEquals(0, extractionList.get(0).getStart());
+    assertEquals(2, extractionList.get(0).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(0).getAccessLogElement());
+    assertEquals(18, extractionList.get(1).getStart());
+    assertEquals(20, extractionList.get(1).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(1).getAccessLogElement());
+    assertEquals(20, extractionList.get(2).getStart());
+    assertEquals(22, extractionList.get(2).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(2).getAccessLogElement());
+    assertEquals(26, extractionList.get(3).getStart());
+    assertEquals(28, extractionList.get(3).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(3).getAccessLogElement());
+  }
+
+  @Test
+  public void testGetPlaceholderPattern() {
+    assertEquals("%D", MATCHER.getPlaceholderPattern());
+  }
+
+  @Test
+  public void getAccessLogElement() {
+    assertTrue(DurationMillisecondElement.class.equals(MATCHER.getAccessLogElement().getClass()));
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DurationSecondMatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DurationSecondMatcherTest.java
new file mode 100644
index 000000000..faa00af73
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/DurationSecondMatcherTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.DurationSecondElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+
+public class DurationSecondMatcherTest {
+  private static final DurationSecondMatcher MATCHER = new DurationSecondMatcher();
+
+  private static final String RAW_PATTERN = "%T %h %{PATTERN}t %T%T %H %T";
+
+  @Test
+  public void testExtractElementPlaceHolder() {
+    List<AccessLogElementExtraction> extractionList = MATCHER.extractElementPlaceholder(RAW_PATTERN);
+
+    assertEquals(4, extractionList.size());
+    assertEquals(0, extractionList.get(0).getStart());
+    assertEquals(2, extractionList.get(0).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(0).getAccessLogElement());
+    assertEquals(18, extractionList.get(1).getStart());
+    assertEquals(20, extractionList.get(1).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(1).getAccessLogElement());
+    assertEquals(20, extractionList.get(2).getStart());
+    assertEquals(22, extractionList.get(2).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(2).getAccessLogElement());
+    assertEquals(26, extractionList.get(3).getStart());
+    assertEquals(28, extractionList.get(3).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(3).getAccessLogElement());
+  }
+
+  @Test
+  public void testGetPlaceholderPattern() {
+    assertEquals("%T", MATCHER.getPlaceholderPattern());
+  }
+
+  @Test
+  public void getAccessLogElement() {
+    assertTrue(DurationSecondElement.class.equals(MATCHER.getAccessLogElement().getClass()));
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/FirstLineOfRequestMatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/FirstLineOfRequestMatcherTest.java
new file mode 100644
index 000000000..4c17f717d
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/FirstLineOfRequestMatcherTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.FirstLineOfRequestElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+
+public class FirstLineOfRequestMatcherTest {
+  private static final FirstLineOfRequestMatcher MATCHER = new FirstLineOfRequestMatcher();
+
+  private static final String RAW_PATTERN = "%r %h %{PATTERN}t %r%r %H %r";
+
+  @Test
+  public void testExtractElementPlaceHolder() {
+    List<AccessLogElementExtraction> extractionList = MATCHER.extractElementPlaceholder(RAW_PATTERN);
+
+    assertEquals(4, extractionList.size());
+    assertEquals(0, extractionList.get(0).getStart());
+    assertEquals(2, extractionList.get(0).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(0).getAccessLogElement());
+    assertEquals(18, extractionList.get(1).getStart());
+    assertEquals(20, extractionList.get(1).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(1).getAccessLogElement());
+    assertEquals(20, extractionList.get(2).getStart());
+    assertEquals(22, extractionList.get(2).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(2).getAccessLogElement());
+    assertEquals(26, extractionList.get(3).getStart());
+    assertEquals(28, extractionList.get(3).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(3).getAccessLogElement());
+  }
+
+  @Test
+  public void testGetPlaceholderPattern() {
+    assertEquals("%r", MATCHER.getPlaceholderPattern());
+  }
+
+  @Test
+  public void getAccessLogElement() {
+    assertTrue(FirstLineOfRequestElement.class.equals(MATCHER.getAccessLogElement().getClass()));
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/ImmutableAccessLogElementMatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/ImmutableAccessLogElementMatcherTest.java
new file mode 100644
index 000000000..45a60045d
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/ImmutableAccessLogElementMatcherTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.AccessLogElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+
+public class ImmutableAccessLogElementMatcherTest {
+  public static final ImmutableAccessLogElementMatcher MATCHER = new MockImmutableAccessLogElementMatcher();
+
+  @Test
+  public void testExtractElementPlaceHolder() {
+    final String rawPattern = "%m %m%m %m";
+    List<AccessLogElementExtraction> extractionList = MATCHER.extractElementPlaceholder(rawPattern);
+
+    assertEquals(4, extractionList.size());
+    assertEquals(0, extractionList.get(0).getStart());
+    assertEquals(2, extractionList.get(0).getEnd());
+    assertEquals(3, extractionList.get(1).getStart());
+    assertEquals(5, extractionList.get(1).getEnd());
+    assertEquals(5, extractionList.get(2).getStart());
+    assertEquals(7, extractionList.get(2).getEnd());
+    assertEquals(8, extractionList.get(3).getStart());
+    assertEquals(10, extractionList.get(3).getEnd());
+
+    assertEquals(MockImmutableAccessLogElementMatcher.ELEMENT, extractionList.get(0).getAccessLogElement());
+    assertEquals(MockImmutableAccessLogElementMatcher.ELEMENT, extractionList.get(1).getAccessLogElement());
+    assertEquals(MockImmutableAccessLogElementMatcher.ELEMENT, extractionList.get(2).getAccessLogElement());
+    assertEquals(MockImmutableAccessLogElementMatcher.ELEMENT, extractionList.get(3).getAccessLogElement());
+  }
+
+  @Test
+  public void testExtractElementPlaceHolderOnNoMatch() {
+    final String rawPattern = "%p %r%{PATTERN}tcs-status";
+    List<AccessLogElementExtraction> extractionList = MATCHER.extractElementPlaceholder(rawPattern);
+
+    assertEquals(0, extractionList.size());
+  }
+
+  public static class MockImmutableAccessLogElementMatcher extends ImmutableAccessLogElementMatcher {
+    public static final AccessLogElement ELEMENT = Mockito.mock(AccessLogElement.class);
+
+    public static final String PLACEHOLDER_PATTERN = "%m";
+
+    @Override
+    protected AccessLogElement getAccessLogElement() {
+      return ELEMENT;
+    }
+
+    @Override
+    public List<AccessLogElementExtraction> extractElementPlaceholder(String rawPattern) {
+      List<AccessLogElementExtraction> extractionList = new ArrayList<>();
+      matchElementPlaceholder(rawPattern, PLACEHOLDER_PATTERN, extractionList);
+
+      return extractionList;
+    }
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/LocalHostMatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/LocalHostMatcherTest.java
new file mode 100644
index 000000000..ca9221c2a
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/LocalHostMatcherTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.LocalHostElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+
+public class LocalHostMatcherTest {
+  private static final LocalHostMatcher MATCHER = new LocalHostMatcher();
+
+  private static final String RAW_PATTERN = "%v %h %{PATTERN}t %v%v %H %v";
+
+  @Test
+  public void testExtractElementPlaceHolder() {
+    List<AccessLogElementExtraction> extractionList = MATCHER.extractElementPlaceholder(RAW_PATTERN);
+
+    assertEquals(4, extractionList.size());
+    assertEquals(0, extractionList.get(0).getStart());
+    assertEquals(2, extractionList.get(0).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(0).getAccessLogElement());
+    assertEquals(18, extractionList.get(1).getStart());
+    assertEquals(20, extractionList.get(1).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(1).getAccessLogElement());
+    assertEquals(20, extractionList.get(2).getStart());
+    assertEquals(22, extractionList.get(2).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(2).getAccessLogElement());
+    assertEquals(26, extractionList.get(3).getStart());
+    assertEquals(28, extractionList.get(3).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(3).getAccessLogElement());
+  }
+
+  @Test
+  public void testGetPlaceholderPattern() {
+    assertEquals("%v", MATCHER.getPlaceholderPattern());
+  }
+
+  @Test
+  public void getAccessLogElement() {
+    assertTrue(LocalHostElement.class.equals(MATCHER.getAccessLogElement().getClass()));
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/LocalPortMatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/LocalPortMatcherTest.java
new file mode 100644
index 000000000..41ce53433
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/LocalPortMatcherTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.LocalPortElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+
+public class LocalPortMatcherTest {
+  private static final LocalPortMatcher MATCHER = new LocalPortMatcher();
+
+  private static final String RAW_PATTERN = "%p %h %{PATTERN}t %p%p %H %p";
+
+  @Test
+  public void testExtractElementPlaceHolder() {
+    List<AccessLogElementExtraction> extractionList = MATCHER.extractElementPlaceholder(RAW_PATTERN);
+
+    assertEquals(4, extractionList.size());
+    assertEquals(0, extractionList.get(0).getStart());
+    assertEquals(2, extractionList.get(0).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(0).getAccessLogElement());
+    assertEquals(18, extractionList.get(1).getStart());
+    assertEquals(20, extractionList.get(1).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(1).getAccessLogElement());
+    assertEquals(20, extractionList.get(2).getStart());
+    assertEquals(22, extractionList.get(2).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(2).getAccessLogElement());
+    assertEquals(26, extractionList.get(3).getStart());
+    assertEquals(28, extractionList.get(3).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(3).getAccessLogElement());
+  }
+
+  @Test
+  public void testGetPlaceholderPattern() {
+    assertEquals("%p", MATCHER.getPlaceholderPattern());
+  }
+
+  @Test
+  public void getAccessLogElement() {
+    assertTrue(LocalPortElement.class.equals(MATCHER.getAccessLogElement().getClass()));
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/MethodMatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/MethodMatcherTest.java
new file mode 100644
index 000000000..3783eb2e2
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/MethodMatcherTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.impl.DefaultAccessLogPatternParser;
+
+public class MethodMatcherTest {
+  private static final MethodMatcher MATCHER = new MethodMatcher();
+
+  private static final String RAW_PATTERN = "cs-method %s cs-method %T %m";
+
+  @Test
+  public void extractElementPlaceHolder() {
+    List<AccessLogElementExtraction> extractionList = MATCHER.extractElementPlaceholder(RAW_PATTERN);
+    Collections.sort(extractionList, DefaultAccessLogPatternParser.ACCESS_LOG_ELEMENT_EXTRACTION_COMPARATOR);
+    assertEquals(3, extractionList.size());
+    assertEquals(0, extractionList.get(0).getStart());
+    assertEquals(9, extractionList.get(0).getEnd());
+    assertEquals(13, extractionList.get(1).getStart());
+    assertEquals(22, extractionList.get(1).getEnd());
+    assertEquals(26, extractionList.get(2).getStart());
+    assertEquals(28, extractionList.get(2).getEnd());
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/QueryOnlyMatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/QueryOnlyMatcherTest.java
new file mode 100644
index 000000000..4f50b8651
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/QueryOnlyMatcherTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.QueryOnlyElement;
+
+public class QueryOnlyMatcherTest {
+
+  public static final QueryOnlyMatcher MATCHER = new QueryOnlyMatcher();
+
+  @Test
+  public void getPlaceholderPatterns() {
+    String[] patterns = MATCHER.getPlaceholderPatterns();
+
+    assertEquals(2, patterns.length);
+    assertEquals("%q", patterns[0]);
+    assertEquals("cs-uri-query", patterns[1]);
+  }
+
+  @Test
+  public void getAccessLogElement() {
+    assertEquals(QueryOnlyElement.class, MATCHER.getAccessLogElement().getClass());
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/RemoteHostMatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/RemoteHostMatcherTest.java
new file mode 100644
index 000000000..cbcd65282
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/RemoteHostMatcherTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.RemoteHostElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+
+public class RemoteHostMatcherTest {
+  private static final RemoteHostMatcher MATCHER = new RemoteHostMatcher();
+
+  private static final String RAW_PATTERN = "%h %h %{PATTERN}t %h%h %H %h";
+
+  @Test
+  public void testExtractElementPlaceHolder() {
+    List<AccessLogElementExtraction> extractionList = MATCHER.extractElementPlaceholder(RAW_PATTERN);
+
+    assertEquals(5, extractionList.size());
+    assertEquals(0, extractionList.get(0).getStart());
+    assertEquals(2, extractionList.get(0).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(0).getAccessLogElement());
+    assertEquals(3, extractionList.get(1).getStart());
+    assertEquals(5, extractionList.get(1).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(1).getAccessLogElement());
+    assertEquals(18, extractionList.get(2).getStart());
+    assertEquals(20, extractionList.get(2).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(2).getAccessLogElement());
+    assertEquals(20, extractionList.get(3).getStart());
+    assertEquals(22, extractionList.get(3).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(3).getAccessLogElement());
+    assertEquals(26, extractionList.get(4).getStart());
+    assertEquals(28, extractionList.get(4).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(4).getAccessLogElement());
+  }
+
+  @Test
+  public void testGetPlaceholderPattern() {
+    assertEquals("%h", MATCHER.getPlaceholderPattern());
+  }
+
+  @Test
+  public void getAccessLogElement() {
+    assertTrue(RemoteHostElement.class.equals(MATCHER.getAccessLogElement().getClass()));
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/RequestHeaderElementMatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/RequestHeaderElementMatcherTest.java
new file mode 100644
index 000000000..efe8a454d
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/RequestHeaderElementMatcherTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.RequestHeaderElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+
+public class RequestHeaderElementMatcherTest {
+  private static final RequestHeaderElementMatcher MATCHER = new RequestHeaderElementMatcher();
+
+  @Test
+  public void extractElementPlaceholder() {
+    List<AccessLogElementExtraction> extractionList = MATCHER
+        .extractElementPlaceholder("%{header0}i %h %{yyyyMMdd HH:mm:ss zzz}t %{header1}i %b%b %H %{header2}i");
+
+    assertEquals(3, extractionList.size());
+    assertEquals(0, extractionList.get(0).getStart());
+    assertEquals(11, extractionList.get(0).getEnd());
+    assertEquals(41, extractionList.get(1).getStart());
+    assertEquals(52, extractionList.get(1).getEnd());
+    assertEquals(61, extractionList.get(2).getStart());
+    assertEquals(72, extractionList.get(2).getEnd());
+
+    assertEquals(RequestHeaderElement.class, extractionList.get(0).getAccessLogElement().getClass());
+    assertEquals(RequestHeaderElement.class, extractionList.get(1).getAccessLogElement().getClass());
+    assertEquals(RequestHeaderElement.class, extractionList.get(2).getAccessLogElement().getClass());
+
+    assertEquals("header0",
+        ((RequestHeaderElement) (extractionList.get(0).getAccessLogElement())).getIdentifier());
+    assertEquals("header1",
+        ((RequestHeaderElement) (extractionList.get(1).getAccessLogElement())).getIdentifier());
+    assertEquals("header2",
+        ((RequestHeaderElement) (extractionList.get(2).getAccessLogElement())).getIdentifier());
+  }
+
+  @Test
+  public void extractElementPlaceholderOnNotMatched() {
+    List<AccessLogElementExtraction> extractionList = MATCHER
+        .extractElementPlaceholder("%{header0}o %h %{yyyyMMdd HH:mm:ss zzz}t %{header1}o %b%b %H %{header2}o");
+
+    assertEquals(0, extractionList.size());
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/ResponseHeaderElementMatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/ResponseHeaderElementMatcherTest.java
new file mode 100644
index 000000000..984c72e08
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/ResponseHeaderElementMatcherTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.ResponseHeaderElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+
+public class ResponseHeaderElementMatcherTest {
+
+  private static final ResponseHeaderElementMatcher MATCHER = new ResponseHeaderElementMatcher();
+
+  @Test
+  public void extractElementPlaceholder() {
+    List<AccessLogElementExtraction> extractionList = MATCHER
+        .extractElementPlaceholder("%{header0}o %h %{yyyyMMdd HH:mm:ss zzz}t %{header1}o %b%b %H %{header2}o");
+
+    assertEquals(3, extractionList.size());
+    assertEquals(0, extractionList.get(0).getStart());
+    assertEquals(11, extractionList.get(0).getEnd());
+    assertEquals(41, extractionList.get(1).getStart());
+    assertEquals(52, extractionList.get(1).getEnd());
+    assertEquals(61, extractionList.get(2).getStart());
+    assertEquals(72, extractionList.get(2).getEnd());
+
+    assertEquals(ResponseHeaderElement.class, extractionList.get(0).getAccessLogElement().getClass());
+    assertEquals(ResponseHeaderElement.class, extractionList.get(1).getAccessLogElement().getClass());
+    assertEquals(ResponseHeaderElement.class, extractionList.get(2).getAccessLogElement().getClass());
+
+    assertEquals("header0",
+        ((ResponseHeaderElement) (extractionList.get(0).getAccessLogElement())).getIdentifier());
+    assertEquals("header1",
+        ((ResponseHeaderElement) (extractionList.get(1).getAccessLogElement())).getIdentifier());
+    assertEquals("header2",
+        ((ResponseHeaderElement) (extractionList.get(2).getAccessLogElement())).getIdentifier());
+  }
+
+  @Test
+  public void extractElementPlaceholderOnNotMatched() {
+    List<AccessLogElementExtraction> extractionList = MATCHER
+        .extractElementPlaceholder("%{header0}i %h %{yyyyMMdd HH:mm:ss zzz}t %{header1}i %b%b %H %{header2}i");
+
+    assertEquals(0, extractionList.size());
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/StatusMatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/StatusMatcherTest.java
new file mode 100644
index 000000000..149fa12cc
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/StatusMatcherTest.java
@@ -0,0 +1,41 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.StatusElement;
+
+public class StatusMatcherTest {
+  private static final StatusMatcher MATCHER = new StatusMatcher();
+
+  @Test
+  public void getPlaceholderPatterns() {
+    String[] patterns = MATCHER.getPlaceholderPatterns();
+    assertEquals(2, patterns.length);
+    assertEquals("%s", patterns[0]);
+    assertEquals("cs-status", patterns[1]);
+  }
+
+  @Test
+  public void getAccessLogElement() {
+    assertEquals(StatusElement.class, MATCHER.getAccessLogElement().getClass());
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/UriPathIncludeQueryMatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/UriPathIncludeQueryMatcherTest.java
new file mode 100644
index 000000000..694952c93
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/UriPathIncludeQueryMatcherTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.UriPathIncludeQueryElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+
+public class UriPathIncludeQueryMatcherTest {
+  private static final UriPathIncludeQueryMatcher MATCHER = new UriPathIncludeQueryMatcher();
+
+  private static final String RAW_PATTERN = "cs-uri %h %{PATTERN}t cs-urics-uri %H cs-uri-query cs-uri";
+
+  @Test
+  public void testExtractElementPlaceHolder() {
+    List<AccessLogElementExtraction> extractionList = MATCHER.extractElementPlaceholder(RAW_PATTERN);
+
+    assertEquals(4, extractionList.size());
+    assertEquals(0, extractionList.get(0).getStart());
+    assertEquals(6, extractionList.get(0).getEnd());
+    assertEquals(UriPathIncludeQueryElement.class, extractionList.get(0).getAccessLogElement().getClass());
+    assertEquals(22, extractionList.get(1).getStart());
+    assertEquals(28, extractionList.get(1).getEnd());
+    assertEquals(UriPathIncludeQueryElement.class, extractionList.get(1).getAccessLogElement().getClass());
+    assertEquals(28, extractionList.get(2).getStart());
+    assertEquals(34, extractionList.get(2).getEnd());
+    assertEquals(UriPathIncludeQueryElement.class, extractionList.get(2).getAccessLogElement().getClass());
+    assertEquals(51, extractionList.get(3).getStart());
+    assertEquals(57, extractionList.get(3).getEnd());
+    assertEquals(UriPathIncludeQueryElement.class, extractionList.get(3).getAccessLogElement().getClass());
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/UriPathOnlyMatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/UriPathOnlyMatcherTest.java
new file mode 100644
index 000000000..cce5e861c
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/UriPathOnlyMatcherTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.UriPathOnlyElement;
+
+public class UriPathOnlyMatcherTest {
+
+  public static final UriPathOnlyMatcher MATCHER = new UriPathOnlyMatcher();
+
+  @Test
+  public void getPlaceholderPatterns() {
+    String[] patterns = MATCHER.getPlaceholderPatterns();
+
+    assertEquals(2, patterns.length);
+    assertEquals("%U", patterns[0]);
+    assertEquals("cs-uri-stem", patterns[1]);
+  }
+
+  @Test
+  public void getAccessLogElement() {
+    assertEquals(UriPathOnlyElement.class, MATCHER.getAccessLogElement().getClass());
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/VersionOrProtocolMatcherTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/VersionOrProtocolMatcherTest.java
new file mode 100644
index 000000000..8460401f9
--- /dev/null
+++ b/transports/transport-rest/transport-rest-vertx/src/test/java/io/servicecomb/transport/rest/vertx/accesslog/parser/matcher/impl/VersionOrProtocolMatcherTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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 io.servicecomb.transport.rest.vertx.accesslog.parser.matcher.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import io.servicecomb.transport.rest.vertx.accesslog.element.impl.VersionOrProtocolElement;
+import io.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogElementExtraction;
+
+public class VersionOrProtocolMatcherTest {
+  private static final VersionOrProtocolMatcher MATCHER = new VersionOrProtocolMatcher();
+
+  private static final String RAW_PATTERN = "%H %h %{PATTERN}t %H%H %H %H";
+
+  @Test
+  public void testExtractElementPlaceHolder() {
+    List<AccessLogElementExtraction> extractionList = MATCHER.extractElementPlaceholder(RAW_PATTERN);
+
+    assertEquals(5, extractionList.size());
+    assertEquals(0, extractionList.get(0).getStart());
+    assertEquals(2, extractionList.get(0).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(0).getAccessLogElement());
+    assertEquals(18, extractionList.get(1).getStart());
+    assertEquals(20, extractionList.get(1).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(1).getAccessLogElement());
+    assertEquals(20, extractionList.get(2).getStart());
+    assertEquals(22, extractionList.get(2).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(2).getAccessLogElement());
+    assertEquals(23, extractionList.get(3).getStart());
+    assertEquals(25, extractionList.get(3).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(3).getAccessLogElement());
+    assertEquals(26, extractionList.get(4).getStart());
+    assertEquals(28, extractionList.get(4).getEnd());
+    assertEquals(MATCHER.getAccessLogElement(), extractionList.get(4).getAccessLogElement());
+  }
+
+  @Test
+  public void testGetPlaceholderPattern() {
+    assertEquals("%H", MATCHER.getPlaceholderPattern());
+  }
+
+  @Test
+  public void getAccessLogElement() {
+    assertTrue(VersionOrProtocolElement.class.equals(MATCHER.getAccessLogElement().getClass()));
+  }
+}
\ No newline at end of file


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services