-
Notifications
You must be signed in to change notification settings - Fork 6.6k
Description
Search before asking
- I had searched in the issues and found no similar issues.
Apache SkyWalking Component
Java Agent (apache/skywalking-java)
What happened
I moved the apm-jdk-threadpool-plugin.jar to the plugins directory and started a Spring Boot application. In a controller method, I added an invocation of ThreadPoolExecutor and printed the traceId. However, I noticed that the traceId is showing as "N/A," which means that the ThreadPoolExecutor class has not been enhanced.
What you expected to happen
The ThreadPoolExecutor class should be enhanced and able to print a valid traceId.
How to reproduce
- jdk 1.8
- skywalking agent 8.14.0
- spring boot application (spring boot 2.2.6.RELEASE), add apm-toolkit-trace to pom.xml
- In the plugins directory of the Skywalking agent, keep the following JAR files:
apm-jdk-threadpool-plugin-8.14.0.jar,apm-spring-core-patch-8.14.0.jar, andtomcat-7.x-8.x-plugin-8.14.0.jar. In the activations directory, keep theapm-toolkit-trace-activation-8.14.0.jar. - The controller code for the Spring Boot application is as follows.
@GetMapping(value = "testHello")
public String testHello(){
ThreadPoolExecutor ThreadPoolExecutor = new ThreadPoolExecutor(1,1,1000, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
ThreadPoolExecutor.execute(()->{
log.info("traceId:"+TraceContext.traceId());
});
return "ok";
}
- start the application with skywalking agent
- call the controller method, then see the traceId in log
Anything else
In the reproduction steps mentioned above, if I only keep apm-jdk-threadpool-plugin-8.14.0.jar and tomcat-7.x-8.x-plugin-8.14.0.jar in the plugins directory, excluding apm-spring-core-patch-8.14.0.jar, then the thread pool plugin will work correctly.
This is because when the Skywalking agent performs class transformation on the classes in the application, it first uses the AgentClassLoader to load the corresponding interceptor classes. When the AgentClassLoader loads a class for the first time, it scans the plugins directory and outputs logs. The logs are written using FileWriter, which depends on ThreadPoolExecutor during instantiation. At this point, since the transformation process for the class that needs to be enhanced has not yet completed, I found that the class loading of ThreadPoolExecutor will not trigger the transformation process again (I speculate that this is to avoid circular dependencies during the transform phase in JVM).
In other words, if there are many classes in the plugins that need to be enhanced, but the class loading of ThreadPoolExecutor during application startup is later than the class loading of other classes that need enhancement (i.e., ThreadPoolExecutor is not the first class to be enhanced), it will result in the failure to enhance ThreadPoolExecutor. Excluding apm-spring-core-patch-8.14.0.jar, as mentioned earlier, is to ensure that ThreadPoolExecutor is the first class to be enhanced during application startup.
I have two solutions:
-
Solution A: Avoid scanning the plugins directory when loading interceptor classes. In fact, during the execution of the agent's
premainmethod, theAgentClassLoaderhas already scanned the directory once, and the result of this scan can be reused. -
Solution B: Modify the implementation of
FileWriterto use an alternative approach instead of relying onThreadPoolExecutor. In this case, you can use a combination ofTimerandTimerTaskto schedule periodic log flushing to a file. Additionally, it would be beneficial to make this implementation configurable.
Are you willing to submit PR?
- Yes I am willing to submit a PR!
Code of Conduct
- I agree to follow this project's Code of Conduct