未验证 提交 ace781ff 编写于 作者: 静夜思朝颜's avatar 静夜思朝颜 提交者: GitHub

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: NMrproliu <mrproliu@lagou.com>
Co-authored-by: Nkezhenxu94 <kezhenxu94@163.com>
上级 a9d34e3b
...@@ -224,4 +224,5 @@ public class ContextManager implements BootService { ...@@ -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; ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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;
......
/*
* 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
}
/*
* 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 { ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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; ...@@ -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> { ...@@ -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; ...@@ -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> { ...@@ -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> { ...@@ -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 @@ ...@@ -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;
} }
/*
* 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 @@ ...@@ -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 { ...@@ -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: ...@@ -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:
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册