* Fix #2546

* Change the stackdepth type

* Fix bug

* Fix CI failed
This commit is contained in:
Xin,Zhang 2019-04-29 11:41:57 +08:00 committed by 吴晟 Wu Sheng
parent f02300a945
commit 31cb96d99c
7 changed files with 185 additions and 29 deletions

View File

@ -32,6 +32,7 @@ public final class SpringTestCaseHelper {
ContextManager.getRuntimeContext().put(Constants.RESPONSE_KEY_IN_RUNTIME_CONTEXT, response);
a.handleCase();
ContextManager.stopSpan();
ContextManager.getRuntimeContext().remove(Constants.CONTROLLER_METHOD_STACK_DEPTH);
}
public interface CaseHandler {

View File

@ -39,4 +39,6 @@ public class Constants {
public static final String FORWARD_REQUEST_FLAG = "SW_FORWARD_REQUEST_FLAG";
public static final String WEBFLUX_REQUEST_KEY = "SW_WEBFLUX_REQUEST_KEY";
public static final String CONTROLLER_METHOD_STACK_DEPTH = "SW_CONTROLLER_METHOD_STACK_DEPTH";
}

View File

@ -0,0 +1,24 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.skywalking.apm.plugin.spring.mvc.commons.exception;
public class IllegalMethodStackDepthException extends RuntimeException {
public IllegalMethodStackDepthException() {
super("Please submit an new issue to Apache Skywalking if this Exception was happened.");
}
}

View File

@ -0,0 +1,24 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.skywalking.apm.plugin.spring.mvc.commons.exception;
public class ServletResponseNotFoundException extends RuntimeException {
public ServletResponseNotFoundException() {
super("Please submit an new issue to Apache Skywalking if this Exception was happened.");
}
}

View File

@ -34,7 +34,10 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInt
import org.apache.skywalking.apm.agent.core.util.MethodUtil;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import org.apache.skywalking.apm.plugin.spring.mvc.commons.EnhanceRequireObjectCache;
import org.apache.skywalking.apm.plugin.spring.mvc.commons.exception.IllegalMethodStackDepthException;
import org.apache.skywalking.apm.plugin.spring.mvc.commons.exception.ServletResponseNotFoundException;
import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.CONTROLLER_METHOD_STACK_DEPTH;
import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.FORWARD_REQUEST_FLAG;
import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.REQUEST_KEY_IN_RUNTIME_CONTEXT;
import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.RESPONSE_KEY_IN_RUNTIME_CONTEXT;
@ -44,6 +47,7 @@ import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.RESP
*/
public abstract class AbstractMethodInterceptor implements InstanceMethodsAroundInterceptor {
public abstract String getRequestURL(Method method);
public abstract String getAcceptedMethodTypes(Method method);
@Override
@ -75,21 +79,48 @@ public abstract class AbstractMethodInterceptor implements InstanceMethodsAround
HttpServletRequest request = (HttpServletRequest)ContextManager.getRuntimeContext().get(REQUEST_KEY_IN_RUNTIME_CONTEXT);
if (request != null) {
ContextCarrier contextCarrier = new ContextCarrier();
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
next.setHeadValue(request.getHeader(next.getHeadKey()));
StackDepth stackDepth = (StackDepth)ContextManager.getRuntimeContext().get(CONTROLLER_METHOD_STACK_DEPTH);
if (stackDepth == null) {
ContextCarrier contextCarrier = new ContextCarrier();
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
next.setHeadValue(request.getHeader(next.getHeadKey()));
}
AbstractSpan span = ContextManager.createEntrySpan(operationName, contextCarrier);
Tags.URL.set(span, request.getRequestURL().toString());
Tags.HTTP.METHOD.set(span, request.getMethod());
span.setComponent(ComponentsDefine.SPRING_MVC_ANNOTATION);
SpanLayer.asHttp(span);
stackDepth = new StackDepth();
ContextManager.getRuntimeContext().put(CONTROLLER_METHOD_STACK_DEPTH, stackDepth);
} else {
AbstractSpan span =
ContextManager.createLocalSpan(buildOperationName(objInst, method));
span.setComponent(ComponentsDefine.SPRING_MVC_ANNOTATION);
}
AbstractSpan span = ContextManager.createEntrySpan(operationName, contextCarrier);
Tags.URL.set(span, request.getRequestURL().toString());
Tags.HTTP.METHOD.set(span, request.getMethod());
span.setComponent(ComponentsDefine.SPRING_MVC_ANNOTATION);
SpanLayer.asHttp(span);
stackDepth.increment();
}
}
private String buildOperationName(Object invoker, Method method) {
StringBuilder operationName = new StringBuilder(invoker.getClass().getName())
.append(".").append(method.getName()).append("(");
for (Class<?> type : method.getParameterTypes()) {
operationName.append(type.getName()).append(",");
}
if (method.getParameterTypes().length > 0) {
operationName = operationName.deleteCharAt(operationName.length() - 1);
}
return operationName.append(")").toString();
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) throws Throwable {
@ -102,19 +133,34 @@ public abstract class AbstractMethodInterceptor implements InstanceMethodsAround
return ret;
}
HttpServletResponse response = (HttpServletResponse)ContextManager.getRuntimeContext().get(RESPONSE_KEY_IN_RUNTIME_CONTEXT);
try {
if (response != null) {
AbstractSpan span = ContextManager.activeSpan();
HttpServletRequest request = (HttpServletRequest)ContextManager.getRuntimeContext().get(REQUEST_KEY_IN_RUNTIME_CONTEXT);
if (request != null) {
StackDepth stackDepth = (StackDepth)ContextManager.getRuntimeContext().get(CONTROLLER_METHOD_STACK_DEPTH);
if (stackDepth == null) {
throw new IllegalMethodStackDepthException();
} else {
stackDepth.decrement();
}
AbstractSpan span = ContextManager.activeSpan();
if (stackDepth.depth() == 0) {
HttpServletResponse response = (HttpServletResponse)ContextManager.getRuntimeContext().get(RESPONSE_KEY_IN_RUNTIME_CONTEXT);
if (response == null) {
throw new ServletResponseNotFoundException();
}
if (response.getStatus() >= 400) {
span.errorOccurred();
Tags.STATUS_CODE.set(span, Integer.toString(response.getStatus()));
ContextManager.getRuntimeContext().remove(REQUEST_KEY_IN_RUNTIME_CONTEXT);
ContextManager.getRuntimeContext().remove(RESPONSE_KEY_IN_RUNTIME_CONTEXT);
}
ContextManager.stopSpan();
}
} finally {
ContextManager.getRuntimeContext().remove(REQUEST_KEY_IN_RUNTIME_CONTEXT);
ContextManager.getRuntimeContext().remove(RESPONSE_KEY_IN_RUNTIME_CONTEXT);
ContextManager.stopSpan();
}
return ret;

View File

@ -0,0 +1,41 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.skywalking.apm.plugin.spring.mvc.commons.interceptor;
public class StackDepth {
private int stackDepth;
public StackDepth() {
this.stackDepth = 0;
}
public int depth() {
return this.stackDepth;
}
public StackDepth increment() {
this.stackDepth++;
return this;
}
public StackDepth decrement() {
this.stackDepth--;
return this;
}
}

View File

@ -30,7 +30,9 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceM
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
import org.apache.skywalking.apm.plugin.spring.mvc.commons.EnhanceRequireObjectCache;
import org.apache.skywalking.apm.plugin.spring.mvc.commons.interceptor.StackDepth;
import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.CONTROLLER_METHOD_STACK_DEPTH;
import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.FORWARD_REQUEST_FLAG;
import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.WEBFLUX_REQUEST_KEY;
@ -39,6 +41,7 @@ import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.WEBF
*/
public abstract class AbstractMethodInterceptor implements InstanceMethodsAroundInterceptor {
public abstract String getRequestURL(Method method);
public abstract String getAcceptedMethodTypes(Method method);
@Override
@ -64,18 +67,30 @@ public abstract class AbstractMethodInterceptor implements InstanceMethodsAround
HttpRequest request = (HttpRequest)ContextManager.getRuntimeContext().get(WEBFLUX_REQUEST_KEY);
if (request != null) {
ContextCarrier contextCarrier = new ContextCarrier();
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
next.setHeadValue(request.headers().get(next.getHeadKey()));
StackDepth stackDepth = (StackDepth)ContextManager.getRuntimeContext().get(CONTROLLER_METHOD_STACK_DEPTH);
if (stackDepth == null) {
ContextCarrier contextCarrier = new ContextCarrier();
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
next.setHeadValue(request.headers().get(next.getHeadKey()));
}
AbstractSpan span = ContextManager.createEntrySpan(requestURL, contextCarrier);
Tags.URL.set(span, request.uri());
Tags.HTTP.METHOD.set(span, request.method().name());
span.setComponent(ComponentsDefine.SPRING_MVC_ANNOTATION);
SpanLayer.asHttp(span);
stackDepth = new StackDepth();
} else {
AbstractSpan span = ContextManager.createLocalSpan(objInst.getClass().getName() + "/" + method.getName());
span.setComponent(ComponentsDefine.SPRING_MVC_ANNOTATION);
}
AbstractSpan span = ContextManager.createEntrySpan(requestURL, contextCarrier);
Tags.URL.set(span, request.uri());
Tags.HTTP.METHOD.set(span, request.method().name());
span.setComponent(ComponentsDefine.SPRING_MVC_ANNOTATION);
SpanLayer.asHttp(span);
stackDepth.increment();
}
}
@ -91,7 +106,10 @@ public abstract class AbstractMethodInterceptor implements InstanceMethodsAround
return ret;
}
ContextManager.stopSpan();
HttpRequest request = (HttpRequest)ContextManager.getRuntimeContext().get(WEBFLUX_REQUEST_KEY);
if (request != null) {
ContextManager.stopSpan();
}
return ret;
}