You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2019/03/12 23:07:53 UTC

[incubator-skywalking] branch master updated: Customize Enhance code of plugin (#2300)

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

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-skywalking.git


The following commit(s) were added to refs/heads/master by this push:
     new 8c3b951  Customize Enhance code of plugin (#2300)
8c3b951 is described below

commit 8c3b951785f4d98cd03f4f10d33299424c21a300
Author: 于玉桔 <76...@qq.com>
AuthorDate: Wed Mar 13 07:07:45 2019 +0800

    Customize Enhance code of plugin (#2300)
    
    * Submit custom enhancement kernel code for the first time.
    
    * Submit the code again.
    
    * Optimize ClassUtil code.
    
    * Submit custom enhancement plugin code for the first time.
    
    * To fix CI issue.
    
    * To fix CI header Tmp issue
    
    * To fix CI Tmp header issue
    
    * Customize plugin code submission
    
    * Add md file.
    
    * Fix some bug.
    
    * Fix ci issue
    
    * Fix md desc
    
    * Fix unapproved license
    
    * Fix bug
    
    * Fix collection bug.
    
    * Fix java8 pair ref issue
    
    * Fix CI issue.
    
    * Add more detail for expression.
    
    * Fix review issue
    
    * Fix review issue 2
    
    * Fix review code issue 2
    
    * Fix md issue
    
    * Fix bug and op desc md.
    
    * Update customize-enhance-trace.md
    
    * Update customize-enhance-trace.md
    
    * FIx code review issue.
---
 .../skywalking/apm/agent/core/conf/Config.java     |  15 +
 .../apm/agent/core/plugin/DynamicPluginLoader.java |  48 +++
 .../apm/agent/core/plugin/PluginBootstrap.java     |   3 +-
 .../core/plugin/loader/InstrumentationLoader.java  |  34 +++
 .../skywalking/apm/agent/core/util/MethodUtil.java |  45 +++
 .../apm/agent/core/util/MethodUtilTest.java        |  37 +++
 .../trace/TraceAnnotationMethodInterceptor.java    |  16 +-
 .../customize-enhance-plugin/pom.xml               |  33 +++
 .../customize/conf/CustomizeConfiguration.java     | 330 +++++++++++++++++++++
 .../plugin/customize/conf/MethodConfiguration.java | 150 ++++++++++
 .../apm/plugin/customize/constants/Constants.java  |  84 ++++++
 .../define/CustomizeInstanceInstrumentation.java   |  80 +++++
 .../define/CustomizeStaticInstrumentation.java     |  73 +++++
 .../interceptor/BaseInterceptorMethods.java        | 100 +++++++
 .../interceptor/CustomizeInstanceInterceptor.java  |  47 +++
 .../interceptor/CustomizeStaticInterceptor.java    |  46 +++
 .../loader/CustomizeInstrumentationLoader.java     |  64 ++++
 .../plugin/customize/util/CustomizeExpression.java | 114 +++++++
 .../apm/plugin/customize/util/CustomizeUtil.java   |  72 +++++
 ....agent.core.plugin.loader.InstrumentationLoader |  19 ++
 .../customize/util/CustomizeExpressionTest.java    | 173 +++++++++++
 .../plugin/customize/util/CustomizeUtilTest.java   |  40 +++
 apm-sniffer/optional-plugins/pom.xml               |   1 +
 .../java-agent/Customize-enhance-trace.md          |  72 +++++
 docs/en/setup/service-agent/java-agent/README.md   |   1 +
 25 files changed, 1682 insertions(+), 15 deletions(-)

diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java
index 1791eb6..f973f50 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java
@@ -23,6 +23,9 @@ import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
 import org.apache.skywalking.apm.agent.core.logging.core.LogLevel;
 import org.apache.skywalking.apm.agent.core.logging.core.WriterFactory;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * This is the core config in sniffer agent.
  *
@@ -163,5 +166,17 @@ public class Config {
              */
             public static boolean TRACE_DSL = false;
         }
+        public static class Customize {
+            /**
+             * Custom enhancement class configuration file path, recommended to use an absolute path.
+             */
+            public static String ENHANCE_FILE = "";
+
+            /**
+             * Some information after custom enhancements, this configuration is used by the custom enhancement plugin.
+             * And using Map CONTEXT for avoiding classloader isolation issue.
+             */
+            public static Map<String, Object> CONTEXT = new HashMap<String, Object>();
+        }
     }
 }
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/DynamicPluginLoader.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/DynamicPluginLoader.java
new file mode 100755
index 0000000..d8f522b
--- /dev/null
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/DynamicPluginLoader.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.agent.core.plugin;
+
+import org.apache.skywalking.apm.agent.core.plugin.loader.AgentClassLoader;
+import org.apache.skywalking.apm.agent.core.plugin.loader.InstrumentationLoader;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ServiceLoader;
+
+/**
+ * The plugin can be inserted into the kernel by implementing this spi return PluginDefine list.
+ *
+ * @author zhaoyuguang
+ */
+
+public enum DynamicPluginLoader {
+
+    INSTANCE;
+
+    public List<AbstractClassEnhancePluginDefine> load(AgentClassLoader classLoader) {
+        List<AbstractClassEnhancePluginDefine> all = new ArrayList<AbstractClassEnhancePluginDefine>();
+        for (InstrumentationLoader instrumentationLoader : ServiceLoader.load(InstrumentationLoader.class, classLoader)) {
+            List<AbstractClassEnhancePluginDefine> plugins = instrumentationLoader.load(classLoader);
+            if (plugins != null && !plugins.isEmpty()) {
+                all.addAll(plugins);
+            }
+        }
+        return all;
+    }
+}
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/PluginBootstrap.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/PluginBootstrap.java
index c663b08..73dc34f 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/PluginBootstrap.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/PluginBootstrap.java
@@ -16,7 +16,6 @@
  *
  */
 
-
 package org.apache.skywalking.apm.agent.core.plugin;
 
 import java.net.URL;
@@ -78,6 +77,8 @@ public class PluginBootstrap {
             }
         }
 
+        plugins.addAll(DynamicPluginLoader.INSTANCE.load(AgentClassLoader.getDefault()));
+
         return plugins;
 
     }
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/loader/InstrumentationLoader.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/loader/InstrumentationLoader.java
new file mode 100755
index 0000000..05614c9
--- /dev/null
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/loader/InstrumentationLoader.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.agent.core.plugin.loader;
+
+import org.apache.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine;
+
+import java.util.List;
+
+/**
+ * the spi of the InstrumentationLoader.
+ *
+ * @author : zhaoyuguang
+ */
+
+public interface InstrumentationLoader {
+
+    List<AbstractClassEnhancePluginDefine> load(AgentClassLoader classLoader);
+}
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/util/MethodUtil.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/util/MethodUtil.java
new file mode 100644
index 0000000..8026044
--- /dev/null
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/util/MethodUtil.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 org.apache.skywalking.apm.agent.core.util;
+
+import java.lang.reflect.Method;
+
+/**
+ * According to the input parameter,
+ * return the OperationName for the span record,
+ * It can determine the unique method
+ *
+ * @author zhaoyuguang
+ */
+
+public class MethodUtil {
+
+    public static String generateOperationName(Method method) {
+        StringBuilder operationName = new StringBuilder(method.getDeclaringClass().getName() + "." + method.getName() + "(");
+        Class<?>[] parameterTypes = method.getParameterTypes();
+        for (int i = 0; i < parameterTypes.length; i++) {
+            operationName.append(parameterTypes[i].getName());
+            if (i < (parameterTypes.length - 1)) {
+                operationName.append(",");
+            }
+        }
+        operationName.append(")");
+        return operationName.toString();
+    }
+}
diff --git a/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/util/MethodUtilTest.java b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/util/MethodUtilTest.java
new file mode 100644
index 0000000..87fa84d
--- /dev/null
+++ b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/util/MethodUtilTest.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 org.apache.skywalking.apm.agent.core.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.lang.reflect.Method;
+
+/**
+ * @author zhaoyuguang
+ */
+
+public class MethodUtilTest {
+
+    @Test
+    public void testClassForName() throws NoSuchMethodException {
+        Assert.assertTrue(MethodUtil.generateOperationName(MethodUtil.class.getMethod("generateOperationName", Method.class))
+                .equals("org.apache.skywalking.apm.agent.core.util.MethodUtil.generateOperationName(java.lang.reflect.Method)"));
+    }
+}
diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-trace-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/trace/TraceAnnotationMethodInterceptor.java b/apm-sniffer/apm-toolkit-activation/apm-toolkit-trace-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/trace/TraceAnnotationMethodInterceptor.java
index dd5d992..d96f5ed 100644
--- a/apm-sniffer/apm-toolkit-activation/apm-toolkit-trace-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/trace/TraceAnnotationMethodInterceptor.java
+++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-trace-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/trace/TraceAnnotationMethodInterceptor.java
@@ -25,6 +25,7 @@ import org.apache.skywalking.apm.agent.core.context.ContextManager;
 import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
 import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
 import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.agent.core.util.MethodUtil;
 
 /**
  * {@link TraceAnnotationMethodInterceptor} create a local span and set the operation name which fetch from
@@ -40,25 +41,12 @@ public class TraceAnnotationMethodInterceptor implements InstanceMethodsAroundIn
         Trace trace = method.getAnnotation(Trace.class);
         String operationName = trace.operationName();
         if (operationName.length() == 0) {
-            operationName = generateOperationName(method);
+            operationName = MethodUtil.generateOperationName(method);
         }
 
         ContextManager.createLocalSpan(operationName);
     }
 
-    private String generateOperationName(Method method) {
-        StringBuilder operationName = new StringBuilder(method.getDeclaringClass().getName() + "." + method.getName() + "(");
-        Class<?>[] parameterTypes = method.getParameterTypes();
-        for (int i = 0; i < parameterTypes.length; i++) {
-            operationName.append(parameterTypes[i].getName());
-            if (i < (parameterTypes.length - 1)) {
-                operationName.append(",");
-            }
-        }
-        operationName.append(")");
-        return operationName.toString();
-    }
-
     @Override
     public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
         Object ret) throws Throwable {
diff --git a/apm-sniffer/optional-plugins/customize-enhance-plugin/pom.xml b/apm-sniffer/optional-plugins/customize-enhance-plugin/pom.xml
new file mode 100644
index 0000000..197bb85
--- /dev/null
+++ b/apm-sniffer/optional-plugins/customize-enhance-plugin/pom.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  ~
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.apache.skywalking</groupId>
+        <artifactId>optional-plugins</artifactId>
+        <version>6.1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>apm-customize-enhance-plugin</artifactId>
+    <name>customize-enhance-plugin</name>
+    <packaging>jar</packaging>
+</project>
\ No newline at end of file
diff --git a/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/conf/CustomizeConfiguration.java b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/conf/CustomizeConfiguration.java
new file mode 100644
index 0000000..24c9c50
--- /dev/null
+++ b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/conf/CustomizeConfiguration.java
@@ -0,0 +1,330 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.customize.conf;
+
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.conf.Config;
+import org.apache.skywalking.apm.agent.core.logging.api.ILog;
+import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine;
+import org.apache.skywalking.apm.plugin.customize.constants.Constants;
+import org.apache.skywalking.apm.plugin.customize.util.CustomizeUtil;
+import org.apache.skywalking.apm.agent.core.util.MethodUtil;
+import org.apache.skywalking.apm.util.StringUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.*;
+
+import static net.bytebuddy.matcher.ElementMatchers.*;
+import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
+
+/**
+ * The CustomizeConfiguration class is the core class for
+ * parsing custom enhanced configuration files,
+ * parsing configuration files,
+ * and converting content into plugins for loading into the kernel.
+ *
+ * @author zhaoyuguang
+ */
+
+public enum CustomizeConfiguration {
+
+    INSTANCE;
+
+    private static final ILog logger = LogManager.getLogger(CustomizeConfiguration.class);
+
+    /**
+     * The load method is resolver configuration file,
+     * and parse it to kernel.
+     */
+    public void load() {
+        try {
+            parse(resolver());
+        } catch (Exception e) {
+            logger.error("CustomizeConfiguration load fail", e);
+        }
+    }
+
+    /**
+     * Resolver custom enhancement file method total entry.
+     *
+     * @return configurations is a bridge resolver method and parse method,
+     * mainly used for decoupling.
+     * @throws ParserConfigurationException link {@link ParserConfigurationException}
+     * @throws IOException                  link {@link IOException}
+     * @throws SAXException                 link {@link SAXException}
+     */
+    private List<Map<String, Object>> resolver() throws ParserConfigurationException, IOException, SAXException {
+        List<Map<String, Object>> customizeMethods = new ArrayList<Map<String, Object>>();
+        File file = new File(Config.Plugin.Customize.ENHANCE_FILE);
+        if (file.exists() && file.isFile()) {
+            NodeList classNodeList = resolverFileClassDesc(file);
+            resolverClassNodeList(classNodeList, customizeMethods);
+        }
+        return customizeMethods;
+    }
+
+    /**
+     * According to the custom enhancement file, return lass description nodes in the file.
+     *
+     * @param file the custom enhanced files
+     * @return all class description nodes
+     * @throws ParserConfigurationException link {@link ParserConfigurationException}
+     * @throws IOException                  link {@link IOException}
+     * @throws SAXException                 link {@link SAXException}
+     */
+    private NodeList resolverFileClassDesc(File file) throws ParserConfigurationException, IOException, SAXException {
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder builder = factory.newDocumentBuilder();
+        Document doc = builder.parse(file);
+        return doc.getElementsByTagName(Constants.XML_ELEMENT_CLASS);
+    }
+
+    /**
+     * Resolver all class description nodes to customizeMethods.
+     *
+     * @param classNodeList    all class description nodes.
+     * @param customizeMethods of memory address, the element {@link MethodConfiguration}.
+     */
+    private void resolverClassNodeList(NodeList classNodeList, List<Map<String, Object>> customizeMethods) {
+        for (int ec = 0; ec < classNodeList.getLength(); ec++) {
+            Node classDesc = classNodeList.item(ec);
+            NodeList methodNodeList = classDesc.getChildNodes();
+            for (int ms = 0; ms < methodNodeList.getLength(); ms++) {
+                Node methodDesc = methodNodeList.item(ms);
+                if (methodDesc.getNodeType() == Node.ELEMENT_NODE) {
+                    String className = classDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_CLASS_NAME).getNodeValue();
+                    Map<String, Object> configuration = resolverMethodNodeDesc(className, methodDesc);
+                    if (configuration != null) {
+                        customizeMethods.add(configuration);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Resolver according to the description of the method under the current class node.
+     *
+     * @param className  class name.
+     * @param methodDesc method node.
+     * @return configurations is a bridge resolver method and parse method,
+     * mainly used for decoupling.
+     */
+    private Map<String, Object> resolverMethodNodeDesc(String className, Node methodDesc) {
+        Map<String, Object> configuration = new HashMap<String, Object>();
+        if (methodDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_OPERATION_NAME) != null) {
+            MethodConfiguration.setOperationName(configuration, methodDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_OPERATION_NAME).getNodeValue());
+        }
+        if (methodDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_CLOSE_BEFORE_METHOD) != null) {
+            MethodConfiguration.setCloseBeforeMethod(configuration, Boolean.valueOf(methodDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_CLOSE_BEFORE_METHOD).getNodeValue()));
+        } else {
+            MethodConfiguration.setCloseBeforeMethod(configuration, false);
+        }
+        if (methodDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_CLOSE_AFTER_METHOD) != null) {
+            MethodConfiguration.setCloseAfterMethod(configuration, Boolean.valueOf(methodDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_CLOSE_AFTER_METHOD).getNodeValue()));
+        } else {
+            MethodConfiguration.setCloseAfterMethod(configuration, false);
+        }
+        if (methodDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_METHOD_IS_STATIC) != null) {
+            MethodConfiguration.setStatic(configuration, Boolean.valueOf(methodDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_METHOD_IS_STATIC).getNodeValue()));
+        }
+        setAdvancedField(configuration, methodDesc);
+        return resolverClassAndMethod(className,
+                methodDesc.getAttributes().getNamedItem(Constants.XML_ELEMENT_METHOD).getNodeValue(),
+                configuration);
+    }
+
+    /**
+     * Add some private properties of the Advanced method configuration.
+     *
+     * @param configuration {@link MethodConfiguration}.
+     * @param methodNode    method node.
+     */
+    private void setAdvancedField(Map<String, Object> configuration, Node methodNode) {
+        NodeList methodContents = methodNode.getChildNodes();
+        for (int mc = 0; mc < methodContents.getLength(); mc++) {
+            Node methodContentNode = methodContents.item(mc);
+            if (methodContentNode.getNodeType() == Node.ELEMENT_NODE) {
+                if (Constants.XML_ELEMENT_OPERATION_NAME_SUFFIX.equals(methodContentNode.getNodeName())) {
+                    MethodConfiguration.addOperationNameSuffixes(configuration, methodContentNode.getTextContent());
+                }
+                if (Constants.XML_ELEMENT_TAG.equals(methodContentNode.getNodeName())) {
+                    MethodConfiguration.addTag(configuration, methodContentNode.getAttributes().getNamedItem(Constants.XML_ELEMENT_KEY).getNodeValue(), methodContentNode.getTextContent());
+                }
+                if (Constants.XML_ELEMENT_LOG.equals(methodContentNode.getNodeName())) {
+                    MethodConfiguration.addLog(configuration, methodContentNode.getAttributes().getNamedItem(Constants.XML_ELEMENT_KEY).getNodeValue(), methodContentNode.getTextContent());
+                }
+            }
+        }
+    }
+
+    /**
+     * Parse class and method,
+     * if no error log is printed in this JVM, and return null.
+     * primitive desc impl by {@link CustomizeUtil}
+     * At the bottom, the default operation name is added.
+     *
+     * @param className     class name.
+     * @param methodDesc    method desc.
+     * @param configuration {@link MethodConfiguration}.
+     * @return configuration of method.
+     */
+    private Map<String, Object> resolverClassAndMethod(String className, String methodDesc, Map<String, Object> configuration) {
+        try {
+            int openParen = methodDesc.indexOf(Constants.LEFT_PARENTHESIS);
+            int closeParen = methodDesc.indexOf(Constants.RIGHT_PARENTHESIS);
+            String methodName = methodDesc.substring(0, openParen);
+            String[] arguments = methodDesc.substring(openParen + 1, closeParen).split(Constants.COMMA);
+            MethodConfiguration.setClz(configuration, className);
+            MethodConfiguration.setMethod(configuration, CustomizeUtil.generateOperationName(className, methodName, arguments));
+            MethodConfiguration.setMethodName(configuration, methodName);
+            MethodConfiguration.setArguments(configuration, StringUtil.isEmpty(arguments[0]) ? new String[0] : arguments);
+            if (StringUtil.isEmpty(MethodConfiguration.getOperationName(configuration))) {
+                MethodConfiguration.setOperationName(configuration, MethodConfiguration.getMethod(configuration));
+            }
+            return configuration;
+        } catch (Exception e) {
+            logger.error(e, "Failed to resolver, className is {}, methodDesc is {}.", className, methodDesc);
+        }
+        return null;
+    }
+
+    /**
+     * Put the plugin configuration into the kernel according to the configuration.
+     *
+     * @param configurations is a bridge resolver method and parse method,
+     *                       mainly used for decoupling.
+     */
+    private void parse(List<Map<String, Object>> configurations) {
+        init();
+        for (Map<String, Object> configuration : configurations) {
+            addContextMethodConfiguration(configuration);
+            addContextEnhanceClass(configuration);
+        }
+    }
+
+    /**
+     * In order to avoid the judgment of the useless null pointer exception.
+     */
+    private void init() {
+        Config.Plugin.Customize.CONTEXT.put(Constants.CONTEXT_METHOD_CONFIGURATIONS, new HashMap<String, Map<String, Object>>());
+        Config.Plugin.Customize.CONTEXT.put(Constants.CONTEXT_ENHANCE_CLASSES, new HashMap<String, ElementMatcher>());
+    }
+
+    /**
+     * The configuration of each method is put into the kernel.
+     *
+     * @param configuration {@link MethodConfiguration}.
+     */
+    private void addContextMethodConfiguration(Map<String, Object> configuration) {
+        getMethodConfigurations().put(MethodConfiguration.getMethod(configuration), configuration);
+    }
+
+
+    /**
+     * The private method for get the configuration of this method.
+     *
+     * @return all method configs.
+     */
+    @SuppressWarnings("unchecked")
+    private Map<String, Map<String, Object>> getMethodConfigurations() {
+        return (Map<String, Map<String, Object>>) Config.Plugin.Customize.CONTEXT.get(Constants.CONTEXT_METHOD_CONFIGURATIONS);
+    }
+
+    /**
+     * The configuration of each class is put into the kernel.
+     *
+     * @param configuration {@link MethodConfiguration}
+     */
+    private void addContextEnhanceClass(Map<String, Object> configuration) {
+        String key = CustomizeUtil.generateClassDesc(MethodConfiguration.getClz(configuration), MethodConfiguration.isStatic(configuration));
+        HashMap<String, ElementMatcher> enhanceClasses = getEnhanceClasses();
+        ElementMatcher matcher = enhanceClasses.get(key);
+        enhanceClasses.put(key, matcher == null ? parserMethodsMatcher(configuration) : ((ElementMatcher.Junction) matcher).or(parserMethodsMatcher(configuration)));
+    }
+
+    /**
+     * Parse each configuration to matcher.
+     *
+     * @param configuration {@link MethodConfiguration}.
+     * @return matcher {@link ElementMatcher}.
+     */
+    private ElementMatcher parserMethodsMatcher(Map<String, Object> configuration) {
+        String[] arguments = MethodConfiguration.getArguments(configuration);
+        ElementMatcher matcher = named(MethodConfiguration.getMethodName(configuration)).and(takesArguments(arguments.length));
+        if (arguments.length > 0) {
+            for (int i = 0; i < arguments.length; i++) {
+                matcher = ((ElementMatcher.Junction) matcher).and(
+                        CustomizeUtil.isJavaClass(arguments[i]) ?
+                                takesArgument(i, CustomizeUtil.getJavaClass(arguments[i])) :
+                                takesArgumentWithType(i, arguments[i]));
+            }
+        }
+        return matcher;
+    }
+
+    /**
+     * Get InterceptPoints, the input dimension is class and is static.
+     *
+     * @param enhanceClass Real enhancement class
+     * @param isStatic     Is it static, because static or not,
+     *                     logic is different in the SkyWalking kernel,
+     *                     so this dimension is abstracted out.
+     * @return all the interceptPoints.
+     */
+    public ElementMatcher getInterceptPoints(String enhanceClass, boolean isStatic) {
+        HashMap<String, ElementMatcher> enhanceClasses = getEnhanceClasses();
+        return enhanceClasses.get(CustomizeUtil.generateClassDesc(enhanceClass, isStatic));
+    }
+
+    /**
+     * Get all the instrumentation {@link ClassEnhancePluginDefine} that need custom enhancements.
+     *
+     * @return all the custom instrumentation.
+     */
+    public Set<String> getInstrumentations() {
+        HashMap<String, ElementMatcher> enhanceClasses = getEnhanceClasses();
+        return enhanceClasses.keySet();
+    }
+
+    /**
+     * Get all the private methods of interceptPoints that need custom enhancements.
+     *
+     * @return all config of the custom instrumentation.
+     */
+    @SuppressWarnings("unchecked")
+    private HashMap<String, ElementMatcher> getEnhanceClasses() {
+        return (HashMap<String, ElementMatcher>) Config.Plugin.Customize.CONTEXT.get(Constants.CONTEXT_ENHANCE_CLASSES);
+    }
+
+    public Map<String, Object> getConfiguration(Method method) {
+        return getMethodConfigurations().get(MethodUtil.generateOperationName(method));
+    }
+}
+
diff --git a/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/conf/MethodConfiguration.java b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/conf/MethodConfiguration.java
new file mode 100644
index 0000000..07c7442
--- /dev/null
+++ b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/conf/MethodConfiguration.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.customize.conf;
+
+import org.apache.skywalking.apm.plugin.customize.constants.Constants;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Default custom enhancement configuration.
+ *
+ * @author zhaoyuguang
+ */
+
+public class MethodConfiguration {
+
+    static String getMethod(Map<String, Object> configuration) {
+        return (String) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_METHOD);
+    }
+
+    static String getClz(Map<String, Object> configuration) {
+        return (String) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_CLZ);
+    }
+
+    static Boolean isStatic(Map<String, Object> configuration) {
+        return (Boolean) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_IS_STATIC);
+    }
+
+    static String getMethodName(Map<String, Object> configuration) {
+        return (String) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_METHOD_NAME);
+    }
+
+    static String[] getArguments(Map<String, Object> configuration) {
+        return (String[]) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_ARGUMENTS);
+    }
+
+    static void setOperationName(Map<String, Object> configuration, String operationName) {
+        configuration.put(Constants.CONFIGURATION_ATTRIBUTE_OPERATION_NAME, operationName);
+    }
+
+    static void setCloseBeforeMethod(Map<String, Object> configuration, Boolean closeBeforeMethod) {
+        configuration.put(Constants.CONFIGURATION_ATTRIBUTE_CLOSE_BEFORE_METHOD, closeBeforeMethod);
+    }
+
+    static void setCloseAfterMethod(Map<String, Object> configuration, Boolean closeAfterMethod) {
+        configuration.put(Constants.CONFIGURATION_ATTRIBUTE_CLOSE_AFTER_METHOD, closeAfterMethod);
+    }
+
+    static void setStatic(Map<String, Object> configuration, Boolean isStatic) {
+        configuration.put(Constants.CONFIGURATION_ATTRIBUTE_IS_STATIC, isStatic);
+    }
+
+    @SuppressWarnings("unchecked")
+    static void addOperationNameSuffixes(Map<String, Object> configuration, String suffix) {
+        List<String> suffixes = (List<String>) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_OPERATION_NAME_SUFFIXES);
+        if (suffixes == null) {
+            suffixes = new ArrayList<String>();
+            suffixes.add(suffix);
+            configuration.put(Constants.CONFIGURATION_ATTRIBUTE_OPERATION_NAME_SUFFIXES, suffixes);
+        } else {
+            suffixes.add(suffix);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    static void addTag(Map<String, Object> configuration, String key, String value) {
+        Map<String, String> tags = (Map<String, String>) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_TAGS);
+        if (tags == null) {
+            tags = new HashMap<String, String>();
+            tags.put(key, value);
+            configuration.put(Constants.CONFIGURATION_ATTRIBUTE_TAGS, tags);
+        } else {
+            tags.put(key, value);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    static void addLog(Map<String, Object> configuration, String key, String value) {
+        Map<String, String> logs = (Map<String, String>) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_LOGS);
+        if (logs == null) {
+            logs = new HashMap<String, String>();
+            logs.put(key, value);
+            configuration.put(Constants.CONFIGURATION_ATTRIBUTE_LOGS, logs);
+        } else {
+            logs.put(key, value);
+        }
+    }
+
+    static void setClz(Map<String, Object> configuration, String className) {
+        configuration.put(Constants.CONFIGURATION_ATTRIBUTE_CLZ, className);
+    }
+
+    static void setMethod(Map<String, Object> configuration, String method) {
+        configuration.put(Constants.CONFIGURATION_ATTRIBUTE_METHOD, method);
+    }
+
+    static void setMethodName(Map<String, Object> configuration, String methodName) {
+        configuration.put(Constants.CONFIGURATION_ATTRIBUTE_METHOD_NAME, methodName);
+    }
+
+    static void setArguments(Map<String, Object> configuration, String[] arguments) {
+        configuration.put(Constants.CONFIGURATION_ATTRIBUTE_ARGUMENTS, arguments);
+    }
+
+    public static String getOperationName(Map<String, Object> configuration) {
+        return (String) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_OPERATION_NAME);
+    }
+
+    public static boolean isCloseBeforeMethod(Map<String, Object> configuration) {
+        return (Boolean) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_CLOSE_BEFORE_METHOD);
+    }
+
+    public static boolean isCloseAfterMethod(Map<String, Object> configuration) {
+        return (Boolean) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_CLOSE_AFTER_METHOD);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static Map<String, String> getTags(Map<String, Object> configuration) {
+        return (Map<String, String>) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_TAGS);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static Map<String, String> getLogs(Map<String, Object> configuration) {
+        return (Map<String, String>) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_LOGS);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static List<String> getOperationNameSuffixes(Map<String, Object> configuration) {
+        return (List<String>) configuration.get(Constants.CONFIGURATION_ATTRIBUTE_OPERATION_NAME_SUFFIXES);
+    }
+}
diff --git a/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/constants/Constants.java b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/constants/Constants.java
new file mode 100644
index 0000000..34fe8d9
--- /dev/null
+++ b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/constants/Constants.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 org.apache.skywalking.apm.plugin.customize.constants;
+
+/**
+ * The constant of customize enhance.
+ *
+ * @author zhaoyuguang
+ */
+
+public class Constants {
+
+    public static final String OPERATION_NAME_SEPARATOR = "/";
+
+    public static final String COMMA = ",";
+
+    public static final String LEFT_PARENTHESIS = "(";
+
+    public static final String RIGHT_PARENTHESIS = ")";
+
+    public static final String XML_ELEMENT_CLASS = "class";
+
+    public static final String XML_ELEMENT_CLASS_NAME = "class_name";
+
+    public static final String XML_ELEMENT_METHOD = "method";
+
+    public static final String XML_ELEMENT_METHOD_IS_STATIC = "static";
+
+    public static final String XML_ELEMENT_OPERATION_NAME = "operation_name";
+
+    public static final String XML_ELEMENT_CLOSE_BEFORE_METHOD = "close_before_method";
+
+    public static final String XML_ELEMENT_CLOSE_AFTER_METHOD = "close_after_method";
+
+    public static final String XML_ELEMENT_OPERATION_NAME_SUFFIX = "operation_name_suffix";
+
+    public static final String XML_ELEMENT_TAG = "tag";
+
+    public static final String XML_ELEMENT_LOG = "log";
+
+    public static final String XML_ELEMENT_KEY = "key";
+
+    public static final String CONTEXT_METHOD_CONFIGURATIONS = "CONTEXT_METHOD_CONFIGURATIONS";
+
+    public static final String CONTEXT_ENHANCE_CLASSES = "CONTEXT_ENHANCE_CLASSES";
+
+    public static final String CONFIGURATION_ATTRIBUTE_METHOD = "CONFIGURATION_ATTRIBUTE_METHOD";
+
+    public static final String CONFIGURATION_ATTRIBUTE_METHOD_NAME = "CONFIGURATION_ATTRIBUTE_METHOD_NAME";
+
+    public static final String CONFIGURATION_ATTRIBUTE_ARGUMENTS = "CONFIGURATION_ATTRIBUTE_ARGUMENTS";
+
+    public static final String CONFIGURATION_ATTRIBUTE_IS_STATIC = "CONFIGURATION_ATTRIBUTE_IS_STATIC";
+
+    public static final String CONFIGURATION_ATTRIBUTE_CLZ = "CONFIGURATION_ATTRIBUTE_CLZ";
+
+    public static final String CONFIGURATION_ATTRIBUTE_OPERATION_NAME = "CONFIGURATION_ATTRIBUTE_OPERATION_NAME";
+
+    public static final String CONFIGURATION_ATTRIBUTE_CLOSE_BEFORE_METHOD = "CONFIGURATION_ATTRIBUTE_CLOSE_BEFORE_METHOD";
+
+    public static final String CONFIGURATION_ATTRIBUTE_CLOSE_AFTER_METHOD = "CONFIGURATION_ATTRIBUTE_CLOSE_AFTER_METHOD";
+
+    public static final String CONFIGURATION_ATTRIBUTE_OPERATION_NAME_SUFFIXES = "CONFIGURATION_ATTRIBUTE_OPERATION_NAME_SUFFIXES";
+
+    public static final String CONFIGURATION_ATTRIBUTE_TAGS = "CONFIGURATION_ATTRIBUTE_TAGS";
+
+    public static final String CONFIGURATION_ATTRIBUTE_LOGS = "CONFIGURATION_ATTRIBUTE_LOGS";
+}
diff --git a/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/define/CustomizeInstanceInstrumentation.java b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/define/CustomizeInstanceInstrumentation.java
new file mode 100644
index 0000000..53931b4
--- /dev/null
+++ b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/define/CustomizeInstanceInstrumentation.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.customize.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+import org.apache.skywalking.apm.plugin.customize.conf.CustomizeConfiguration;
+
+/**
+ * The instance of customize instrumentation.
+ *
+ * @author zhaoyuguang
+ */
+
+public class CustomizeInstanceInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+    private String enhanceClass;
+
+    public CustomizeInstanceInstrumentation(String enhanceClass) {
+        this.enhanceClass = enhanceClass;
+    }
+
+    @Override
+    protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+        return new ConstructorInterceptPoint[0];
+    }
+
+    @Override
+    protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+        final ElementMatcher matcher = CustomizeConfiguration.INSTANCE.getInterceptPoints(enhanceClass, false);
+        if (matcher == null) {
+            return new InstanceMethodsInterceptPoint[0];
+        } else {
+            return new InstanceMethodsInterceptPoint[]{
+                new InstanceMethodsInterceptPoint() {
+                    @Override
+                    public ElementMatcher<MethodDescription> getMethodsMatcher() {
+                        return matcher;
+                    }
+
+                    @Override
+                    public String getMethodsInterceptor() {
+                        return "org.apache.skywalking.apm.plugin.customize.interceptor.CustomizeInstanceInterceptor";
+                    }
+
+                    @Override
+                    public boolean isOverrideArgs() {
+                        return false;
+                    }
+                }
+            };
+        }
+    }
+
+    @Override
+    protected ClassMatch enhanceClass() {
+        return NameMatch.byName(enhanceClass);
+    }
+}
diff --git a/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/define/CustomizeStaticInstrumentation.java b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/define/CustomizeStaticInstrumentation.java
new file mode 100644
index 0000000..4fb09f1
--- /dev/null
+++ b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/define/CustomizeStaticInstrumentation.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 org.apache.skywalking.apm.plugin.customize.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassStaticMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+import org.apache.skywalking.apm.plugin.customize.conf.CustomizeConfiguration;
+
+/**
+ * The static of customize instrumentation.
+ *
+ * @author zhaoyuguang
+ */
+
+public class CustomizeStaticInstrumentation extends ClassStaticMethodsEnhancePluginDefine {
+    private String enhanceClass;
+
+    public CustomizeStaticInstrumentation(String enhanceClass) {
+        this.enhanceClass = enhanceClass;
+    }
+
+    @Override
+    protected StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
+        final ElementMatcher matcher = CustomizeConfiguration.INSTANCE.getInterceptPoints(enhanceClass, true);
+        if (matcher == null) {
+            return new StaticMethodsInterceptPoint[0];
+        } else {
+            return new StaticMethodsInterceptPoint[]{
+                new StaticMethodsInterceptPoint() {
+                    @Override
+                    public ElementMatcher<MethodDescription> getMethodsMatcher() {
+                        return matcher;
+                    }
+
+                    @Override
+                    public String getMethodsInterceptor() {
+                        return "org.apache.skywalking.apm.plugin.customize.interceptor.CustomizeStaticInterceptor";
+                    }
+
+                    @Override
+                    public boolean isOverrideArgs() {
+                        return false;
+                    }
+                }
+            };
+        }
+    }
+
+    @Override
+    protected ClassMatch enhanceClass() {
+        return NameMatch.byName(enhanceClass);
+    }
+}
diff --git a/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/interceptor/BaseInterceptorMethods.java b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/interceptor/BaseInterceptorMethods.java
new file mode 100644
index 0000000..691d44e
--- /dev/null
+++ b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/interceptor/BaseInterceptorMethods.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.customize.interceptor;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.plugin.customize.conf.CustomizeConfiguration;
+import org.apache.skywalking.apm.plugin.customize.conf.MethodConfiguration;
+import org.apache.skywalking.apm.plugin.customize.constants.Constants;
+import org.apache.skywalking.apm.plugin.customize.util.CustomizeExpression;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author zhaoyuguang
+ */
+
+class BaseInterceptorMethods {
+
+    void beforeMethod(Method method, Object[] allArguments) {
+        Map<String, Object> configuration = CustomizeConfiguration.INSTANCE.getConfiguration(method);
+        if (!MethodConfiguration.isCloseBeforeMethod(configuration)) {
+            String operationName = MethodConfiguration.getOperationName(configuration);
+            Map<String, Object> context = CustomizeExpression.evaluationContext(allArguments);
+            if (context == null || context.isEmpty()) {
+                ContextManager.createLocalSpan(operationName);
+            } else {
+
+                Map<String, String> tags = MethodConfiguration.getTags(configuration);
+                Map<String, String> spanTags = new HashMap<String, String>();
+                Map<String, String> logs = MethodConfiguration.getLogs(configuration);
+                Map<String, String> spanLogs = new HashMap<String, String>();
+
+                List<String> operationNameSuffixes = MethodConfiguration.getOperationNameSuffixes(configuration);
+                StringBuilder operationNameSuffix = new StringBuilder();
+                if (operationNameSuffixes != null && !operationNameSuffixes.isEmpty()) {
+                    for (String expression : operationNameSuffixes) {
+                        operationNameSuffix.append(Constants.OPERATION_NAME_SEPARATOR);
+                        operationNameSuffix.append(CustomizeExpression.parseExpression(expression, context));
+                    }
+                }
+                if (tags != null && !tags.isEmpty()) {
+                    for (String key : tags.keySet()) {
+                        String expression = tags.get(key);
+                        spanTags.put(key, CustomizeExpression.parseExpression(expression, context));
+                    }
+                }
+                if (logs != null && !logs.isEmpty()) {
+                    for (String key : logs.keySet()) {
+                        String expression = logs.get(key);
+                        spanLogs.put(key, CustomizeExpression.parseExpression(expression, context));
+                    }
+                }
+                operationName = operationNameSuffix.insert(0, operationName).toString();
+
+                AbstractSpan span = ContextManager.createLocalSpan(operationName);
+                if (!spanTags.isEmpty()) {
+                    for (Map.Entry<String, String> tag : spanTags.entrySet()) {
+                        span.tag(tag.getKey(), tag.getValue());
+                    }
+                }
+                if (!spanLogs.isEmpty()) {
+                    span.log(System.currentTimeMillis(), spanLogs);
+                }
+            }
+        }
+    }
+
+    void afterMethod(Method method) {
+        if (!MethodConfiguration.isCloseAfterMethod(CustomizeConfiguration.INSTANCE.getConfiguration(method))) {
+            ContextManager.stopSpan();
+        }
+    }
+
+    void handleMethodException(Throwable t) {
+        if (ContextManager.activeSpan() != null) {
+            ContextManager.activeSpan().errorOccurred().log(t);
+        }
+    }
+
+}
diff --git a/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/interceptor/CustomizeInstanceInterceptor.java b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/interceptor/CustomizeInstanceInterceptor.java
new file mode 100644
index 0000000..e9bf07a
--- /dev/null
+++ b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/interceptor/CustomizeInstanceInterceptor.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 org.apache.skywalking.apm.plugin.customize.interceptor;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+
+import java.lang.reflect.Method;
+
+/**
+ * @author zhaoyuguang
+ */
+
+public class CustomizeInstanceInterceptor extends BaseInterceptorMethods implements InstanceMethodsAroundInterceptor {
+    @Override
+    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+        super.beforeMethod(method, allArguments);
+    }
+
+    @Override
+    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
+        super.afterMethod(method);
+        return ret;
+    }
+
+    @Override
+    public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
+        super.handleMethodException(t);
+    }
+}
diff --git a/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/interceptor/CustomizeStaticInterceptor.java b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/interceptor/CustomizeStaticInterceptor.java
new file mode 100644
index 0000000..68975c3
--- /dev/null
+++ b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/interceptor/CustomizeStaticInterceptor.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.customize.interceptor;
+
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor;
+
+import java.lang.reflect.Method;
+
+/**
+ * @author zhaoyuguang
+ */
+
+public class CustomizeStaticInterceptor extends BaseInterceptorMethods implements StaticMethodsAroundInterceptor {
+    @Override
+    public void beforeMethod(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes, MethodInterceptResult result) {
+        super.beforeMethod(method, allArguments);
+    }
+
+    @Override
+    public Object afterMethod(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes, Object ret) {
+        super.afterMethod(method);
+        return ret;
+    }
+
+    @Override
+    public void handleMethodException(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes, Throwable t) {
+        super.handleMethodException(t);
+    }
+}
diff --git a/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/loader/CustomizeInstrumentationLoader.java b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/loader/CustomizeInstrumentationLoader.java
new file mode 100644
index 0000000..afaf804
--- /dev/null
+++ b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/loader/CustomizeInstrumentationLoader.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 org.apache.skywalking.apm.plugin.customize.loader;
+
+import org.apache.skywalking.apm.agent.core.logging.api.ILog;
+import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
+import org.apache.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.loader.AgentClassLoader;
+import org.apache.skywalking.apm.agent.core.plugin.loader.InstrumentationLoader;
+import org.apache.skywalking.apm.plugin.customize.conf.CustomizeConfiguration;
+import org.apache.skywalking.apm.plugin.customize.define.CustomizeInstanceInstrumentation;
+import org.apache.skywalking.apm.plugin.customize.define.CustomizeStaticInstrumentation;
+import org.apache.skywalking.apm.plugin.customize.util.CustomizeUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * The customize instrumentation plugin loader,
+ * so implements {@link InstrumentationLoader}
+ *
+ * @author zhaoyuguang
+ */
+
+public class CustomizeInstrumentationLoader implements InstrumentationLoader {
+
+    private static final ILog logger = LogManager.getLogger(CustomizeConfiguration.class);
+
+    @Override
+    public List<AbstractClassEnhancePluginDefine> load(AgentClassLoader classLoader) {
+        List<AbstractClassEnhancePluginDefine> instrumentations = new ArrayList<AbstractClassEnhancePluginDefine>();
+        CustomizeConfiguration.INSTANCE.load();
+        Set<String> enhanceClasses = CustomizeConfiguration.INSTANCE.getInstrumentations();
+        try {
+            for (String enhanceClass : enhanceClasses) {
+                String[] classDesc = CustomizeUtil.getClassDesc(enhanceClass);
+                AbstractClassEnhancePluginDefine plugin = (AbstractClassEnhancePluginDefine) Class.forName(
+                        Boolean.valueOf(classDesc[1]) ? CustomizeStaticInstrumentation.class.getName() : CustomizeInstanceInstrumentation.class.getName(),
+                        true, classLoader).getConstructor(String.class).newInstance(classDesc[0]);
+                instrumentations.add(plugin);
+            }
+        } catch (Exception e) {
+            logger.error(e, "InstrumentationLoader loader is error, spi loader is {}", CustomizeInstrumentationLoader.class.getName());
+        }
+        return instrumentations;
+    }
+}
diff --git a/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/util/CustomizeExpression.java b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/util/CustomizeExpression.java
new file mode 100644
index 0000000..66627cc
--- /dev/null
+++ b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/util/CustomizeExpression.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 org.apache.skywalking.apm.plugin.customize.util;
+
+import org.apache.skywalking.apm.agent.core.logging.api.ILog;
+import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * a simple parsing expression
+ *
+ * @author zhaoyuguang
+ */
+
+public class CustomizeExpression {
+
+    private static final ILog logger = LogManager.getLogger(CustomizeExpression.class);
+
+    public static Map<String, Object> evaluationContext(Object[] allArguments) {
+        Map<String, Object> context = new HashMap<String, Object>();
+        for (int i = 0; i < allArguments.length; i++) {
+            context.put("arg[" + i + "]", allArguments[i]);
+        }
+        return context;
+    }
+
+    public static String parseExpression(String expression, Map<String, Object> context) {
+        try {
+            String[] es = expression.split("\\.");
+            Object o = context.get(es[0]);
+            return o == null ? "null" : String.valueOf(parse(es, o, 0));
+        } catch (Exception e) {
+            logger.debug("parse expression error, expression is {}, exception is {}", expression, e.getMessage());
+        }
+        return "null";
+
+    }
+
+    private static Object parse(String[] expressions, Object o, int i) {
+        int next = i + 1;
+        if (next == expressions.length) {
+            return o;
+        } else {
+            o = parse0(expressions[next], o);
+            return o == null ? "null" : parse(expressions, o, next);
+        }
+    }
+
+    private static Object parse0(String expression, Object o) {
+        if (o instanceof Map) {
+            return matcherMap(expression, o);
+        } else if (o instanceof List) {
+            return matcherList(expression, o);
+        } else if (o.getClass().isArray()) {
+            return matcherArray(expression, o);
+        } else {
+            return matcherDefault(expression, o);
+        }
+    }
+
+    private static Object matcherMap(String expression, Object o) {
+        String key = expression.replace("['", "").replace("']", "");
+        return ((Map) o).get(key);
+    }
+
+    private static Object matcherList(String expression, Object o) {
+        int index = Integer.valueOf(expression.replace("[", "").replace("]", ""));
+        List l = (List) o;
+        return l != null && l.size() > index ? l.get(index) : null;
+    }
+
+    private static Object matcherArray(String expression, Object o) {
+        int index = Integer.valueOf(expression.replace("[", "").replace("]", ""));
+        return o != null && Array.getLength(o) > index ? Array.get(o, index) : null;
+    }
+
+    private static Object matcherDefault(String expression, Object o) {
+        try {
+            if (expression.contains("()")) {
+                Method m = o.getClass().getMethod(expression.replace("()", ""), null);
+                return m.invoke(o, null);
+            } else {
+                Field f = o.getClass().getDeclaredField(expression);
+                f.setAccessible(true);
+                return f.get(o);
+            }
+        } catch (Exception e) {
+            logger.debug("matcher default error, expression is {}, object is {}, expression is {}", expression, o, e.getMessage());
+        }
+        return null;
+    }
+}
diff --git a/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/util/CustomizeUtil.java b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/util/CustomizeUtil.java
new file mode 100644
index 0000000..617f58c
--- /dev/null
+++ b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/java/org/apache/skywalking/apm/plugin/customize/util/CustomizeUtil.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 org.apache.skywalking.apm.plugin.customize.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author zhaoyuguang
+ */
+
+public class CustomizeUtil {
+
+    private static final Map<String, Class> JAVA_CLASS = new HashMap<String, Class>();
+
+    static {
+        JAVA_CLASS.put("boolean.class", boolean.class);
+        JAVA_CLASS.put("char.class", char.class);
+        JAVA_CLASS.put("byte.class", byte.class);
+        JAVA_CLASS.put("short.class", short.class);
+        JAVA_CLASS.put("int.class", int.class);
+        JAVA_CLASS.put("long.class", long.class);
+        JAVA_CLASS.put("float.class", float.class);
+        JAVA_CLASS.put("double.class", double.class);
+        JAVA_CLASS.put("java.util.List", java.util.List.class);
+        JAVA_CLASS.put("java.util.Map", java.util.Map.class);
+    }
+
+    public static boolean isJavaClass(String className) {
+        return JAVA_CLASS.containsKey(className);
+    }
+
+    public static Class getJavaClass(String className) {
+        return JAVA_CLASS.get(className);
+    }
+
+    public static String generateOperationName(String className, String methodName, String[] parameterTypes) {
+        StringBuilder operationName = new StringBuilder(className + "." + methodName + "(");
+        for (int i = 0; i < parameterTypes.length; i++) {
+            operationName.append(CustomizeUtil.isJavaClass(parameterTypes[i]) ? CustomizeUtil.getJavaClass(parameterTypes[i]).getName() : parameterTypes[i]);
+            if (i < (parameterTypes.length - 1)) {
+                operationName.append(",");
+            }
+        }
+        operationName.append(")");
+        return operationName.toString();
+    }
+
+    public static String generateClassDesc(String className, boolean isStatic) {
+        return className + ":" + isStatic;
+    }
+
+    public static String[] getClassDesc(String enhanceClass) {
+        return enhanceClass.split(":");
+    }
+}
diff --git a/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/resources/META-INF/services/org.apache.skywalking.apm.agent.core.plugin.loader.InstrumentationLoader b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/resources/META-INF/services/org.apache.skywalking.apm.agent.core.plugin.loader.InstrumentationLoader
new file mode 100755
index 0000000..3c8414e
--- /dev/null
+++ b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/main/resources/META-INF/services/org.apache.skywalking.apm.agent.core.plugin.loader.InstrumentationLoader
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+#
+
+org.apache.skywalking.apm.plugin.customize.loader.CustomizeInstrumentationLoader
\ No newline at end of file
diff --git a/apm-sniffer/optional-plugins/customize-enhance-plugin/src/test/java/org/apache/skywalking/apm/plugin/customize/util/CustomizeExpressionTest.java b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/test/java/org/apache/skywalking/apm/plugin/customize/util/CustomizeExpressionTest.java
new file mode 100644
index 0000000..7911e9d
--- /dev/null
+++ b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/test/java/org/apache/skywalking/apm/plugin/customize/util/CustomizeExpressionTest.java
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.customize.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author zhaoyuguang
+ */
+
+public class CustomizeExpressionTest {
+
+    @Test
+    public void testExpression() {
+        Object[] allArguments = init();
+        Map<String, Object> context = CustomizeExpression.evaluationContext(allArguments);
+        Assert.assertTrue("String_test".equals(CustomizeExpression.parseExpression("arg[0]", context)));
+        Assert.assertTrue("1024".equals(CustomizeExpression.parseExpression("arg[1]", context)));
+        Assert.assertTrue("v2_1".equals(CustomizeExpression.parseExpression("arg[2].['k2_1']", context)));
+        Assert.assertTrue("test1".equals(CustomizeExpression.parseExpression("arg[3].[1]", context)));
+        Assert.assertTrue("null".equals(CustomizeExpression.parseExpression("arg[3].[100]", context)));
+        Assert.assertTrue("100".equals(CustomizeExpression.parseExpression("arg[4].id", context)));
+        Assert.assertTrue("sw".equals(CustomizeExpression.parseExpression("arg[4].getName()", context)));
+        Assert.assertTrue("ext_v_1".equals(CustomizeExpression.parseExpression("arg[4].ext.['ext_k_1']", context)));
+        Assert.assertTrue("uuid".equals(CustomizeExpression.parseExpression("arg[5].uuid", context)));
+        Assert.assertTrue("c".equals(CustomizeExpression.parseExpression("arg[5].orderIds.[0]", context)));
+        Assert.assertTrue("2".equals(CustomizeExpression.parseExpression("arg[5].ids.[2]", context)));
+        Assert.assertTrue("3".equals(CustomizeExpression.parseExpression("arg[5].ids.[1]", context)));
+        Assert.assertTrue("open_id".equals(CustomizeExpression.parseExpression("arg[5].openId", context)));
+        Assert.assertTrue("ext_v_2".equals(CustomizeExpression.parseExpression("arg[5].user.ext.['ext_k_2']", context)));
+    }
+
+    private static Object[] init() {
+        Object[] allArguments = new Object[6];
+        allArguments[0] = "String_test";
+        allArguments[1] = 1024;
+        Map m0 = new HashMap();
+        m0.put("k2_1", "v2_1");
+        allArguments[2] = m0;
+        List l0 = new ArrayList();
+        l0.add("test0");
+        l0.add("test1");
+        allArguments[3] = l0;
+        Map m1 = new HashMap();
+        m1.put("ext_k_1", "ext_v_1");
+        allArguments[4] = new User(100, "sw", m1);
+        Map m2 = new HashMap();
+        m2.put("ext_k_2", "ext_v_2");
+        User user2 = new User(101, "sw0", m2);
+        List l1 = new ArrayList();
+        l1.add("c");
+        Order order = new Order(999, "uuid", l1, user2, "open_id", new Object[]{0, 3, "2"});
+        allArguments[5] = order;
+        return allArguments;
+    }
+
+    static class Order {
+        public Order(int id, String uuid, List orderIds, User user, String openId, Object[] ids) {
+            this.id = id;
+            this.uuid = uuid;
+            this.orderIds = orderIds;
+            this.user = user;
+            this.openId = openId;
+            this.ids = ids;
+        }
+
+        private int id;
+        private String uuid;
+        private List orderIds;
+        private User user;
+        public String openId;
+        private Object[] ids;
+
+        public int getId() {
+            return id;
+        }
+
+        public void setId(int id) {
+            this.id = id;
+        }
+
+        public String getUuid() {
+            return uuid;
+        }
+
+        public void setUuid(String uuid) {
+            this.uuid = uuid;
+        }
+
+        public List getOrderIds() {
+            return orderIds;
+        }
+
+        public void setOrderIds(List orderIds) {
+            this.orderIds = orderIds;
+        }
+
+        public User getUser() {
+            return user;
+        }
+
+        public void setUser(User user) {
+            this.user = user;
+        }
+
+        public Object[] getIds() {
+            return ids;
+        }
+
+        public void setIds(Object[] ids) {
+            this.ids = ids;
+        }
+    }
+
+    static class User {
+
+        public User(int id, String name, Map ext) {
+            this.id = id;
+            this.name = name;
+            this.ext = ext;
+        }
+
+        private int id;
+        private String name;
+        private Map ext;
+
+        public int getId() {
+            return id;
+        }
+
+        public void setId(int id) {
+            this.id = id;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public Map getExt() {
+            return ext;
+        }
+
+        public void setExt(Map ext) {
+            this.ext = ext;
+        }
+    }
+}
diff --git a/apm-sniffer/optional-plugins/customize-enhance-plugin/src/test/java/org/apache/skywalking/apm/plugin/customize/util/CustomizeUtilTest.java b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/test/java/org/apache/skywalking/apm/plugin/customize/util/CustomizeUtilTest.java
new file mode 100644
index 0000000..9e7ea1a
--- /dev/null
+++ b/apm-sniffer/optional-plugins/customize-enhance-plugin/src/test/java/org/apache/skywalking/apm/plugin/customize/util/CustomizeUtilTest.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.customize.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author zhaoyuguang
+ */
+
+public class CustomizeUtilTest {
+
+    @Test
+    public void testClassForName() throws ClassNotFoundException {
+        Assert.assertTrue(CustomizeUtil.isJavaClass("boolean.class"));
+        Assert.assertTrue(CustomizeUtil.isJavaClass("char.class"));
+        Assert.assertTrue(CustomizeUtil.getJavaClass("byte.class") == byte.class);
+        Assert.assertTrue(CustomizeUtil.getJavaClass("short.class") == short.class);
+        Assert.assertTrue(CustomizeUtil.getJavaClass("int.class") == int.class);
+        Assert.assertTrue(CustomizeUtil.getJavaClass("long.class") == long.class);
+        Assert.assertTrue(CustomizeUtil.getJavaClass("float.class") == float.class);
+    }
+}
diff --git a/apm-sniffer/optional-plugins/pom.xml b/apm-sniffer/optional-plugins/pom.xml
index be50e20..4140e6f 100644
--- a/apm-sniffer/optional-plugins/pom.xml
+++ b/apm-sniffer/optional-plugins/pom.xml
@@ -46,6 +46,7 @@
         <module>gson-2.8.x-plugin</module>
         <module>lettuce-5.x-plugin</module>
         <module>zookeeper-3.4.x-plugin</module>
+        <module>customize-enhance-plugin</module>
     </modules>
 
     <dependencies>
diff --git a/docs/en/setup/service-agent/java-agent/Customize-enhance-trace.md b/docs/en/setup/service-agent/java-agent/Customize-enhance-trace.md
new file mode 100644
index 0000000..36cf31e
--- /dev/null
+++ b/docs/en/setup/service-agent/java-agent/Customize-enhance-trace.md
@@ -0,0 +1,72 @@
+## Support custom enhance 
+Here is an optional plugin `apm-customize-enhance-plugin`
+
+## Introduce
+SkyWalking has provided [Java agent plugin development guide](https://github.com/apache/incubator-skywalking/blob/master/docs/en/guides/Java-Plugin-Development-Guide.md) to help developers to build new plugin. 
+
+This plugin is not designed for replacement but for user convenience. The behaviour is very similar with [@Trace toolkit](Application-toolkit-trace.md), but without code change requirement, and more powerful, such as provide tag and log.                                                                                                      
+
+## How to configure
+Implementing enhancements to custom classes requires two steps.
+
+1. Active the plugin, move the `optional-plugins/apm-customize-enhance-plugin.jar` to `plugin/apm-customize-enhance-plugin.jar`.
+2. Set `plugin.customize.enhance_file` in agent.config, which targets to rule file, such as `/absolute/path/to/customize_enhance.xml`.
+3. Set enhancement rules in `customize_enhance.xml`.
+	```xml
+	<?xml version="1.0" encoding="UTF-8"?>
+	<enhanced>
+	    <class class_name="test.apache.skywalking.testcase.customize.service.TestService1">
+	        <method method="staticMethod()" operation_name="/is_static_method" static="true"/>
+	        <method method="staticMethod(java.lang.String,int.class,java.util.Map,java.util.List,[Ljava.lang.Object;)" operation_name="/is_static_method_args" static="true">
+	            <operation_name_suffix>arg[0]</operation_name_suffix>
+	            <operation_name_suffix>arg[1]</operation_name_suffix>
+	            <operation_name_suffix>arg[3].[0]</operation_name_suffix>
+	            <tag key="tag_1">arg[2].['k1']</tag>
+	            <tag key="tag_2">arg[4].[1]</tag>
+	            <log key="log_1">arg[4].[2]</log>
+	        </method>
+	        <method method="method()" static="false"/>
+	        <method method="method(java.lang.String,int.class)" operation_name="/method_2" static="false">
+	            <operation_name_suffix>arg[0]</operation_name_suffix>
+	            <tag key="tag_1">arg[0]</tag>
+	            <log key="log_1">arg[1]</log>
+	        </method>
+	        <method method="method(test.apache.skywalking.testcase.customize.model.Model0,java.lang.String,int.class)" operation_name="/method_3" static="false">
+	            <operation_name_suffix>arg[0].id</operation_name_suffix>
+	            <operation_name_suffix>arg[0].model1.name</operation_name_suffix>
+	            <operation_name_suffix>arg[0].model1.getId()</operation_name_suffix>
+	            <tag key="tag_os">arg[0].os.[1]</tag>
+	            <log key="log_map">arg[0].getM().['k1']</log>
+	        </method>
+	    </class>
+	    <class class_name="test.apache.skywalking.testcase.customize.service.TestService2">
+	        <method method="staticMethod(java.lang.String,int.class)" operation_name="/is_2_static_method" static="true">
+	            <tag key="tag_2_1">arg[0]</tag>
+	            <log key="log_1_1">arg[1]</log>
+	        </method>
+	        <method method="method([Ljava.lang.Object;)" operation_name="/method_4" static="false">
+	            <tag key="tag_4_1">arg[0].[0]</tag>
+	        </method>
+	        <method method="method(java.util.List,int.class)" operation_name="/method_5" static="false">
+	            <tag key="tag_5_1">arg[0].[0]</tag>
+	            <log key="log_5_1">arg[1]</log>
+	        </method>
+	    </class>
+	</enhanced>
+	```
+
+- Explanation of the configuration in the file
+
+	| configuration  | explanation |
+	|:----------------- |:---------------|
+	| class_name | The enhanced class |
+	| method | The interceptor method of the class |
+	| operation_name | If fill it out, will use it instead of the default operation_name. |
+	| operation_name\_suffix | What it means adding dynamic data after the operation_name. |
+	| static | Is this method static. |
+	| tag | Will add a tag in local span. The value of key needs to be represented on the XML node. |
+	| log | Will add a log in local span. The value of key needs to be represented on the XML node. |
+	| arg[x]   | What it means is to get the input arguments. such as arg[0] is means get first arguments. |
+	| .[x]     | When the parsing object is Array or List, you can use it to get the object at the specified index. |
+	| .['key'] | When the parsing object is Map, you can get the map 'key' through it.|
+
diff --git a/docs/en/setup/service-agent/java-agent/README.md b/docs/en/setup/service-agent/java-agent/README.md
index 85df690..2e94271 100644
--- a/docs/en/setup/service-agent/java-agent/README.md
+++ b/docs/en/setup/service-agent/java-agent/README.md
@@ -92,6 +92,7 @@ Now, we have the following known optional plugins.
 * Gson serialization lib in optional plugin folder
 * Lettuce 5.x(JRE1.8+) in optional plugin folder 
 * Zookeeper 3.4.x in optional plugin folder. The reason of being optional plugin is, many business irrelevant traces are generated, which cause extra payload to agents and backends. At the same time, those traces may be just heartbeat(s).
+* [Customize enhance](Customize-enhance-trace.md) Trace methods based on description files, rather than write plugin or change source codes.
 
 ## Advanced Features
 * Set the settings through system properties for config file override. Read [setting override](Setting-override.md).