Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/plugins-jdk21-test.0.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ jobs:
matrix:
case:
- spring-6.x-scenario
- jdk-virtual-thread-executor-scenario
steps:
- uses: actions/checkout@v2
with:
Expand Down
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Release Notes.
9.5.0
------------------

* Add the virtual thread executor plugin


All issues and pull requests are [here](https://github.com/apache/skywalking/milestone/236?closed=1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,4 +260,6 @@ public class ComponentsDefine {
public static final OfficialComponent SOLON_MVC = new OfficialComponent(158, "SolonMVC");

public static final OfficialComponent CAFFEINE = new OfficialComponent(160, "Caffeine");

public static final OfficialComponent THREAD_PER_TASK_EXECUTOR = new OfficialComponent(161, "ThreadPerTask-executor");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ID submitted through apache/skywalking#13090

}
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,11 @@ public static final class HTTP {
*/
public static final StringTag THREAD_ID = new StringTag(23, "thread.id");

/**
* THREAD_CARRIER represents the actual operating system thread that carries out the execution of the virtual thread.
*/
public static final StringTag THREAD_CARRIER = new StringTag(24, "thread.carrier");

/**
* Creates a {@code StringTag} with the given key and cache it, if it's created before, simply return it without
* creating a new one.
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
~
-->

<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>bootstrap-plugins</artifactId>
<groupId>org.apache.skywalking</groupId>
<version>9.5.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>apm-jdk-virtual-thread-executor-plugin</artifactId>
<packaging>jar</packaging>

<name>apm-jdk-virtual-thread-executor-plugin</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>


<build>
<plugins>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
</plugin>
</plugins>
</build>
Comment on lines +38 to +44
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you check whether your new module could generate javadoc jar? Another plugin pom.xml has relative configurations to generate that file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you check whether your new module could generate javadoc jar? Another plugin pom.xml has relative configurations to generate that file.

When I added the maven-javadoc-plugin, I could generate the javadoc.jar

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add that plugin, otherwise, this will fail the release process.


</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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;

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;

public class ThreadPerTaskExecutorConstructInterceptor implements InstanceConstructorInterceptor {

@Override
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws Throwable {
if (ContextManager.isActive()) {
objInst.setSkyWalkingDynamicField(ContextManager.capture());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* 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;

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.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
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;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;

import java.lang.reflect.Method;

public class ThreadPerTaskExecutorRunInterceptor implements InstanceMethodsAroundInterceptor {

@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
Object skyWalkingDynamicField = objInst.getSkyWalkingDynamicField();
if (skyWalkingDynamicField == null) {
return;
}

if (!(skyWalkingDynamicField instanceof ContextSnapshot)) {
return;
}

AbstractSpan span = ContextManager.createLocalSpan(getOperationName(objInst, method));
span.setComponent(ComponentsDefine.THREAD_PER_TASK_EXECUTOR);
setCarrierThread(span);

ContextSnapshot contextSnapshot = (ContextSnapshot) skyWalkingDynamicField;
ContextManager.continued(contextSnapshot);
}

@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
if (ContextManager.isActive()) {
ContextManager.stopSpan();
}
return ret;
}

@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
if (ContextManager.isActive()) {
ContextManager.activeSpan().log(t);
}
}

private String getOperationName(EnhancedInstance objInst, Method method) {
return objInst.getClass().getName() + "." + method.getName();
}

private void setCarrierThread(AbstractSpan span) {
String threadInfo = Thread.currentThread().toString();
if (threadInfo.startsWith("VirtualThread")) {
String[] parts = threadInfo.split("@");
if (parts.length >= 1) {
Tags.THREAD_CARRIER.set(span, parts[1]);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* 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.define;

import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;
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 org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch;

import static net.bytebuddy.matcher.ElementMatchers.any;

public class ThreadPerTaskExecutorFutureInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {

private static final String ENHANCE_CLASS = "java.util.concurrent.ThreadPerTaskExecutor$ThreadBoundFuture";

private static final String INTERCEPT_RUN_METHOD = "run";

private static final String INTERCEPT_RUN_HANDLE = "org.apache.skywalking.apm.plugin.ThreadPerTaskExecutorRunInterceptor";

private static final String TASK_RUNNER_CONSTRUCT_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.ThreadPerTaskExecutorConstructInterceptor";

@Override
public boolean isBootstrapInstrumentation() {
return true;
}

@Override
protected ClassMatch enhanceClass() {
return MultiClassNameMatch.byMultiClassMatch(ENHANCE_CLASS);
}

@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[]{
new ConstructorInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getConstructorMatcher() {
return any();
}

@Override
public String getConstructorInterceptor() {
return TASK_RUNNER_CONSTRUCT_METHOD_INTERCEPTOR;
}
}
};
}

@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return ElementMatchers.named(INTERCEPT_RUN_METHOD);
}

@Override
public String getMethodsInterceptor() {
return INTERCEPT_RUN_HANDLE;
}

@Override
public boolean isOverrideArgs() {
return true;
}
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* 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.define;

import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;
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 org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch;

import static net.bytebuddy.matcher.ElementMatchers.any;

public class ThreadPerTaskExecutorTaskRunnerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {

private static final String ENHANCE_CLASS = "java.util.concurrent.ThreadPerTaskExecutor$TaskRunner";

private static final String INTERCEPT_RUN_METHOD = "run";

private static final String INTERCEPT_RUN_HANDLE = "org.apache.skywalking.apm.plugin.ThreadPerTaskExecutorRunInterceptor";

private static final String TASK_RUNNER_CONSTRUCT_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.ThreadPerTaskExecutorConstructInterceptor";

@Override
public boolean isBootstrapInstrumentation() {
return true;
}

@Override
protected ClassMatch enhanceClass() {
return MultiClassNameMatch.byMultiClassMatch(ENHANCE_CLASS);
}

@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[]{
new ConstructorInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getConstructorMatcher() {
return any();
}

@Override
public String getConstructorInterceptor() {
return TASK_RUNNER_CONSTRUCT_METHOD_INTERCEPTOR;
}
}
};
}

@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return ElementMatchers.named(INTERCEPT_RUN_METHOD);
}

@Override
public String getMethodsInterceptor() {
return INTERCEPT_RUN_HANDLE;
}

@Override
public boolean isOverrideArgs() {
return true;
}
}
};
}
}
Loading
Loading