This is an automated email from the ASF dual-hosted git repository. wusheng pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-skywalking.git
The following commit(s) were added to refs/heads/master by this push: new 8612f80 add jdk-cross-thread-plugin (#845) 8612f80 is described below commit 8612f80260c8dd691a5c8308625fae5fca03ade2 Author: carlvine500 <carlvine...@163.com> AuthorDate: Thu Apr 12 20:51:09 2018 +0800 add jdk-cross-thread-plugin (#845) * add jdk-cross-thread-plugin --- .../apm/toolkit/trace/CallableWrapper.java | 41 ++++++++ .../apm/toolkit/trace/TraceCrossThread.java | 32 ++++++ .../apm/agent/core/context/ContextManager.java | 1 + .../apm-sdk-plugin/jdk-cross-thread-plugin/pom.xml | 59 +++++++++++ .../CallableOrRunnableConstructInterceptor.java | 35 +++++++ .../CallableOrRunnableInvokeInterceptor.java | 54 ++++++++++ .../define/CallableOrRunnableInstrumentation.java | 85 ++++++++++++++++ .../src/main/resources/skywalking-plugin.def | 17 ++++ .../thread/CallableOrRunnableInterceptorTest.java | 112 +++++++++++++++++++++ apm-sniffer/apm-sdk-plugin/pom.xml | 1 + 10 files changed, 437 insertions(+) diff --git a/apm-application-toolkit/apm-toolkit-trace/src/main/java/org/apache/skywalking/apm/toolkit/trace/CallableWrapper.java b/apm-application-toolkit/apm-toolkit-trace/src/main/java/org/apache/skywalking/apm/toolkit/trace/CallableWrapper.java new file mode 100644 index 0000000..32c8f31 --- /dev/null +++ b/apm-application-toolkit/apm-toolkit-trace/src/main/java/org/apache/skywalking/apm/toolkit/trace/CallableWrapper.java @@ -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.toolkit.trace; + +import java.util.concurrent.Callable; + +/** + * @author carlvine500 + */ +@TraceCrossThread +public class CallableWrapper<V> implements Callable<V> { + final Callable<V> callable; + + public static <V> CallableWrapper of(Callable<V> r) { + return new CallableWrapper<V>(r); + } + + public CallableWrapper(Callable<V> callable) { + this.callable = callable; + } + + @Override + public V call() throws Exception { + return callable.call(); + } +} \ No newline at end of file diff --git a/apm-application-toolkit/apm-toolkit-trace/src/main/java/org/apache/skywalking/apm/toolkit/trace/TraceCrossThread.java b/apm-application-toolkit/apm-toolkit-trace/src/main/java/org/apache/skywalking/apm/toolkit/trace/TraceCrossThread.java new file mode 100644 index 0000000..1eaf87a --- /dev/null +++ b/apm-application-toolkit/apm-toolkit-trace/src/main/java/org/apache/skywalking/apm/toolkit/trace/TraceCrossThread.java @@ -0,0 +1,32 @@ +/* + * 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.trace; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author carlvine500 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface TraceCrossThread { + +} \ No newline at end of file diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java index b2d3a99..f4f50a0 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java @@ -204,4 +204,5 @@ public class ContextManager implements TracingContextListener, BootService, Igno public static boolean isActive() { return CONTEXT.get() != null; } + } diff --git a/apm-sniffer/apm-sdk-plugin/jdk-cross-thread-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/jdk-cross-thread-plugin/pom.xml new file mode 100644 index 0000000..91354b9 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/jdk-cross-thread-plugin/pom.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright 2017, OpenSkywalking Organization All rights reserved. + ~ + ~ Licensed 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. + ~ + ~ Project repository: https://github.com/OpenSkywalking/skywalking + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>apm-sdk-plugin</artifactId> + <groupId>org.apache.skywalking</groupId> + <version>5.0.0-beta-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>apm-jdk-cross-thread-plugin</artifactId> + <name>jdk-cross-thread-plugin</name> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-deploy-plugin</artifactId> + </plugin> + <plugin> + <!-- 源码插件 --> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + <!-- 发布时自动将源码同时发布的配置 --> + <executions> + <execution> + <id>attach-sources</id> + <goals> + <goal>jar</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/apm-sniffer/apm-sdk-plugin/jdk-cross-thread-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/thread/CallableOrRunnableConstructInterceptor.java b/apm-sniffer/apm-sdk-plugin/jdk-cross-thread-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/thread/CallableOrRunnableConstructInterceptor.java new file mode 100644 index 0000000..3c96f60 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/jdk-cross-thread-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/thread/CallableOrRunnableConstructInterceptor.java @@ -0,0 +1,35 @@ +/* + * 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.jdk.thread; + +import org.apache.skywalking.apm.agent.core.context.ContextManager; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; + +/** + * @author carlvine500 + */ +public class CallableOrRunnableConstructInterceptor implements InstanceConstructorInterceptor { + @Override + public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { + if (ContextManager.isActive()) { + objInst.setSkyWalkingDynamicField(ContextManager.capture()); + } + } + +} diff --git a/apm-sniffer/apm-sdk-plugin/jdk-cross-thread-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/thread/CallableOrRunnableInvokeInterceptor.java b/apm-sniffer/apm-sdk-plugin/jdk-cross-thread-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/thread/CallableOrRunnableInvokeInterceptor.java new file mode 100644 index 0000000..8be7075 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/jdk-cross-thread-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/thread/CallableOrRunnableInvokeInterceptor.java @@ -0,0 +1,54 @@ +/* + * 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.jdk.thread; + +import java.lang.reflect.Method; +import org.apache.skywalking.apm.agent.core.context.ContextManager; +import org.apache.skywalking.apm.agent.core.context.ContextSnapshot; +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; + +/** + * @author carlvine500 + */ +public class CallableOrRunnableInvokeInterceptor implements InstanceMethodsAroundInterceptor { + @Override + public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, + MethodInterceptResult result) throws Throwable { + ContextManager.createLocalSpan("Thread/" + objInst.getClass().getName() + "/" + method.getName()); + ContextSnapshot cachedObjects = (ContextSnapshot)objInst.getSkyWalkingDynamicField(); + if (cachedObjects != null) { + ContextManager.continued(cachedObjects); + } + } + + @Override + public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, + Object ret) throws Throwable { + ContextManager.stopSpan(); + // clear ContextSnapshot + objInst.setSkyWalkingDynamicField(null); + return ret; + } + + @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, + Class<?>[] argumentsTypes, Throwable t) { + ContextManager.activeSpan().errorOccurred().log(t); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/jdk-cross-thread-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/thread/define/CallableOrRunnableInstrumentation.java b/apm-sniffer/apm-sdk-plugin/jdk-cross-thread-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/thread/define/CallableOrRunnableInstrumentation.java new file mode 100644 index 0000000..4a4730e --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/jdk-cross-thread-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/thread/define/CallableOrRunnableInstrumentation.java @@ -0,0 +1,85 @@ +/* + * 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.jdk.thread.define; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine; +import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch; + +import static net.bytebuddy.matcher.ElementMatchers.any; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; +import static org.apache.skywalking.apm.agent.core.plugin.match.ClassAnnotationMatch.byClassAnnotationMatch; + +/** + * {@link CallableOrRunnableInstrumentation} presents that skywalking intercepts all Class with annotation + * "org.skywalking.apm.toolkit.trace.TraceCrossThread" and method named "call" or "run". + * + * @author carlvine500 + */ +public class CallableOrRunnableInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + + public static final String ANNOTATION_NAME = "org.apache.skywalking.apm.toolkit.trace.TraceCrossThread"; + private static final String INIT_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdk.thread.CallableOrRunnableConstructInterceptor"; + private static final String CALL_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdk.thread.CallableOrRunnableInvokeInterceptor"; + private static final String CALL_METHOD_NAME = "call"; + private static final String RUN_METHOD_NAME = "run"; + + @Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[] { + new ConstructorInterceptPoint() { + @Override public ElementMatcher<MethodDescription> getConstructorMatcher() { + return any(); + } + + @Override public String getConstructorInterceptor() { + return INIT_METHOD_INTERCEPTOR; + } + } + }; + } + + @Override + protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[] { + new InstanceMethodsInterceptPoint() { + @Override public ElementMatcher<MethodDescription> getMethodsMatcher() { + return (named(CALL_METHOD_NAME).and(takesArguments(0))) + .or(named(RUN_METHOD_NAME).and(takesArguments(0))); + } + + @Override public String getMethodsInterceptor() { + return CALL_METHOD_INTERCEPTOR; + } + + @Override public boolean isOverrideArgs() { + return false; + } + } + }; + } + + @Override protected ClassMatch enhanceClass() { + return byClassAnnotationMatch(new String[] {ANNOTATION_NAME}); + } + +} diff --git a/apm-sniffer/apm-sdk-plugin/jdk-cross-thread-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/jdk-cross-thread-plugin/src/main/resources/skywalking-plugin.def new file mode 100644 index 0000000..9323cf3 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/jdk-cross-thread-plugin/src/main/resources/skywalking-plugin.def @@ -0,0 +1,17 @@ +# 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. +jdk-cross-thread=org.apache.skywalking.apm.plugin.jdk.thread.define.CallableOrRunnableInstrumentation + diff --git a/apm-sniffer/apm-sdk-plugin/jdk-cross-thread-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdk/thread/CallableOrRunnableInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/jdk-cross-thread-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdk/thread/CallableOrRunnableInterceptorTest.java new file mode 100644 index 0000000..c76d65f --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/jdk-cross-thread-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdk/thread/CallableOrRunnableInterceptorTest.java @@ -0,0 +1,112 @@ +/* + * 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.jdk.thread; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.concurrent.Callable; +import org.junit.Assert; +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 org.apache.skywalking.apm.agent.core.context.ContextSnapshot; +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.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.test.helper.SegmentHelper; +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.TracingSegmentRunner; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +@RunWith(PowerMockRunner.class) +@PowerMockRunnerDelegate(TracingSegmentRunner.class) +public class CallableOrRunnableInterceptorTest { + + private CallableOrRunnableConstructInterceptor constructorInterceptor; + + private CallableOrRunnableInvokeInterceptor callableCallInterceptor; + @Rule + public AgentServiceRule serviceRule = new AgentServiceRule(); + @SegmentStoragePoint + private SegmentStorage segmentStorage; + + private EnhancedInstance enhancedInstance = new EnhancedInstance() { + + private Object object; + + @Override + public Object getSkyWalkingDynamicField() { + return object; + } + + @Override public void setSkyWalkingDynamicField(Object value) { + this.object = value; + } + }; + + @Mock + private ContextSnapshot contextSnapshot; + + private Object[] arguments; + + private Method callMethod; + + @Before + public void setUp() throws NoSuchMethodException { + constructorInterceptor = new CallableOrRunnableConstructInterceptor(); + callableCallInterceptor = new CallableOrRunnableInvokeInterceptor(); + + Callable<String> call = new Callable<String>() { + @Override public String call() throws Exception { + return null; + } + }; + callMethod = call.getClass().getMethod("call"); + arguments = new Object[0]; + } + + @Test + public void testOnConstructor() { + constructorInterceptor.onConstruct(enhancedInstance, null); + Assert.assertNull(enhancedInstance.getSkyWalkingDynamicField()); + } + + @Test + public void testCall() throws Throwable { + + enhancedInstance.setSkyWalkingDynamicField(contextSnapshot); + callableCallInterceptor.beforeMethod(enhancedInstance, callMethod, arguments, null, null); + callableCallInterceptor.afterMethod(enhancedInstance, callMethod, arguments, null, "result"); + + assertThat(segmentStorage.getTraceSegments().size(), is(1)); + TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0); + List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment); + assertThat(spans.size(), is(1)); + + } + +} diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml index 5f780d7..f31c869 100644 --- a/apm-sniffer/apm-sdk-plugin/pom.xml +++ b/apm-sniffer/apm-sdk-plugin/pom.xml @@ -56,6 +56,7 @@ <module>kafka-v1-plugin</module> <module>servicecomb-plugin</module> <module>hystrix-1.x-plugin</module> + <module>jdk-cross-thread-plugin</module> </modules> <packaging>pom</packaging> -- To stop receiving notification emails like this one, please contact wush...@apache.org.