未验证 提交 e5366c09 编写于 作者: L lxliuxuankb 提交者: GitHub

Tag annotation supports returned expression (#4327)

Co-authored-by: wu-sheng's avatar吴晟 Wu Sheng <wu.sheng@foxmail.com>
Co-authored-by: Nkezhenxu94 <kezhenxu94@163.com>
上级 a07bfe14
......@@ -47,6 +47,20 @@ public class CustomizeExpression {
return context;
}
public static Map<String, Object> evaluationReturnContext(Object ret) {
Map<String, Object> context = new HashMap<>();
Field[] fields = ret.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
try {
context.put(field.getName(), field.get(ret));
} catch (Exception e) {
logger.debug("evaluationReturnContext error, ret is {}, exception is {}", ret, e.getMessage());
}
}
return context;
}
public static String parseExpression(String expression, Map<String, Object> context) {
try {
String[] es = expression.split("\\.");
......@@ -56,7 +70,17 @@ public class CustomizeExpression {
logger.debug("parse expression error, expression is {}, exception is {}", expression, e.getMessage());
}
return "null";
}
public static String parseReturnExpression(String expression, Map<String, Object> context) {
try {
String[] es = expression.split("\\.");
Object o = context.get(es[1]);
return o == null ? "null" : String.valueOf(parse(es, o, 1));
} catch (Exception e) {
logger.debug("parse expression error, expression is {}, exception is {}", expression, e.getMessage());
}
return "null";
}
private static Object parse(String[] expressions, Object o, int i) {
......
......@@ -22,8 +22,8 @@ import java.lang.reflect.Method;
import java.util.Map;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.tag.StringTag;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.toolkit.activation.util.TagUtil;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
......@@ -46,23 +46,42 @@ public class TagAnnotationMethodInterceptor implements InstanceMethodsAroundInte
final Tags tags = method.getAnnotation(Tags.class);
if (tags != null && tags.value().length > 0) {
for (final Tag tag : tags.value()) {
tagSpan(activeSpan, tag, context);
if (!TagUtil.isReturnTag(tag.value())) {
TagUtil.tagParamsSpan(activeSpan, context, tag);
}
}
}
final Tag tag = method.getAnnotation(Tag.class);
if (tag != null) {
tagSpan(activeSpan, tag, context);
if (tag != null && !TagUtil.isReturnTag(tag.value())) {
TagUtil.tagParamsSpan(activeSpan, context, tag);
}
}
private void tagSpan(final AbstractSpan span, final Tag tag, final Map<String, Object> context) {
new StringTag(tag.key()).set(span, CustomizeExpression.parseExpression(tag.value(), context));
}
@Override
public Object afterMethod(final EnhancedInstance objInst, final Method method, final Object[] allArguments,
final Class<?>[] argumentsTypes, final Object ret) {
public Object afterMethod(
final EnhancedInstance objInst,
final Method method,
final Object[] allArguments,
final Class<?>[] argumentsTypes,
final Object ret) {
if (ret == null || !ContextManager.isActive()) {
return ret;
}
final AbstractSpan localSpan = ContextManager.activeSpan();
final Map<String, Object> context = CustomizeExpression.evaluationReturnContext(ret);
final Tags tags = method.getAnnotation(Tags.class);
if (tags != null && tags.value().length > 0) {
for (final Tag tag : tags.value()) {
if (TagUtil.isReturnTag(tag.value())) {
TagUtil.tagReturnSpanSpan(localSpan, context, tag);
}
}
}
final Tag tag = method.getAnnotation(Tag.class);
if (tag != null && TagUtil.isReturnTag(tag.value())) {
TagUtil.tagReturnSpanSpan(localSpan, context, tag);
}
return ret;
}
......
......@@ -22,8 +22,8 @@ import java.lang.reflect.Method;
import java.util.Map;
import org.apache.skywalking.apm.agent.core.conf.Config;
import org.apache.skywalking.apm.agent.core.context.tag.StringTag;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.toolkit.activation.util.TagUtil;
import org.apache.skywalking.apm.agent.core.util.CustomizeExpression;
import org.apache.skywalking.apm.toolkit.trace.Tag;
import org.apache.skywalking.apm.toolkit.trace.Tags;
......@@ -56,24 +56,41 @@ public class TraceAnnotationMethodInterceptor implements InstanceMethodsAroundIn
final Tags tags = method.getAnnotation(Tags.class);
if (tags != null && tags.value().length > 0) {
for (final Tag tag : tags.value()) {
tagSpan(localSpan, tag, context);
if (!TagUtil.isReturnTag(tag.value())) {
TagUtil.tagParamsSpan(localSpan, context, tag);
}
}
}
final Tag tag = method.getAnnotation(Tag.class);
if (tag != null) {
tagSpan(localSpan, tag, context);
if (tag != null && !TagUtil.isReturnTag(tag.value())) {
TagUtil.tagParamsSpan(localSpan, context, tag);
}
}
private void tagSpan(final AbstractSpan span, final Tag tag, final Map<String, Object> context) {
new StringTag(tag.key()).set(span, CustomizeExpression.parseExpression(tag.value(), context));
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) throws Throwable {
ContextManager.stopSpan();
try {
if (ret == null) {
return ret;
}
final AbstractSpan localSpan = ContextManager.activeSpan();
final Map<String, Object> context = CustomizeExpression.evaluationReturnContext(ret);
final Tags tags = method.getAnnotation(Tags.class);
if (tags != null && tags.value().length > 0) {
for (final Tag tag : tags.value()) {
if (TagUtil.isReturnTag(tag.value())) {
TagUtil.tagReturnSpanSpan(localSpan, context, tag);
}
}
}
final Tag tag = method.getAnnotation(Tag.class);
if (tag != null && TagUtil.isReturnTag(tag.value())) {
TagUtil.tagReturnSpanSpan(localSpan, context, tag);
}
} finally {
ContextManager.stopSpan();
}
return ret;
}
......
/*
* 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.toolkit.activation.util;
import java.util.Map;
import org.apache.skywalking.apm.agent.core.context.tag.StringTag;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.util.CustomizeExpression;
import org.apache.skywalking.apm.toolkit.trace.Tag;
public class TagUtil {
public static void tagParamsSpan(final AbstractSpan span, final Map<String, Object> context,
final Tag tag) {
new StringTag(tag.key()).set(span, CustomizeExpression.parseExpression(tag.value(), context));
}
public static void tagReturnSpanSpan(final AbstractSpan span, final Map<String, Object> context,
final Tag tag) {
new StringTag(tag.key()).set(span, CustomizeExpression.parseReturnExpression(tag.value(), context));
}
public static Boolean isReturnTag(String expression) {
String[] es = expression.split("\\.");
return es.length == 2 && "returnedObj".equals(es[0]);
}
}
/*
* 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.toolkit.activation.trace;
import java.lang.reflect.Method;
import java.util.List;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.core.context.util.TagValuePair;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
import org.apache.skywalking.apm.agent.test.helper.SpanHelper;
import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
import org.apache.skywalking.apm.agent.test.tools.SpanAssert;
import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import org.apache.skywalking.apm.toolkit.trace.Tag;
import org.apache.skywalking.apm.toolkit.trace.Tags;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(TracingSegmentRunner.class)
public class TagAnnotationTest {
@SegmentStoragePoint
private SegmentStorage storage;
@Rule
public AgentServiceRule serviceRule = new AgentServiceRule();
@Mock
private EnhancedInstance enhancedInstance;
private TagAnnotationMethodInterceptor methodInterceptor;
private ActiveSpanTagInterceptor tagInterceptor;
private Object[] tagParameters;
private Class[] tagParameterTypes;
@Before
public void setUp() throws Exception {
methodInterceptor = new TagAnnotationMethodInterceptor();
tagInterceptor = new ActiveSpanTagInterceptor();
tagParameters = new Object[] {"testTagKey", "testTagValue"};
tagParameterTypes = new Class[] {String.class, String.class};
String operationName = "testMethod";
ContextManager.createLocalSpan(operationName);
}
@Test
public void testTraceWithTag() throws Throwable {
Method testMethodWithTag = TestAnnotationMethodClass.class.getDeclaredMethod("testMethodWithTag", String.class);
methodInterceptor.beforeMethod(enhancedInstance, testMethodWithTag, new Object[]{"zhangsan"}, null, null);
methodInterceptor.afterMethod(enhancedInstance, testMethodWithTag, null, null, null);
ContextManager.stopSpan();
assertThat(storage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = storage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertThat(spans.size(), is(1));
AbstractTracingSpan tracingSpan = spans.get(0);
assertThat(tracingSpan.getOperationName(), is("testMethod"));
SpanAssert.assertLogSize(tracingSpan, 0);
SpanAssert.assertTagSize(tracingSpan, 1);
List<TagValuePair> tags = SpanHelper.getTags(tracingSpan);
assertThat(tags.get(0).getKey().key(), is("username"));
assertThat(tags.get(0).getValue(), is("zhangsan"));
}
@Test
public void testTraceWithReturnTag() throws Throwable {
Method testMethodWithTag = TestAnnotationMethodClass.class.getDeclaredMethod("testMethodWithReturnTag", String.class, Integer.class);
methodInterceptor.beforeMethod(enhancedInstance, testMethodWithTag, new Object[]{"lisi", 14}, null, null);
methodInterceptor.afterMethod(enhancedInstance, testMethodWithTag, null, null, new User("lisi", 14));
ContextManager.stopSpan();
assertThat(storage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = storage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertThat(spans.size(), is(1));
AbstractTracingSpan tracingSpan = spans.get(0);
assertThat(tracingSpan.getOperationName(), is("testMethod"));
SpanAssert.assertLogSize(tracingSpan, 0);
SpanAssert.assertTagSize(tracingSpan, 1);
List<TagValuePair> tags = SpanHelper.getTags(tracingSpan);
assertThat(tags.get(0).getKey().key(), is("username"));
assertThat(tags.get(0).getValue(), is("lisi"));
}
@Test
public void testTraceWithTags() throws Throwable {
Method testMethodWithTags = TestAnnotationMethodClass.class.getDeclaredMethod("testMethodWithTags", String.class, Integer.class);
methodInterceptor.beforeMethod(enhancedInstance, testMethodWithTags, new Object[]{"lisi", 14}, null, null);
methodInterceptor.afterMethod(enhancedInstance, testMethodWithTags, null, null, new User("lisi", 14));
ContextManager.stopSpan();
assertThat(storage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = storage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertThat(spans.size(), is(1));
AbstractTracingSpan tracingSpan = spans.get(0);
assertThat(tracingSpan.getOperationName(), is("testMethod"));
SpanAssert.assertLogSize(tracingSpan, 0);
SpanAssert.assertTagSize(tracingSpan, 2);
List<TagValuePair> tags = SpanHelper.getTags(tracingSpan);
assertThat(tags.get(0).getKey().key(), is("username"));
assertThat(tags.get(0).getValue(), is("lisi"));
assertThat(tags.get(1).getKey().key(), is("info"));
assertThat(tags.get(1).getValue(), is("username=lisi,age=14"));
}
private class TestAnnotationMethodClass {
@Tag(key = "username", value = "arg[0]")
public void testMethodWithTag(String username) {
}
@Tag(key = "username", value = "returnedObj.username")
public User testMethodWithReturnTag(String username, Integer age) {
return new User(username, age);
}
@Tags({@Tag(key = "username", value = "arg[0]"), @Tag(key = "info", value = "returnedObj.info")})
public User testMethodWithTags(String username, Integer age) {
return new User(username, age);
}
}
private class User {
private String username;
private Integer age;
private String info;
public User(String username, Integer age) {
this.username = username;
this.age = age;
info = String.format("username=%s,age=%s", username, age);
}
}
}
......@@ -20,6 +20,7 @@ package org.apache.skywalking.apm.toolkit.activation.trace;
import java.lang.reflect.Method;
import java.util.List;
import lombok.AllArgsConstructor;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.core.context.util.TagValuePair;
......@@ -31,6 +32,7 @@ import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
import org.apache.skywalking.apm.agent.test.tools.SpanAssert;
import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import org.apache.skywalking.apm.toolkit.trace.Tag;
import org.apache.skywalking.apm.toolkit.trace.Trace;
import org.junit.Before;
import org.junit.Rule;
......@@ -98,10 +100,12 @@ public class TraceAnnotationTest {
}
@Test
public void testTrace() throws Throwable {
Method withOperationNameMethod = TestAnnotationMethodClass.class.getDeclaredMethod("testMethodWithDefaultValue");
methodInterceptor.beforeMethod(enhancedInstance, withOperationNameMethod, null, null, null);
methodInterceptor.afterMethod(enhancedInstance, withOperationNameMethod, null, null, null);
public void testTraceWithTag() throws Throwable {
Method testMethodWithTag = TestAnnotationMethodClass.class.getDeclaredMethod("testMethodWithTag", String.class);
methodInterceptor.beforeMethod(enhancedInstance, testMethodWithTag, new Object[]{"zhangsan"}, null, null);
tagInterceptor.beforeMethod(TestAnnotationMethodClass.class, testMethodWithTag, tagParameters, tagParameterTypes, null);
tagInterceptor.afterMethod(TestAnnotationMethodClass.class, testMethodWithTag, tagParameters, tagParameterTypes, null);
methodInterceptor.afterMethod(enhancedInstance, testMethodWithTag, null, null, null);
assertThat(storage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = storage.getTraceSegments().get(0);
......@@ -109,8 +113,51 @@ public class TraceAnnotationTest {
assertThat(spans.size(), is(1));
AbstractTracingSpan tracingSpan = spans.get(0);
assertThat(tracingSpan.getOperationName(), is(TestAnnotationMethodClass.class.getName() + "." + withOperationNameMethod
.getName() + "()"));
assertThat(tracingSpan.getOperationName(), is("testMethod"));
SpanAssert.assertLogSize(tracingSpan, 0);
SpanAssert.assertTagSize(tracingSpan, 2);
List<TagValuePair> tags = SpanHelper.getTags(tracingSpan);
assertThat(tags.get(0).getKey().key(), is("username"));
assertThat(tags.get(0).getValue(), is("zhangsan"));
assertThat(tags.get(1).getKey().key(), is("testTagKey"));
assertThat(tags.get(1).getValue(), is("testTagValue"));
}
@Test
public void testTraceWithReturnTag() throws Throwable {
Method testMethodWithReturnTag = TestAnnotationMethodClass.class.getDeclaredMethod("testMethodWithReturnTag", String.class, Integer.class);
methodInterceptor.beforeMethod(enhancedInstance, testMethodWithReturnTag, new Object[]{"lisi", 14}, null, null);
tagInterceptor.beforeMethod(TestAnnotationMethodClass.class, testMethodWithReturnTag, tagParameters, tagParameterTypes, null);
tagInterceptor.afterMethod(TestAnnotationMethodClass.class, testMethodWithReturnTag, tagParameters, tagParameterTypes, null);
methodInterceptor.afterMethod(enhancedInstance, testMethodWithReturnTag, null, null, new User("lisi", 14));
assertThat(storage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = storage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertThat(spans.size(), is(1));
AbstractTracingSpan tracingSpan = spans.get(0);
assertThat(tracingSpan.getOperationName(), is("testMethod"));
SpanAssert.assertLogSize(tracingSpan, 0);
SpanAssert.assertTagSize(tracingSpan, 2);
List<TagValuePair> tags = SpanHelper.getTags(tracingSpan);
assertThat(tags.get(0).getKey().key(), is("testTagKey"));
assertThat(tags.get(0).getValue(), is("testTagValue"));
assertThat(tags.get(1).getKey().key(), is("username"));
assertThat(tags.get(1).getValue(), is("lisi"));
}
@Test
public void testTrace() throws Throwable {
Method testMethodWithDefaultValue = TestAnnotationMethodClass.class.getDeclaredMethod("testMethodWithDefaultValue");
methodInterceptor.beforeMethod(enhancedInstance, testMethodWithDefaultValue, null, null, null);
methodInterceptor.afterMethod(enhancedInstance, testMethodWithDefaultValue, null, null, null);
assertThat(storage.getTraceSegments().size(), is(1));
TraceSegment traceSegment = storage.getTraceSegments().get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertThat(spans.size(), is(1));
AbstractTracingSpan tracingSpan = spans.get(0);
assertThat(tracingSpan.getOperationName(), is(TestAnnotationMethodClass.class.getName() + "." + testMethodWithDefaultValue.getName() + "()"));
SpanAssert.assertLogSize(tracingSpan, 0);
SpanAssert.assertTagSize(tracingSpan, 0);
}
......@@ -120,8 +167,25 @@ public class TraceAnnotationTest {
public void testMethodWithOperationName() {
}
@Trace(operationName = "testMethod")
@Tag(key = "username", value = "arg[0]")
public void testMethodWithTag(String username) {
}
@Trace(operationName = "testMethod")
@Tag(key = "username", value = "returnedObj.username")
public User testMethodWithReturnTag(String username, Integer age) {
return new User(username, age);
}
@Trace
public void testMethodWithDefaultValue() {
}
}
@AllArgsConstructor
private class User {
private String username;
private Integer age;
}
}
......@@ -39,12 +39,16 @@ ActiveSpan.debug("Test-debug-Msg");
/**
* The codes below will generate a span,
* and two tags, keys are `tag1` and `tag2`, values are the passed-in parameters, respectively
* and two types of tags,
one type tag: keys are `tag1` and `tag2`, values are the passed-in parameters, respectively,
the other type tag: keys are `username` and `age`, values are the return value in User, respectively
*/
@Trace
@Tag(key = "tag1", value = "arg[0]")
@Tag(key = "tag2", value = "arg[1]")
public void methodYouWantToTrace(String param1, String param2) {
@Tag(key = "username", value = "returnedObj.username")
@Tag(key = "age", value = "returnedObj.age")
public User methodYouWantToTrace(String param1, String param2) {
// ...
}
```
......
......@@ -145,6 +145,21 @@ segmentItems:
tags:
- {key: p1, value: testTagAnnotationParam1}
- {key: p2, value: testTagAnnotationParam2}
- operationName: test.org.apache.skywalking.apm.testcase.toolkit.controller.TestService.testTagAnnotationReturnInfo(java.lang.String,java.lang.Integer)
operationId: 0
parentSpanId: 0
spanId: 8
spanLayer: Unknown
startTime: nq 0
endTime: nq 0
componentId: 0
componentName: ''
isError: false
spanType: Local
peer: ''
peerId: 0
tags:
- {key: username, value: zhangsan}
- operationName: /case/tool-kit
operationId: 0
parentSpanId: -1
......
/*
* 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.toolkit.model;
public class User {
private String username;
private Integer age;
public User(String username, Integer age) {
this.username = username;
this.age = age;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
......@@ -47,6 +47,7 @@ public class TestController {
testService.testErrorMsg();
testService.testErrorThrowable();
testService.testTagAnnotation("testTagAnnotationParam1", "testTagAnnotationParam2");
testService.testTagAnnotationReturnInfo("zhangsan", 15);
testService.asyncCallable(() -> {
visit("http://localhost:8080/apm-toolkit-trace-scenario/case/asyncVisit/callable");
return true;
......
......@@ -18,6 +18,7 @@
package test.org.apache.skywalking.apm.testcase.toolkit.controller;
import org.apache.skywalking.apm.toolkit.model.User;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
......@@ -72,6 +73,11 @@ public class TestService {
ActiveSpan.debug("TestDebugMsg");
}
@Trace
@Tag(key = "username", value = "returnedObj.username")
public User testTagAnnotationReturnInfo(final String username, final Integer age) {
return new User(username, age);
}
@Trace
@Tag(key = "testTag", value = "arg[0]")
public void testInfo(final String testInfoParam) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册