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 <mrproliu@lagou.com> Co-authored-by: kezhenxu94 <kezhenxu94@163.com>
This commit is contained in:
parent
a9d34e3b61
commit
ace781ff49
|
|
@ -224,4 +224,5 @@ public class ContextManager implements BootService {
|
||||||
|
|
||||||
return runtimeContext;
|
return runtimeContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.dictionary.DictionaryUtil;
|
||||||
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
|
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.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.profile.ProfileTaskExecutionService;
|
||||||
import org.apache.skywalking.apm.agent.core.sampling.SamplingService;
|
import org.apache.skywalking.apm.agent.core.sampling.SamplingService;
|
||||||
import org.apache.skywalking.apm.util.StringUtil;
|
import org.apache.skywalking.apm.util.StringUtil;
|
||||||
|
|
@ -106,9 +107,9 @@ public class TracingContext implements AbstractTracerContext {
|
||||||
private final long createTime;
|
private final long createTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* profiling status
|
* profile status
|
||||||
*/
|
*/
|
||||||
private volatile boolean profiling;
|
private final ProfileStatusReference profileStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize all fields with default value.
|
* Initialize all fields with default value.
|
||||||
|
|
@ -128,7 +129,7 @@ public class TracingContext implements AbstractTracerContext {
|
||||||
if (PROFILE_TASK_EXECUTION_SERVICE == null) {
|
if (PROFILE_TASK_EXECUTION_SERVICE == null) {
|
||||||
PROFILE_TASK_EXECUTION_SERVICE = ServiceManager.INSTANCE.findService(ProfileTaskExecutionService.class);
|
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;
|
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;
|
return this.createTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isProfiling() {
|
public ProfileStatusReference profileStatus() {
|
||||||
return this.profiling;
|
return this.profileStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -126,4 +126,9 @@ public interface AbstractSpan extends AsyncSpan {
|
||||||
AbstractSpan start(long startTime);
|
AbstractSpan start(long startTime);
|
||||||
|
|
||||||
AbstractSpan setPeer(String remotePeer);
|
AbstractSpan setPeer(String remotePeer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the span's owner(tracing context main thread) is been profiled.
|
||||||
|
*/
|
||||||
|
boolean isProfiling();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -358,4 +358,9 @@ public abstract class AbstractTracingSpan implements AbstractSpan {
|
||||||
isAsyncStopped = true;
|
isAsyncStopped = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isProfiling() {
|
||||||
|
return this.owner.profileStatus().isProfiling();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,11 @@ public class NoopSpan implements AbstractSpan {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isProfiling() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AbstractSpan prepareForAsync() {
|
public AbstractSpan prepareForAsync() {
|
||||||
return this;
|
return this;
|
||||||
|
|
|
||||||
|
|
@ -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.agent.core.profile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Profile status, include entire profile cycle
|
||||||
|
*/
|
||||||
|
public enum ProfileStatus {
|
||||||
|
/**
|
||||||
|
* No profile
|
||||||
|
*/
|
||||||
|
NONE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -74,48 +74,49 @@ public class ProfileTaskExecutionContext {
|
||||||
*
|
*
|
||||||
* @return is add profile success
|
* @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
|
// check has available slot
|
||||||
final int usingSlotCount = currentProfilingCount.get();
|
final int usingSlotCount = currentProfilingCount.get();
|
||||||
if (usingSlotCount >= Config.Profile.MAX_PARALLEL) {
|
if (usingSlotCount >= Config.Profile.MAX_PARALLEL) {
|
||||||
return false;
|
return ProfileStatusReference.createWithNone();
|
||||||
}
|
}
|
||||||
|
|
||||||
// check first operation name matches
|
// check first operation name matches
|
||||||
if (!Objects.equals(task.getFistSpanOPName(), firstSpanOPName)) {
|
if (!Objects.equals(task.getFistSpanOPName(), firstSpanOPName)) {
|
||||||
return false;
|
return ProfileStatusReference.createWithNone();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if out limit started profiling count then stop add profiling
|
// if out limit started profiling count then stop add profiling
|
||||||
if (totalStartedProfilingCount.get() > task.getMaxSamplingCount()) {
|
if (totalStartedProfilingCount.get() > task.getMaxSamplingCount()) {
|
||||||
return false;
|
return ProfileStatusReference.createWithNone();
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to occupy slot
|
// try to occupy slot
|
||||||
if (!currentProfilingCount.compareAndSet(usingSlotCount, usingSlotCount + 1)) {
|
if (!currentProfilingCount.compareAndSet(usingSlotCount, usingSlotCount + 1)) {
|
||||||
return false;
|
return ProfileStatusReference.createWithNone();
|
||||||
}
|
}
|
||||||
|
|
||||||
final ThreadProfiler threadProfiler = new ThreadProfiler(tracingContext, traceSegmentId, Thread.currentThread(), this);
|
final ThreadProfiler threadProfiler = new ThreadProfiler(tracingContext, traceSegmentId, Thread.currentThread(), this);
|
||||||
int slotLength = profilingSegmentSlots.length();
|
int slotLength = profilingSegmentSlots.length();
|
||||||
for (int slot = 0; slot < slotLength; slot++) {
|
for (int slot = 0; slot < slotLength; slot++) {
|
||||||
if (profilingSegmentSlots.compareAndSet(slot, null, threadProfiler)) {
|
if (profilingSegmentSlots.compareAndSet(slot, null, threadProfiler)) {
|
||||||
break;
|
return threadProfiler.profilingStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return ProfileStatusReference.createWithNone();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* profiling recheck
|
* 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 started, keep profiling
|
||||||
if (tracingContext.isProfiling()) {
|
if (tracingContext.profileStatus().isBeingWatched()) {
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return attemptProfiling(tracingContext, traceSegmentId, firstSpanOPName);
|
// update profiling status
|
||||||
|
tracingContext.profileStatus().updateStatus(attemptProfiling(tracingContext, traceSegmentId, firstSpanOPName).get());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -91,11 +91,11 @@ public class ProfileTaskExecutionService implements BootService, TracingThreadLi
|
||||||
/**
|
/**
|
||||||
* check and add {@link TracingContext} profiling
|
* 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
|
// get current profiling task, check need profiling
|
||||||
final ProfileTaskExecutionContext executionContext = taskExecutionContext.get();
|
final ProfileTaskExecutionContext executionContext = taskExecutionContext.get();
|
||||||
if (executionContext == null) {
|
if (executionContext == null) {
|
||||||
return false;
|
return ProfileStatusReference.createWithNone();
|
||||||
}
|
}
|
||||||
|
|
||||||
return executionContext.attemptProfiling(tracingContext, traceSegmentId, firstSpanOPName);
|
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.
|
* 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
|
// get current profiling task, check need profiling
|
||||||
final ProfileTaskExecutionContext executionContext = taskExecutionContext.get();
|
final ProfileTaskExecutionContext executionContext = taskExecutionContext.get();
|
||||||
if (executionContext == null) {
|
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
|
@Override
|
||||||
public void afterMainThreadFinish(TracingContext tracingContext) {
|
public void afterMainThreadFinish(TracingContext tracingContext) {
|
||||||
if (tracingContext.isProfiling()) {
|
if (tracingContext.profileStatus().isBeingWatched()) {
|
||||||
// stop profiling tracing context
|
// stop profiling tracing context
|
||||||
ProfileTaskExecutionContext currentExecutionContext = taskExecutionContext.get();
|
ProfileTaskExecutionContext currentExecutionContext = taskExecutionContext.get();
|
||||||
if (currentExecutionContext != null) {
|
if (currentExecutionContext != null) {
|
||||||
|
|
|
||||||
|
|
@ -81,9 +81,9 @@ public class ProfileThread implements Runnable {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (currentProfiler.profilingStatus()) {
|
switch (currentProfiler.profilingStatus().get()) {
|
||||||
|
|
||||||
case READY:
|
case PENDING:
|
||||||
// check tracing context running time
|
// check tracing context running time
|
||||||
currentProfiler.startProfilingIfNeed();
|
currentProfiler.startProfilingIfNeed();
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ public class ThreadProfiler {
|
||||||
private long profilingMaxTimeMills;
|
private long profilingMaxTimeMills;
|
||||||
|
|
||||||
// after min duration threshold check, it will start dump
|
// after min duration threshold check, it will start dump
|
||||||
private ProfilingStatus profilingStatus = ProfilingStatus.READY;
|
private final ProfileStatusReference profilingStatus;
|
||||||
// thread dump sequence
|
// thread dump sequence
|
||||||
private int dumpSequence = 0;
|
private int dumpSequence = 0;
|
||||||
|
|
||||||
|
|
@ -52,6 +52,7 @@ public class ThreadProfiler {
|
||||||
this.traceSegmentId = traceSegmentId;
|
this.traceSegmentId = traceSegmentId;
|
||||||
this.profilingThread = profilingThread;
|
this.profilingThread = profilingThread;
|
||||||
this.executionContext = executionContext;
|
this.executionContext = executionContext;
|
||||||
|
this.profilingStatus = ProfileStatusReference.createWithPending();
|
||||||
this.profilingMaxTimeMills = TimeUnit.MINUTES.toMillis(Config.Profile.MAX_DURATION);
|
this.profilingMaxTimeMills = TimeUnit.MINUTES.toMillis(Config.Profile.MAX_DURATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,7 +63,7 @@ public class ThreadProfiler {
|
||||||
if (System.currentTimeMillis() - tracingContext.createTime() > executionContext.getTask()
|
if (System.currentTimeMillis() - tracingContext.createTime() > executionContext.getTask()
|
||||||
.getMinDurationThreshold()) {
|
.getMinDurationThreshold()) {
|
||||||
this.profilingStartTime = System.currentTimeMillis();
|
this.profilingStartTime = System.currentTimeMillis();
|
||||||
this.profilingStatus = ProfilingStatus.PROFILING;
|
this.tracingContext.profileStatus().updateStatus(ProfileStatus.PROFILING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,7 +71,7 @@ public class ThreadProfiler {
|
||||||
* Stop profiling status
|
* Stop profiling status
|
||||||
*/
|
*/
|
||||||
public void stopProfiling() {
|
public void stopProfiling() {
|
||||||
this.profilingStatus = ProfilingStatus.STOPPED;
|
this.tracingContext.profileStatus().updateStatus(ProfileStatus.STOPPED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -145,7 +146,7 @@ public class ThreadProfiler {
|
||||||
return tracingContext;
|
return tracingContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProfilingStatus profilingStatus() {
|
public ProfileStatusReference profilingStatus() {
|
||||||
return profilingStatus;
|
return profilingStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,12 +109,7 @@ public abstract class AbstractMethodInterceptor implements InstanceMethodsAround
|
||||||
SpanLayer.asHttp(span);
|
SpanLayer.asHttp(span);
|
||||||
|
|
||||||
if (Config.Plugin.SpringMVC.COLLECT_HTTP_PARAMS) {
|
if (Config.Plugin.SpringMVC.COLLECT_HTTP_PARAMS) {
|
||||||
final Map<String, String[]> parameterMap = request.getParameterMap();
|
collectHttpParam(request, span);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stackDepth = new StackDepth();
|
stackDepth = new StackDepth();
|
||||||
|
|
@ -185,6 +180,11 @@ public abstract class AbstractMethodInterceptor implements InstanceMethodsAround
|
||||||
ContextManager.getRuntimeContext().remove(CONTROLLER_METHOD_STACK_DEPTH);
|
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();
|
ContextManager.stopSpan();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,4 +196,13 @@ public abstract class AbstractMethodInterceptor implements InstanceMethodsAround
|
||||||
Class<?>[] argumentsTypes, Throwable t) {
|
Class<?>[] argumentsTypes, Throwable t) {
|
||||||
ContextManager.activeSpan().errorOccurred().log(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,25 +83,14 @@ public class TomcatInvokeInterceptor implements InstanceMethodsAroundInterceptor
|
||||||
SpanLayer.asHttp(span);
|
SpanLayer.asHttp(span);
|
||||||
|
|
||||||
if (Config.Plugin.Tomcat.COLLECT_HTTP_PARAMS) {
|
if (Config.Plugin.Tomcat.COLLECT_HTTP_PARAMS) {
|
||||||
final Map<String, String[]> parameterMap = new HashMap<>();
|
collectHttpParam(request, span);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||||
Object ret) throws Throwable {
|
Object ret) throws Throwable {
|
||||||
|
Request request = (Request) allArguments[0];
|
||||||
HttpServletResponse response = (HttpServletResponse) allArguments[1];
|
HttpServletResponse response = (HttpServletResponse) allArguments[1];
|
||||||
|
|
||||||
AbstractSpan span = ContextManager.activeSpan();
|
AbstractSpan span = ContextManager.activeSpan();
|
||||||
|
|
@ -109,6 +98,10 @@ public class TomcatInvokeInterceptor implements InstanceMethodsAroundInterceptor
|
||||||
span.errorOccurred();
|
span.errorOccurred();
|
||||||
Tags.STATUS_CODE.set(span, Integer.toString(response.getStatus()));
|
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.stopSpan();
|
||||||
ContextManager.getRuntimeContext().remove(Constants.FORWARD_REQUEST_FLAG);
|
ContextManager.getRuntimeContext().remove(Constants.FORWARD_REQUEST_FLAG);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -121,4 +114,20 @@ public class TomcatInvokeInterceptor implements InstanceMethodsAroundInterceptor
|
||||||
span.log(t);
|
span.log(t);
|
||||||
span.errorOccurred();
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ import com.google.common.primitives.Ints;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@ToString
|
@ToString
|
||||||
public class ProfiledSpan implements Comparable<ProfiledSpan> {
|
public class ProfiledSpan implements Comparable<ProfiledSpan> {
|
||||||
|
|
@ -31,6 +33,7 @@ public class ProfiledSpan implements Comparable<ProfiledSpan> {
|
||||||
private String startTime;
|
private String startTime;
|
||||||
private String endTime;
|
private String endTime;
|
||||||
private String endpointName;
|
private String endpointName;
|
||||||
|
private List<ProfiledSpanTag> tags;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(ProfiledSpan o) {
|
public int compareTo(ProfiledSpan o) {
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,11 @@ import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import org.apache.skywalking.e2e.verification.AbstractMatcher;
|
import org.apache.skywalking.e2e.verification.AbstractMatcher;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
|
@ -33,6 +38,7 @@ public class ProfiledSpanMatcher extends AbstractMatcher<ProfiledSpan> {
|
||||||
private String startTime;
|
private String startTime;
|
||||||
private String endTime;
|
private String endTime;
|
||||||
private String endpointName;
|
private String endpointName;
|
||||||
|
private List<ProfiledSpanTagMatcher> tags;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void verify(ProfiledSpan span) {
|
public void verify(ProfiledSpan span) {
|
||||||
|
|
@ -42,5 +48,14 @@ public class ProfiledSpanMatcher extends AbstractMatcher<ProfiledSpan> {
|
||||||
doVerify(startTime, span.getStartTime());
|
doVerify(startTime, span.getStartTime());
|
||||||
doVerify(endTime, span.getEndTime());
|
doVerify(endTime, span.getEndTime());
|
||||||
doVerify(endpointName, span.getEndpointName());
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
@Data
|
||||||
|
@ToString
|
||||||
PROFILING,
|
public class ProfiledSpanTag {
|
||||||
|
private String key;
|
||||||
STOPPED
|
private String value;
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.skywalking.e2e.profile.query;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
import org.apache.skywalking.e2e.verification.AbstractMatcher;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class ProfiledSpanTagMatcher extends AbstractMatcher<ProfiledSpanTag> {
|
||||||
|
private String key;
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void verify(ProfiledSpanTag profiledSpanTag) {
|
||||||
|
if (value == null) {
|
||||||
|
value = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
doVerify(key, profiledSpanTag.getKey());
|
||||||
|
doVerify(value, profiledSpanTag.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -18,6 +18,9 @@
|
||||||
segment: getProfiledSegment(segmentId: $segmentId) {
|
segment: getProfiledSegment(segmentId: $segmentId) {
|
||||||
spans {
|
spans {
|
||||||
spanId parentSpanId serviceCode startTime endTime endpointName type peer component isError layer
|
spanId parentSpanId serviceCode startTime endTime endpointName type peer component isError layer
|
||||||
|
tags {
|
||||||
|
key value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}",
|
}",
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,7 @@ public class ProfileE2E extends SkyWalkingTestAdapter {
|
||||||
final Map<String, String> user = ImmutableMap.of(
|
final Map<String, String> user = ImmutableMap.of(
|
||||||
"name", "SkyWalking", "enableProfiling", String.valueOf(needProfiling)
|
"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 {
|
private void verifyProfiledSegment(String taskId) throws Exception {
|
||||||
|
|
|
||||||
|
|
@ -20,27 +20,62 @@ spans:
|
||||||
startTime: gt 0
|
startTime: gt 0
|
||||||
endTime: gt 0
|
endTime: gt 0
|
||||||
endpointName: /profile/users
|
endpointName: /profile/users
|
||||||
|
tags:
|
||||||
|
- key: url
|
||||||
|
value: not null
|
||||||
|
- key: http.method
|
||||||
|
value: POST
|
||||||
|
- key: http.params
|
||||||
|
value: "e2e=[true]"
|
||||||
- spanId: 1
|
- spanId: 1
|
||||||
parentSpanId: 0
|
parentSpanId: 0
|
||||||
serviceCode: not null
|
serviceCode: not null
|
||||||
startTime: gt 0
|
startTime: gt 0
|
||||||
endTime: gt 0
|
endTime: gt 0
|
||||||
endpointName: H2/JDBI/PreparedStatement/executeQuery
|
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
|
- spanId: 2
|
||||||
parentSpanId: 0
|
parentSpanId: 0
|
||||||
serviceCode: not null
|
serviceCode: not null
|
||||||
startTime: gt 0
|
startTime: gt 0
|
||||||
endTime: gt 0
|
endTime: gt 0
|
||||||
endpointName: H2/JDBI/PreparedStatement/executeUpdate
|
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
|
- spanId: 3
|
||||||
parentSpanId: 0
|
parentSpanId: 0
|
||||||
serviceCode: not null
|
serviceCode: not null
|
||||||
startTime: gt 0
|
startTime: gt 0
|
||||||
endTime: gt 0
|
endTime: gt 0
|
||||||
endpointName: H2/JDBI/Connection/commit
|
endpointName: H2/JDBI/Connection/commit
|
||||||
|
tags:
|
||||||
|
- key: db.type
|
||||||
|
value: sql
|
||||||
|
- key: db.instance
|
||||||
|
value: testdb
|
||||||
|
- key: db.statement
|
||||||
|
value:
|
||||||
- spanId: 4
|
- spanId: 4
|
||||||
parentSpanId: 0
|
parentSpanId: 0
|
||||||
serviceCode: not null
|
serviceCode: not null
|
||||||
startTime: gt 0
|
startTime: gt 0
|
||||||
endTime: gt 0
|
endTime: gt 0
|
||||||
endpointName: H2/JDBI/Connection/commit
|
endpointName: H2/JDBI/Connection/commit
|
||||||
|
tags:
|
||||||
|
- key: db.type
|
||||||
|
value: sql
|
||||||
|
- key: db.instance
|
||||||
|
value: testdb
|
||||||
|
- key: db.statement
|
||||||
|
value:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue