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 2020/03/22 09:20:14 UTC

[skywalking] branch master updated: Provide HTTP parameter in the profiling contet (#4546)

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/skywalking.git


The following commit(s) were added to refs/heads/master by this push:
     new ace781f  Provide HTTP parameter in the profiling contet (#4546)
ace781f is described below

commit ace781ff490310de09313f19194281826f9064b0
Author: mrproliu <74...@qq.com>
AuthorDate: Sun Mar 22 17:19:57 2020 +0800

    Provide HTTP parameter in the profiling contet (#4546)
    
    * Provide active HTTP parameter collection automatically in the profiling context
    
    * Fix style check
    
    * fix style error
    
    * Add profile status, storage it into TracingContext. simplify to get profiling method
    
    * Change the profile status field name in TracingContext
    
    * Replace gone images
    
    * resolve issues
    
    * resole description issues
    
    Co-authored-by: Mrproliu <mr...@lagou.com>
    Co-authored-by: kezhenxu94 <ke...@163.com>
---
 .../apm/agent/core/context/ContextManager.java     |  1 +
 .../apm/agent/core/context/TracingContext.java     | 14 ++---
 .../apm/agent/core/context/trace/AbstractSpan.java |  5 ++
 .../core/context/trace/AbstractTracingSpan.java    |  5 ++
 .../apm/agent/core/context/trace/NoopSpan.java     |  5 ++
 .../{ProfilingStatus.java => ProfileStatus.java}   | 22 ++++++-
 .../agent/core/profile/ProfileStatusReference.java | 69 ++++++++++++++++++++++
 .../core/profile/ProfileTaskExecutionContext.java  | 23 ++++----
 .../core/profile/ProfileTaskExecutionService.java  | 12 ++--
 .../apm/agent/core/profile/ProfileThread.java      |  4 +-
 .../apm/agent/core/profile/ThreadProfiler.java     |  9 +--
 .../interceptor/AbstractMethodInterceptor.java     | 21 +++++--
 .../plugin/tomcat78x/TomcatInvokeInterceptor.java  | 35 +++++++----
 .../skywalking/e2e/profile/query/ProfiledSpan.java |  3 +
 .../e2e/profile/query/ProfiledSpanMatcher.java     | 15 +++++
 .../e2e/profile/query/ProfiledSpanTag.java         | 15 ++---
 ...ofiledSpan.java => ProfiledSpanTagMatcher.java} | 25 ++++----
 .../src/main/resources/profiledSegment.gql         |  3 +
 .../apache/skywalking/e2e/profile/ProfileE2E.java  |  2 +-
 .../resources/expected/profile/profileSegment.yml  | 35 +++++++++++
 20 files changed, 253 insertions(+), 70 deletions(-)

diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java
index d609492..0a5a96d 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java
@@ -224,4 +224,5 @@ public class ContextManager implements BootService {
 
         return runtimeContext;
     }
+
 }
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java
index d73998a..a31145e 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java
@@ -39,6 +39,7 @@ import org.apache.skywalking.apm.agent.core.dictionary.DictionaryManager;
 import org.apache.skywalking.apm.agent.core.dictionary.DictionaryUtil;
 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.profile.ProfileStatusReference;
 import org.apache.skywalking.apm.agent.core.profile.ProfileTaskExecutionService;
 import org.apache.skywalking.apm.agent.core.sampling.SamplingService;
 import org.apache.skywalking.apm.util.StringUtil;
@@ -106,9 +107,9 @@ public class TracingContext implements AbstractTracerContext {
     private final long createTime;
 
     /**
-     * profiling status
+     * profile status
      */
-    private volatile boolean profiling;
+    private final ProfileStatusReference profileStatus;
 
     /**
      * Initialize all fields with default value.
@@ -128,7 +129,7 @@ public class TracingContext implements AbstractTracerContext {
         if (PROFILE_TASK_EXECUTION_SERVICE == null) {
             PROFILE_TASK_EXECUTION_SERVICE = ServiceManager.INSTANCE.findService(ProfileTaskExecutionService.class);
         }
-        this.profiling = PROFILE_TASK_EXECUTION_SERVICE.addProfiling(this, segment.getTraceSegmentId(), firstOPName);
+        this.profileStatus = PROFILE_TASK_EXECUTION_SERVICE.addProfiling(this, segment.getTraceSegmentId(), firstOPName);
     }
 
     /**
@@ -521,7 +522,7 @@ public class TracingContext implements AbstractTracerContext {
             return;
         }
 
-        profiling = PROFILE_TASK_EXECUTION_SERVICE.profilingRecheck(this, segment.getTraceSegmentId(), operationName);
+        PROFILE_TASK_EXECUTION_SERVICE.profilingRecheck(this, segment.getTraceSegmentId(), operationName);
     }
 
     /**
@@ -688,8 +689,7 @@ public class TracingContext implements AbstractTracerContext {
         return this.createTime;
     }
 
-    public boolean isProfiling() {
-        return this.profiling;
+    public ProfileStatusReference profileStatus() {
+        return this.profileStatus;
     }
-
 }
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractSpan.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractSpan.java
index 88ee212..75946d3 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractSpan.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractSpan.java
@@ -126,4 +126,9 @@ public interface AbstractSpan extends AsyncSpan {
     AbstractSpan start(long startTime);
 
     AbstractSpan setPeer(String remotePeer);
+
+    /**
+     * @return true if the span's owner(tracing context main thread) is been profiled.
+     */
+    boolean isProfiling();
 }
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractTracingSpan.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractTracingSpan.java
index fb170ab..001f934 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractTracingSpan.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractTracingSpan.java
@@ -358,4 +358,9 @@ public abstract class AbstractTracingSpan implements AbstractSpan {
         isAsyncStopped = true;
         return this;
     }
+
+    @Override
+    public boolean isProfiling() {
+        return this.owner.profileStatus().isProfiling();
+    }
 }
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/NoopSpan.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/NoopSpan.java
index c08db0e..234af2d 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/NoopSpan.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/NoopSpan.java
@@ -130,6 +130,11 @@ public class NoopSpan implements AbstractSpan {
     }
 
     @Override
+    public boolean isProfiling() {
+        return false;
+    }
+
+    @Override
     public AbstractSpan prepareForAsync() {
         return this;
     }
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfilingStatus.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileStatus.java
similarity index 61%
copy from apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfilingStatus.java
copy to apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileStatus.java
index 305b8a8..1fab052 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfilingStatus.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileStatus.java
@@ -18,11 +18,29 @@
 
 package org.apache.skywalking.apm.agent.core.profile;
 
-public enum ProfilingStatus {
+/**
+ * Profile status, include entire profile cycle
+ */
+public enum ProfileStatus {
+    /**
+     * No profile
+     */
+    NONE,
 
-    READY,
+    /**
+     * Prepare to profile, until {@link ProfileTask#getMinDurationThreshold()} reached,
+     * Once the status changed to profiling, the thread snapshot is officially started
+     */
+    PENDING,
 
+    /**
+     * Profile operation has been started.
+     */
     PROFILING,
 
+    /**
+     * The current {@link org.apache.skywalking.apm.agent.core.context.TracingContext} has finished,
+     * or the current thread isn't available.
+     */
     STOPPED
 }
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileStatusReference.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileStatusReference.java
new file mode 100644
index 0000000..7d1149f
--- /dev/null
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileStatusReference.java
@@ -0,0 +1,69 @@
+/*
+ * 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.profile;
+
+/**
+ * Wrapper {@link ProfileStatus}, make sure {@link org.apache.skywalking.apm.agent.core.context.TracingContext} with {@link ThreadProfiler} have same reference with {@link ProfileStatus},
+ * And only the profile module could change the status
+ */
+public class ProfileStatusReference {
+
+    private volatile ProfileStatus status;
+
+    private ProfileStatusReference(ProfileStatus status) {
+        this.status = status;
+    }
+
+    /**
+     * Create with not watching
+     */
+    public static ProfileStatusReference createWithNone() {
+        return new ProfileStatusReference(ProfileStatus.NONE);
+    }
+
+    /**
+     * Create with pending to profile
+     */
+    public static ProfileStatusReference createWithPending() {
+        return new ProfileStatusReference(ProfileStatus.PENDING);
+    }
+
+    public ProfileStatus get() {
+        return this.status;
+    }
+
+    /**
+     * The profile monitoring is watching, wait for some profile conditions.
+     */
+    public boolean isBeingWatched() {
+        return this.status != ProfileStatus.NONE;
+    }
+
+    public boolean isProfiling() {
+        return this.status == ProfileStatus.PROFILING;
+    }
+
+    /**
+     * Update status, only access with profile module
+     */
+    void updateStatus(ProfileStatus status) {
+        this.status = status;
+    }
+
+}
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileTaskExecutionContext.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileTaskExecutionContext.java
index bb1949f..d1f5caf 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileTaskExecutionContext.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileTaskExecutionContext.java
@@ -74,48 +74,49 @@ public class ProfileTaskExecutionContext {
      *
      * @return is add profile success
      */
-    public boolean attemptProfiling(TracingContext tracingContext, ID traceSegmentId, String firstSpanOPName) {
+    public ProfileStatusReference attemptProfiling(TracingContext tracingContext, ID traceSegmentId, String firstSpanOPName) {
         // check has available slot
         final int usingSlotCount = currentProfilingCount.get();
         if (usingSlotCount >= Config.Profile.MAX_PARALLEL) {
-            return false;
+            return ProfileStatusReference.createWithNone();
         }
 
         // check first operation name matches
         if (!Objects.equals(task.getFistSpanOPName(), firstSpanOPName)) {
-            return false;
+            return ProfileStatusReference.createWithNone();
         }
 
         // if out limit started profiling count then stop add profiling
         if (totalStartedProfilingCount.get() > task.getMaxSamplingCount()) {
-            return false;
+            return ProfileStatusReference.createWithNone();
         }
 
         // try to occupy slot
         if (!currentProfilingCount.compareAndSet(usingSlotCount, usingSlotCount + 1)) {
-            return false;
+            return ProfileStatusReference.createWithNone();
         }
 
         final ThreadProfiler threadProfiler = new ThreadProfiler(tracingContext, traceSegmentId, Thread.currentThread(), this);
         int slotLength = profilingSegmentSlots.length();
         for (int slot = 0; slot < slotLength; slot++) {
             if (profilingSegmentSlots.compareAndSet(slot, null, threadProfiler)) {
-                break;
+                return threadProfiler.profilingStatus();
             }
         }
-        return true;
+        return ProfileStatusReference.createWithNone();
     }
 
     /**
      * profiling recheck
      */
-    public boolean profilingRecheck(TracingContext tracingContext, ID traceSegmentId, String firstSpanOPName) {
+    public void profilingRecheck(TracingContext tracingContext, ID traceSegmentId, String firstSpanOPName) {
         // if started, keep profiling
-        if (tracingContext.isProfiling()) {
-            return true;
+        if (tracingContext.profileStatus().isBeingWatched()) {
+            return;
         }
 
-        return attemptProfiling(tracingContext, traceSegmentId, firstSpanOPName);
+        // update profiling status
+        tracingContext.profileStatus().updateStatus(attemptProfiling(tracingContext, traceSegmentId, firstSpanOPName).get());
     }
 
     /**
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileTaskExecutionService.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileTaskExecutionService.java
index afe840e..308b20c 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileTaskExecutionService.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileTaskExecutionService.java
@@ -91,11 +91,11 @@ public class ProfileTaskExecutionService implements BootService, TracingThreadLi
     /**
      * check and add {@link TracingContext} profiling
      */
-    public boolean addProfiling(TracingContext tracingContext, ID traceSegmentId, String firstSpanOPName) {
+    public ProfileStatusReference addProfiling(TracingContext tracingContext, ID traceSegmentId, String firstSpanOPName) {
         // get current profiling task, check need profiling
         final ProfileTaskExecutionContext executionContext = taskExecutionContext.get();
         if (executionContext == null) {
-            return false;
+            return ProfileStatusReference.createWithNone();
         }
 
         return executionContext.attemptProfiling(tracingContext, traceSegmentId, firstSpanOPName);
@@ -104,14 +104,14 @@ public class ProfileTaskExecutionService implements BootService, TracingThreadLi
     /**
      * Re-check current trace need profiling, in case that third-party plugins change the operation name.
      */
-    public boolean profilingRecheck(TracingContext tracingContext, ID traceSegmentId, String firstSpanOPName) {
+    public void profilingRecheck(TracingContext tracingContext, ID traceSegmentId, String firstSpanOPName) {
         // get current profiling task, check need profiling
         final ProfileTaskExecutionContext executionContext = taskExecutionContext.get();
         if (executionContext == null) {
-            return false;
+            return;
         }
 
-        return executionContext.profilingRecheck(tracingContext, traceSegmentId, firstSpanOPName);
+        executionContext.profilingRecheck(tracingContext, traceSegmentId, firstSpanOPName);
     }
 
     /**
@@ -247,7 +247,7 @@ public class ProfileTaskExecutionService implements BootService, TracingThreadLi
 
     @Override
     public void afterMainThreadFinish(TracingContext tracingContext) {
-        if (tracingContext.isProfiling()) {
+        if (tracingContext.profileStatus().isBeingWatched()) {
             // stop profiling tracing context
             ProfileTaskExecutionContext currentExecutionContext = taskExecutionContext.get();
             if (currentExecutionContext != null) {
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileThread.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileThread.java
index b8c6e44..ba0b7ce 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileThread.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileThread.java
@@ -81,9 +81,9 @@ public class ProfileThread implements Runnable {
                     continue;
                 }
 
-                switch (currentProfiler.profilingStatus()) {
+                switch (currentProfiler.profilingStatus().get()) {
 
-                    case READY:
+                    case PENDING:
                         // check tracing context running time
                         currentProfiler.startProfilingIfNeed();
                         break;
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ThreadProfiler.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ThreadProfiler.java
index b860b36..8587a97 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ThreadProfiler.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ThreadProfiler.java
@@ -42,7 +42,7 @@ public class ThreadProfiler {
     private long profilingMaxTimeMills;
 
     // after min duration threshold check, it will start dump
-    private ProfilingStatus profilingStatus = ProfilingStatus.READY;
+    private final ProfileStatusReference profilingStatus;
     // thread dump sequence
     private int dumpSequence = 0;
 
@@ -52,6 +52,7 @@ public class ThreadProfiler {
         this.traceSegmentId = traceSegmentId;
         this.profilingThread = profilingThread;
         this.executionContext = executionContext;
+        this.profilingStatus = ProfileStatusReference.createWithPending();
         this.profilingMaxTimeMills = TimeUnit.MINUTES.toMillis(Config.Profile.MAX_DURATION);
     }
 
@@ -62,7 +63,7 @@ public class ThreadProfiler {
         if (System.currentTimeMillis() - tracingContext.createTime() > executionContext.getTask()
                                                                                        .getMinDurationThreshold()) {
             this.profilingStartTime = System.currentTimeMillis();
-            this.profilingStatus = ProfilingStatus.PROFILING;
+            this.tracingContext.profileStatus().updateStatus(ProfileStatus.PROFILING);
         }
     }
 
@@ -70,7 +71,7 @@ public class ThreadProfiler {
      * Stop profiling status
      */
     public void stopProfiling() {
-        this.profilingStatus = ProfilingStatus.STOPPED;
+        this.tracingContext.profileStatus().updateStatus(ProfileStatus.STOPPED);
     }
 
     /**
@@ -145,7 +146,7 @@ public class ThreadProfiler {
         return tracingContext;
     }
 
-    public ProfilingStatus profilingStatus() {
+    public ProfileStatusReference profilingStatus() {
         return profilingStatus;
     }
 
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/AbstractMethodInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/AbstractMethodInterceptor.java
index 1de75ec..d601067 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/AbstractMethodInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/AbstractMethodInterceptor.java
@@ -109,12 +109,7 @@ public abstract class AbstractMethodInterceptor implements InstanceMethodsAround
                 SpanLayer.asHttp(span);
 
                 if (Config.Plugin.SpringMVC.COLLECT_HTTP_PARAMS) {
-                    final Map<String, String[]> parameterMap = request.getParameterMap();
-                    if (parameterMap != null && !parameterMap.isEmpty()) {
-                        String tagValue = CollectionUtil.toString(parameterMap);
-                        tagValue = Config.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD > 0 ? StringUtil.cut(tagValue, Config.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD) : tagValue;
-                        Tags.HTTP.PARAMS.set(span, tagValue);
-                    }
+                    collectHttpParam(request, span);
                 }
 
                 stackDepth = new StackDepth();
@@ -185,6 +180,11 @@ public abstract class AbstractMethodInterceptor implements InstanceMethodsAround
                 ContextManager.getRuntimeContext().remove(CONTROLLER_METHOD_STACK_DEPTH);
             }
 
+            // Active HTTP parameter collection automatically in the profiling context.
+            if (!Config.Plugin.SpringMVC.COLLECT_HTTP_PARAMS && span.isProfiling()) {
+                collectHttpParam(request, span);
+            }
+
             ContextManager.stopSpan();
         }
 
@@ -196,4 +196,13 @@ public abstract class AbstractMethodInterceptor implements InstanceMethodsAround
         Class<?>[] argumentsTypes, Throwable t) {
         ContextManager.activeSpan().errorOccurred().log(t);
     }
+
+    private void collectHttpParam(HttpServletRequest request, AbstractSpan span) {
+        final Map<String, String[]> parameterMap = request.getParameterMap();
+        if (parameterMap != null && !parameterMap.isEmpty()) {
+            String tagValue = CollectionUtil.toString(parameterMap);
+            tagValue = Config.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD > 0 ? StringUtil.cut(tagValue, Config.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD) : tagValue;
+            Tags.HTTP.PARAMS.set(span, tagValue);
+        }
+    }
 }
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatInvokeInterceptor.java b/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatInvokeInterceptor.java
index 3434fdb..aa37060 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatInvokeInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatInvokeInterceptor.java
@@ -83,25 +83,14 @@ public class TomcatInvokeInterceptor implements InstanceMethodsAroundInterceptor
         SpanLayer.asHttp(span);
 
         if (Config.Plugin.Tomcat.COLLECT_HTTP_PARAMS) {
-            final Map<String, String[]> parameterMap = new HashMap<>();
-            final org.apache.coyote.Request coyoteRequest = request.getCoyoteRequest();
-            final Parameters parameters = coyoteRequest.getParameters();
-            for (final Enumeration<String> names = parameters.getParameterNames(); names.hasMoreElements(); ) {
-                final String name = names.nextElement();
-                parameterMap.put(name, parameters.getParameterValues(name));
-            }
-
-            if (!parameterMap.isEmpty()) {
-                String tagValue = CollectionUtil.toString(parameterMap);
-                tagValue = Config.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD > 0 ? StringUtil.cut(tagValue, Config.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD) : tagValue;
-                Tags.HTTP.PARAMS.set(span, tagValue);
-            }
+            collectHttpParam(request, span);
         }
     }
 
     @Override
     public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
         Object ret) throws Throwable {
+        Request request = (Request) allArguments[0];
         HttpServletResponse response = (HttpServletResponse) allArguments[1];
 
         AbstractSpan span = ContextManager.activeSpan();
@@ -109,6 +98,10 @@ public class TomcatInvokeInterceptor implements InstanceMethodsAroundInterceptor
             span.errorOccurred();
             Tags.STATUS_CODE.set(span, Integer.toString(response.getStatus()));
         }
+        // Active HTTP parameter collection automatically in the profiling context.
+        if (!Config.Plugin.Tomcat.COLLECT_HTTP_PARAMS && span.isProfiling()) {
+            collectHttpParam(request, span);
+        }
         ContextManager.stopSpan();
         ContextManager.getRuntimeContext().remove(Constants.FORWARD_REQUEST_FLAG);
         return ret;
@@ -121,4 +114,20 @@ public class TomcatInvokeInterceptor implements InstanceMethodsAroundInterceptor
         span.log(t);
         span.errorOccurred();
     }
+
+    private void collectHttpParam(Request request, AbstractSpan span) {
+        final Map<String, String[]> parameterMap = new HashMap<>();
+        final org.apache.coyote.Request coyoteRequest = request.getCoyoteRequest();
+        final Parameters parameters = coyoteRequest.getParameters();
+        for (final Enumeration<String> names = parameters.getParameterNames(); names.hasMoreElements(); ) {
+            final String name = names.nextElement();
+            parameterMap.put(name, parameters.getParameterValues(name));
+        }
+
+        if (!parameterMap.isEmpty()) {
+            String tagValue = CollectionUtil.toString(parameterMap);
+            tagValue = Config.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD > 0 ? StringUtil.cut(tagValue, Config.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD) : tagValue;
+            Tags.HTTP.PARAMS.set(span, tagValue);
+        }
+    }
 }
diff --git a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpan.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpan.java
index 3b7d2a2..b07e00e 100644
--- a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpan.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpan.java
@@ -22,6 +22,8 @@ import com.google.common.primitives.Ints;
 import lombok.Data;
 import lombok.ToString;
 
+import java.util.List;
+
 @Data
 @ToString
 public class ProfiledSpan implements Comparable<ProfiledSpan> {
@@ -31,6 +33,7 @@ public class ProfiledSpan implements Comparable<ProfiledSpan> {
     private String startTime;
     private String endTime;
     private String endpointName;
+    private List<ProfiledSpanTag> tags;
 
     @Override
     public int compareTo(ProfiledSpan o) {
diff --git a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpanMatcher.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpanMatcher.java
index 71fcf7e..82e244e 100644
--- a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpanMatcher.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpanMatcher.java
@@ -23,6 +23,11 @@ import lombok.EqualsAndHashCode;
 import lombok.ToString;
 import org.apache.skywalking.e2e.verification.AbstractMatcher;
 
+import java.util.Comparator;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
 @Data
 @ToString(callSuper = true)
 @EqualsAndHashCode(callSuper = true)
@@ -33,6 +38,7 @@ public class ProfiledSpanMatcher extends AbstractMatcher<ProfiledSpan> {
     private String startTime;
     private String endTime;
     private String endpointName;
+    private List<ProfiledSpanTagMatcher> tags;
 
     @Override
     public void verify(ProfiledSpan span) {
@@ -42,5 +48,14 @@ public class ProfiledSpanMatcher extends AbstractMatcher<ProfiledSpan> {
         doVerify(startTime, span.getStartTime());
         doVerify(endTime, span.getEndTime());
         doVerify(endpointName, span.getEndpointName());
+
+        assertThat(tags).hasSameSizeAs(span.getTags());
+
+        tags.sort(Comparator.comparing(ProfiledSpanTagMatcher::getKey));
+        span.getTags().sort(Comparator.comparing(ProfiledSpanTag::getKey));
+
+        for (int i = 0; i < tags.size(); i++) {
+            tags.get(i).verify(span.getTags().get(i));
+        }
     }
 }
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfilingStatus.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpanTag.java
similarity index 81%
rename from apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfilingStatus.java
rename to test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpanTag.java
index 305b8a8..62042bf 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfilingStatus.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpanTag.java
@@ -16,13 +16,14 @@
  *
  */
 
-package org.apache.skywalking.apm.agent.core.profile;
+package org.apache.skywalking.e2e.profile.query;
 
-public enum ProfilingStatus {
+import lombok.Data;
+import lombok.ToString;
 
-    READY,
-
-    PROFILING,
-
-    STOPPED
+@Data
+@ToString
+public class ProfiledSpanTag {
+    private String key;
+    private String value;
 }
diff --git a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpan.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpanTagMatcher.java
similarity index 64%
copy from test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpan.java
copy to test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpanTagMatcher.java
index 3b7d2a2..ef44436 100644
--- a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpan.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpanTagMatcher.java
@@ -18,22 +18,25 @@
 
 package org.apache.skywalking.e2e.profile.query;
 
-import com.google.common.primitives.Ints;
 import lombok.Data;
+import lombok.EqualsAndHashCode;
 import lombok.ToString;
+import org.apache.skywalking.e2e.verification.AbstractMatcher;
 
 @Data
-@ToString
-public class ProfiledSpan implements Comparable<ProfiledSpan> {
-    private String spanId;
-    private String parentSpanId;
-    private String serviceCode;
-    private String startTime;
-    private String endTime;
-    private String endpointName;
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+public class ProfiledSpanTagMatcher extends AbstractMatcher<ProfiledSpanTag> {
+    private String key;
+    private String value;
 
     @Override
-    public int compareTo(ProfiledSpan o) {
-        return Ints.compare(Integer.parseInt(spanId), Integer.parseInt(o.spanId));
+    public void verify(ProfiledSpanTag profiledSpanTag) {
+        if (value == null) {
+            value = "";
+        }
+
+        doVerify(key, profiledSpanTag.getKey());
+        doVerify(value, profiledSpanTag.getValue());
     }
 }
diff --git a/test/e2e/e2e-data/src/main/resources/profiledSegment.gql b/test/e2e/e2e-data/src/main/resources/profiledSegment.gql
index 164fb84..852c32f 100644
--- a/test/e2e/e2e-data/src/main/resources/profiledSegment.gql
+++ b/test/e2e/e2e-data/src/main/resources/profiledSegment.gql
@@ -18,6 +18,9 @@
     segment: getProfiledSegment(segmentId: $segmentId) {
         spans {
            spanId parentSpanId serviceCode startTime endTime endpointName type peer component isError layer
+           tags {
+               key value
+           }
         }
     }
   }",
diff --git a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/profile/ProfileE2E.java b/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/profile/ProfileE2E.java
index 47fa9a6..c143293 100644
--- a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/profile/ProfileE2E.java
+++ b/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/profile/ProfileE2E.java
@@ -169,7 +169,7 @@ public class ProfileE2E extends SkyWalkingTestAdapter {
         final Map<String, String> user = ImmutableMap.of(
             "name", "SkyWalking", "enableProfiling", String.valueOf(needProfiling)
         );
-        return restTemplate.postForEntity(instrumentedServiceUrl + "/profile/users", user, String.class);
+        return restTemplate.postForEntity(instrumentedServiceUrl + "/profile/users?e2e=true", user, String.class);
     }
 
     private void verifyProfiledSegment(String taskId) throws Exception {
diff --git a/test/e2e/e2e-test/src/test/resources/expected/profile/profileSegment.yml b/test/e2e/e2e-test/src/test/resources/expected/profile/profileSegment.yml
index 4499a58..f6646e4 100644
--- a/test/e2e/e2e-test/src/test/resources/expected/profile/profileSegment.yml
+++ b/test/e2e/e2e-test/src/test/resources/expected/profile/profileSegment.yml
@@ -20,27 +20,62 @@ spans:
     startTime: gt 0
     endTime: gt 0
     endpointName: /profile/users
+    tags:
+      - key: url
+        value: not null
+      - key: http.method
+        value: POST
+      - key: http.params
+        value: "e2e=[true]"
   - spanId: 1
     parentSpanId: 0
     serviceCode: not null
     startTime: gt 0
     endTime: gt 0
     endpointName: H2/JDBI/PreparedStatement/executeQuery
+    tags:
+      - key: db.type
+        value: sql
+      - key: db.instance
+        value: testdb
+      - key: db.statement
+        value: "call next value for hibernate_sequence"
   - spanId: 2
     parentSpanId: 0
     serviceCode: not null
     startTime: gt 0
     endTime: gt 0
     endpointName: H2/JDBI/PreparedStatement/executeUpdate
+    tags:
+      - key: db.type
+        value: sql
+      - key: db.instance
+        value: testdb
+      - key: db.statement
+        value: "insert into user (name, id) values (?, ?)"
   - spanId: 3
     parentSpanId: 0
     serviceCode: not null
     startTime: gt 0
     endTime: gt 0
     endpointName: H2/JDBI/Connection/commit
+    tags:
+      - key: db.type
+        value: sql
+      - key: db.instance
+        value: testdb
+      - key: db.statement
+        value:
   - spanId: 4
     parentSpanId: 0
     serviceCode: not null
     startTime: gt 0
     endTime: gt 0
     endpointName: H2/JDBI/Connection/commit
+    tags:
+      - key: db.type
+        value: sql
+      - key: db.instance
+        value: testdb
+      - key: db.statement
+        value: