You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by GitBox <gi...@apache.org> on 2021/04/07 03:46:41 UTC

[GitHub] [skywalking] BFergerson opened a new issue #6701: Redefinition support

BFergerson opened a new issue #6701:
URL: https://github.com/apache/skywalking/issues/6701


   Please answer these questions before submitting your issue.
   
   - Why do you submit this issue?
   - [x] Feature or performance improvement
   
   ___
   ### Requirement or improvement
   
   Calling `Instrumentation.retransformClasses())` on a class which SkyWalking has already enhanced will cause issues such as https://github.com/raphw/byte-buddy/issues/908. This issue boils down to SkyWalking not generating the same bytecode modifications each time it's called.
   
   As an example, here is the loaded class after SkyWalking enhancements:
   <details>
     <summary>Decompiled source code</summary>
     
   ```java
   package spp.example.webapp.controller;
   
   import spp.example.webapp.service.*;
   import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.*;
   import java.lang.reflect.*;
   import spp.example.webapp.model.*;
   import java.util.concurrent.*;
   import org.springframework.web.bind.annotation.*;
   import org.springframework.http.*;
   import org.apache.skywalking.apm.toolkit.trace.*;
   import org.slf4j.*;
   
   @RestController
   public class WebappController implements EnhancedInstance
   {
       private static final Logger log;
       private final UserService userService = userService;
       private volatile Object _$EnhancedClassField_ws;
       public static volatile /* synthetic */ InstMethodsInter delegate$v1o0sl0;
       public static volatile /* synthetic */ InstMethodsInter delegate$1p16ip1;
       public static volatile /* synthetic */ ConstructorInter delegate$bn83ge1;
       private static final /* synthetic */ Method cachedValue$5aQdBH3R$tcgf6s2;
       private static final /* synthetic */ Method cachedValue$5aQdBH3R$551d7u2;
       private static final /* synthetic */ Method cachedValue$5aQdBH3R$r5lbqa2;
       private static final /* synthetic */ Method cachedValue$5aQdBH3R$pslu6e0;
       private static final /* synthetic */ Method cachedValue$5aQdBH3R$tv4hlg2;
       private static final /* synthetic */ Method cachedValue$5aQdBH3R$fe38712;
       private static final /* synthetic */ Method cachedValue$5aQdBH3R$moqjd11;
       
       public WebappController(final UserService userService) {
           this(userService, null);
           WebappController.delegate$bn83ge1.intercept((Object)this, new Object[] { userService });
       }
       
       @RequestMapping(value = { "/users" }, method = { RequestMethod.GET })
       public ResponseEntity<Iterable<User>> userList() {
           return (ResponseEntity<Iterable<User>>)WebappController.delegate$1p16ip1.intercept((Object)this, new Object[0], (Callable)new WebappController$auxiliary$rC0tNskD(this), WebappController.cachedValue$5aQdBH3R$tv4hlg2);
       }
       
       @RequestMapping(value = { "/users/{id}" }, method = { RequestMethod.GET })
       public ResponseEntity<User> getUser(@PathVariable final long id) {
           return (ResponseEntity<User>)WebappController.delegate$1p16ip1.intercept((Object)this, new Object[] { id }, (Callable)new WebappController$auxiliary$3VgxmlNG(this, id), WebappController.cachedValue$5aQdBH3R$fe38712);
       }
       
       @RequestMapping(value = { "/users" }, method = { RequestMethod.POST })
       public ResponseEntity<User> createUser(@RequestParam final String firstName, @RequestParam final String lastName) {
           return (ResponseEntity<User>)WebappController.delegate$1p16ip1.intercept((Object)this, new Object[] { firstName, lastName }, (Callable)new WebappController$auxiliary$giwk9nlQ(this, firstName, lastName), WebappController.cachedValue$5aQdBH3R$r5lbqa2);
       }
       
       @RequestMapping(value = { "/users" }, method = { RequestMethod.DELETE })
       public void deleteUser(@RequestParam final String firstName, @RequestParam final String lastName) {
           WebappController.delegate$1p16ip1.intercept((Object)this, new Object[] { firstName, lastName }, (Callable)new WebappController$auxiliary$TTasfNa2(this, firstName, lastName), WebappController.cachedValue$5aQdBH3R$pslu6e0);
       }
       
       @RequestMapping(value = { "/throws-exception" }, method = { RequestMethod.GET })
       public void throwsException() {
           WebappController.delegate$1p16ip1.intercept((Object)this, new Object[0], (Callable)new WebappController$auxiliary$dwKvz7iY(this), WebappController.cachedValue$5aQdBH3R$551d7u2);
       }
       
       @Trace
       private void caughtException() {
           WebappController.delegate$v1o0sl0.intercept((Object)this, new Object[0], (Callable)new WebappController$auxiliary$O6efGa79(this), WebappController.cachedValue$5aQdBH3R$moqjd11);
       }
       
       @Trace
       private void uncaughtException() {
           WebappController.delegate$v1o0sl0.intercept((Object)this, new Object[0], (Callable)new WebappController$auxiliary$7x058cxd(this), WebappController.cachedValue$5aQdBH3R$tcgf6s2);
       }
       
       static {
           ClassLoader.getSystemClassLoader().loadClass("org.apache.skywalking.apm.dependencies.net.bytebuddy.dynamic.Nexus").getMethod("initialize", Class.class, Integer.TYPE).invoke(null, WebappController.class, -1316167843);
           cachedValue$5aQdBH3R$tcgf6s2 = WebappController.class.getDeclaredMethod("uncaughtException", (Class<?>[])new Class[0]);
           cachedValue$5aQdBH3R$551d7u2 = WebappController.class.getMethod("throwsException", (Class<?>[])new Class[0]);
           cachedValue$5aQdBH3R$r5lbqa2 = WebappController.class.getMethod("createUser", String.class, String.class);
           cachedValue$5aQdBH3R$pslu6e0 = WebappController.class.getMethod("deleteUser", String.class, String.class);
           cachedValue$5aQdBH3R$tv4hlg2 = WebappController.class.getMethod("userList", (Class<?>[])new Class[0]);
           cachedValue$5aQdBH3R$fe38712 = WebappController.class.getMethod("getUser", Long.TYPE);
           cachedValue$5aQdBH3R$moqjd11 = WebappController.class.getDeclaredMethod("caughtException", (Class<?>[])new Class[0]);
           log = LoggerFactory.getLogger((Class)WebappController.class);
       }
       
       public void setSkyWalkingDynamicField(final Object $EnhancedClassField_ws) {
           this._$EnhancedClassField_ws = $EnhancedClassField_ws;
       }
       
       public Object getSkyWalkingDynamicField() {
           return this._$EnhancedClassField_ws;
       }
   }
   ```
   </details>
   
   This is the same class after calling `Instrumentation.retransformClasses()`:
   <details>
     <summary>Decompiled source code</summary>
     
   ```java
   package spp.example.webapp.controller;
   
   import spp.example.webapp.service.*;
   import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.*;
   import java.lang.reflect.*;
   import spp.example.webapp.model.*;
   import java.util.concurrent.*;
   import org.springframework.web.bind.annotation.*;
   import org.springframework.http.*;
   import org.apache.skywalking.apm.toolkit.trace.*;
   import org.slf4j.*;
   
   @RestController
   public class WebappController implements EnhancedInstance
   {
       private static final Logger log;
       private final UserService userService = userService;
       private volatile Object _$EnhancedClassField_ws;
       public static volatile /* synthetic */ InstMethodsInter delegate$4vkd9v0;
       public static volatile /* synthetic */ InstMethodsInter delegate$memmhe1;
       public static volatile /* synthetic */ ConstructorInter delegate$20v8b80;
       private static final /* synthetic */ Method cachedValue$5e7WjZyN$tcgf6s2;
       private static final /* synthetic */ Method cachedValue$5e7WjZyN$551d7u2;
       private static final /* synthetic */ Method cachedValue$5e7WjZyN$r5lbqa2;
       private static final /* synthetic */ Method cachedValue$5e7WjZyN$pslu6e0;
       private static final /* synthetic */ Method cachedValue$5e7WjZyN$tv4hlg2;
       private static final /* synthetic */ Method cachedValue$5e7WjZyN$fe38712;
       private static final /* synthetic */ Method cachedValue$5e7WjZyN$moqjd11;
       
       public WebappController(final UserService userService) {
           this(userService, null);
           WebappController.delegate$20v8b80.intercept((Object)this, new Object[] { userService });
       }
       
       @RequestMapping(value = { "/users" }, method = { RequestMethod.GET })
       public ResponseEntity<Iterable<User>> userList() {
           return (ResponseEntity<Iterable<User>>)WebappController.delegate$memmhe1.intercept((Object)this, new Object[0], (Callable)new WebappController$auxiliary$nPDeHsP4(this), WebappController.cachedValue$5e7WjZyN$tv4hlg2);
       }
       
       @RequestMapping(value = { "/users/{id}" }, method = { RequestMethod.GET })
       public ResponseEntity<User> getUser(@PathVariable final long id) {
           return (ResponseEntity<User>)WebappController.delegate$memmhe1.intercept((Object)this, new Object[] { id }, (Callable)new WebappController$auxiliary$cByl7fIX(this, id), WebappController.cachedValue$5e7WjZyN$fe38712);
       }
       
       @RequestMapping(value = { "/users" }, method = { RequestMethod.POST })
       public ResponseEntity<User> createUser(@RequestParam final String firstName, @RequestParam final String lastName) {
           return (ResponseEntity<User>)WebappController.delegate$memmhe1.intercept((Object)this, new Object[] { firstName, lastName }, (Callable)new WebappController$auxiliary$sJY8TJLs(this, firstName, lastName), WebappController.cachedValue$5e7WjZyN$r5lbqa2);
       }
       
       @RequestMapping(value = { "/users" }, method = { RequestMethod.DELETE })
       public void deleteUser(@RequestParam final String firstName, @RequestParam final String lastName) {
           WebappController.delegate$memmhe1.intercept((Object)this, new Object[] { firstName, lastName }, (Callable)new WebappController$auxiliary$HdooN252(this, firstName, lastName), WebappController.cachedValue$5e7WjZyN$pslu6e0);
       }
       
       @RequestMapping(value = { "/throws-exception" }, method = { RequestMethod.GET })
       public void throwsException() {
           WebappController.delegate$memmhe1.intercept((Object)this, new Object[0], (Callable)new WebappController$auxiliary$vZfbpnR9(this), WebappController.cachedValue$5e7WjZyN$551d7u2);
       }
       
       @Trace
       private void caughtException() {
           WebappController.delegate$4vkd9v0.intercept((Object)this, new Object[0], (Callable)new WebappController$auxiliary$P2tJxjm1(this), WebappController.cachedValue$5e7WjZyN$moqjd11);
       }
       
       @Trace
       private void uncaughtException() {
           WebappController.delegate$4vkd9v0.intercept((Object)this, new Object[0], (Callable)new WebappController$auxiliary$7xenKkaR(this), WebappController.cachedValue$5e7WjZyN$tcgf6s2);
       }
       
       static {
           ClassLoader.getSystemClassLoader().loadClass("org.apache.skywalking.apm.dependencies.net.bytebuddy.dynamic.Nexus").getMethod("initialize", Class.class, Integer.TYPE).invoke(null, WebappController.class, 433866945);
           cachedValue$5e7WjZyN$tcgf6s2 = WebappController.class.getDeclaredMethod("uncaughtException", (Class<?>[])new Class[0]);
           cachedValue$5e7WjZyN$551d7u2 = WebappController.class.getMethod("throwsException", (Class<?>[])new Class[0]);
           cachedValue$5e7WjZyN$r5lbqa2 = WebappController.class.getMethod("createUser", String.class, String.class);
           cachedValue$5e7WjZyN$pslu6e0 = WebappController.class.getMethod("deleteUser", String.class, String.class);
           cachedValue$5e7WjZyN$tv4hlg2 = WebappController.class.getMethod("userList", (Class<?>[])new Class[0]);
           cachedValue$5e7WjZyN$fe38712 = WebappController.class.getMethod("getUser", Long.TYPE);
           cachedValue$5e7WjZyN$moqjd11 = WebappController.class.getDeclaredMethod("caughtException", (Class<?>[])new Class[0]);
           log = LoggerFactory.getLogger((Class)WebappController.class);
       }
   }
   ```
   </details>
   
   ----
   
   The primary difference between the two is that fields like `cachedValue$5aQdBH3R$551d7u2` have been renamed and the second file is missing the necessary `setSkyWalkingDynamicField/getSkyWalkingDynamicField` methods.
   
   The latter issue seems easy to solve as you could simply check the trace stack for `Instrumentation.retransformClasses()` and allow the enhancement to occur again. The former issue seems like it might be a bit harder and I'm curious if anyone has an idea how to solve it. The ways I've been thinking about solving it are either to:
    - generate unique but consistent fields names (so each time it comes up with the same field names as before)
    - save an additional map to each class which specificies what the existing fields are and reuse the previous names


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [skywalking] BFergerson commented on issue #6701: Redefinition support

Posted by GitBox <gi...@apache.org>.
BFergerson commented on issue #6701:
URL: https://github.com/apache/skywalking/issues/6701#issuecomment-814911373


   Thank you @wu-sheng, this is exactly what I need.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [skywalking] wu-sheng commented on issue #6701: Redefinition support

Posted by GitBox <gi...@apache.org>.
wu-sheng commented on issue #6701:
URL: https://github.com/apache/skywalking/issues/6701#issuecomment-814734300


   Hi, we used to face retransferring issues, but by another agent not inside the agent core. 
   Could you try `agent.is_cache_enhanced_class` and `agent.class_cache_mode` on the agent.config? The reference doc is https://skywalking.apache.org/docs/main/latest/en/setup/service-agent/java-agent/readme/
   This config should be able to cache the transferred source codes to avoid retransferring changes, which seems the case your described.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [skywalking] BFergerson closed issue #6701: Redefinition support

Posted by GitBox <gi...@apache.org>.
BFergerson closed issue #6701:
URL: https://github.com/apache/skywalking/issues/6701


   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org