1 Reply Latest reply on Mar 9, 2016 3:55 AM by Andrew Dinn

    Proper usage example for $@?

    Taylor Marks Newbie

      Here's some Byteman rules that work fine:

       

       

      RULE trace SLServer initCoreServices at getInstance

      CLASS ^com.empolis.ecls.server.system.server.Server

      METHOD initCoreServices

      AT INVOKE getInstance ALL

      IF true

      DO traceOpen("ECLSManagedConnectionFactory", "/app/ECLSManagedConnectionFactory.log");

         traceln("ECLSManagedConnectionFactory", "Invoking getInstance in initCoreServices on Server or subclass.");

         traceClose("ECLSManagedConnectionFactory");

      ENDRULE

       

      RULE trace SLServer initCoreServices at getProperty

      CLASS ^com.empolis.ecls.server.system.server.Server

      METHOD initCoreServices

      AT INVOKE getProperty ALL

      IF true

      DO traceOpen("ECLSManagedConnectionFactory", "/app/ECLSManagedConnectionFactory.log");

         traceln("ECLSManagedConnectionFactory", "Invoking getProperty in initCoreServices on Server or subclass.");

         traceClose("ECLSManagedConnectionFactory");

      ENDRULE

       

      When I run these rules, I get output that looks like this in my log file:

       

      Invoking getInstance in initCoreServices on Server or subclass.

      Invoking getInstance in initCoreServices on Server or subclass.

      Invoking getInstance in initCoreServices on Server or subclass.

      Invoking getInstance in initCoreServices on Server or subclass.

      Invoking getProperty in initCoreServices on Server or subclass.

      Invoking getProperty in initCoreServices on Server or subclass.

      Invoking getInstance in initCoreServices on Server or subclass.

      Invoking getInstance in initCoreServices on Server or subclass.

      Invoking getProperty in initCoreServices on Server or subclass.

      Invoking getProperty in initCoreServices on Server or subclass.

       

      That's useful - I kind of know what is getting run. I'd like more details, though. What arguments are actually getting passed in? The documentation for 3.0.2 (the latest version of the docs I could find - I'm actually using 3.0.3) says that I can use $@ to get at the arguments inside of AT INVOKE. I tried each of the following in seperate tests within a DO body. Each of them resulted in no logs going to my log file at all, which suggests they aren't working for whatever reason.

       

       

      traceln("ECLSManagedConnectionFactory", $@);

      traceln("ECLSManagedConnectionFactory", "Invoking getProperty in initCoreServices on Server or subclass. Arguments: " + $@);

      traceln("ECLSManagedConnectionFactory", "Invoking getProperty in initCoreServices on Server or subclass. First argument: " + $@[1]);


      I've looked around but couldn't find any examples of using $@. Am I using it properly? How can I find out? I'm firing up Byteman during my Wildfly server start up... is there some way I can get Byteman to log feedback about my rules into a file or something? (It would be quite difficult to run the rules without the Wildfly server... getting the classes to resolve and whatnot would be a major pain.)


      Also... how do types within Byteman work? I thought it would be super typesafe/strict like Java is, but this rule works:

      RULE trace setECLSPropFile exception

      CLASS com.empolis.ecls.server.j2ee.jca.impl.ECLSManagedConnectionFactory

      METHOD setECLSPropFile

      AT THROW

      IF true

      DO traceOpen("ECLSManagedConnectionFactory", "/app/ECLSManagedConnectionFactory.log");

         traceln("ECLSManagedConnectionFactory", "Throwing from setECLSPropFile");

         traceln("ECLSManagedConnectionFactory", "This was thrown: " + $^);

         traceClose("ECLSManagedConnectionFactory");

      ENDRULE

       

      $^, according to the documentation, is a Throwable. In ordinary Java, attempting to add a Throwable to a string wouldn't work - you need to run the toString method on the Throwable first (I think - I haven't actually done much Java programming in the last 3 years). In Byteman, it seems that running toString is implicit.

        • 1. Re: Proper usage example for $@?
          Andrew Dinn Master

          Hi Taylor

           

          Taylor Marks wrote:

            . . .

          The documentation for 3.0.2 (the latest version of the docs I could find - I'm actually using 3.0.3) says that I can use $@ to get at the arguments inside of AT INVOKE. I tried each of the following in seperate tests within a DO body. Each of them resulted in no logs going to my log file at all, which suggests they aren't working for whatever reason.

           

           

          traceln("ECLSManagedConnectionFactory", $@);

          traceln("ECLSManagedConnectionFactory", "Invoking getProperty in initCoreServices on Server or subclass. Arguments: " + $@);

          traceln("ECLSManagedConnectionFactory", "Invoking getProperty in initCoreServices on Server or subclass. First argument: " + $@[1]);


          I've looked around but couldn't find any examples of using $@. Am I using it properly? How can I find out? I'm firing up Byteman during my Wildfly server start up... is there some way I can get Byteman to log feedback about my rules into a file or something? (It would be quite difficult to run the rules without the Wildfly server... getting the classes to resolve and whatnot would be a major pain.)

           

          This is correct usage and definitely ought to be printing something. Note that the type of $@ is an Object array so when you print it in the first two cases the resulting text will be some internal identifier for the array (whatever Object.toString() generates for an aray object). In the third case $@[1] is an Object and will print in whatever format that object prints according to its toString() method.

           

          The $@ syntax is tested every time Byteman builds (by test TestInvokeParamBinding.java with  script TestInvokeParamBinding.btm) so it does work, at least n basic cases. If your rule is not working then there may be an error in your rule or it may be a bug in Byteman. If you can show me the rule and, perhaps, the relevant bit of program code I might be able to determine what the problem is. However, there are several other things you can do to check the stauis of your rules:

           

          1) Check the injection status of your rules

           

          While the app server is still running you can check what has happened to your rules by executing the bmsubmit script with no arguments. For this to work you need to ensure you start the agent with listener:true as a javaagent option (n.b. that's automatic if you have installed the agent using script bminstall).

           

          What you should see is a listing of all uploaded rules. If a rule has been injected then the listing will say also list the class(es) and classloader(s) for the injection point(s). If th erule has been triggered (i.e. execution reached the injection point) then the listing will state either that it has been 'compiled' (strictly this ought just to say 'parsed and type-checked' unless you have requested compilation of the rule to bytecode) or will list a parse error or type check error.

           

          2) Type Check your rules offline

           

          You can use script bmcheck to type-check your rules offline.

           

          You will need to provide one or more -cp path/to/code.jar arguments to tell bmcheck where to look for classes mentioned in your rules (not just on the CLASS or INTERFACE line but also classes directly or indirectly referenced from the desinated CLASS or INTERFACE and also from expressions in the rule body). If you omit the package in the CLASS/INTERFACE clause then you need to also one or more hints as to which package to use to translate the unqualified name to a full package qualified name in the format -p org.my.package.name (your rule above uses the package name so this is not a problem).

           

          Unfortunately, bmcheck is not able to fully type check CLASS rules that employ ^ or type check INTERFACE rules. For a CLASS ^Foo rule it can type check the rule for class Foo but is not able to determine what classes might subclass Foo. Similarly, for an INTERFACE IFoo rule (also interface ^IFoo) bmcheck cannot determine what classes might implement interface IFoo (especially indirect implementations where X is a subclass of Y implements IFoo). In these cases I recommend that you make a copy of the rule and change it to apply to CLASS X where X is one of the cases you want to check (X is a subclass of Foo, X implements IFoo etc)

           

          3) If you start your program with -Dorg.jboss.byteman.verbose then teh Byteman agent will print information to System.out detailing what it is doing as it loads and injects rules. If there is a problem injecting or executing your rules then you should see it in the server log output.

           

          Please try any or all of those tacks to see what yo can find or send me your rule so I can eyeball it or otherwise try to reproduce the problem.

          Taylor Marks wrote:

            . . .

          Also... how do types within Byteman work? I thought it would be super typesafe/strict like Java is, but this rule works:


          RULE trace setECLSPropFile exception

          CLASS com.empolis.ecls.server.j2ee.jca.impl.ECLSManagedConnectionFactory

          METHOD setECLSPropFile

          AT THROW

          IF true

          DO traceOpen("ECLSManagedConnectionFactory", "/app/ECLSManagedConnectionFactory.log");

            traceln("ECLSManagedConnectionFactory", "Throwing from setECLSPropFile");

            traceln("ECLSManagedConnectionFactory", "This was thrown: " + $^);

            traceClose("ECLSManagedConnectionFactory");

          ENDRULE

           

          $^, according to the documentation, is a Throwable. In ordinary Java, attempting to add a Throwable to a string wouldn't work - you need to run the toString method on the Throwable first (I think - I haven't actually done much Java programming in the last 3 years). In Byteman, it seems that running toString is implicit.

           

          Yes, running toString is being done implicitly. In order to allow rules to stay simple and small Byteman tries to avoid the need for explicit type declarations and conversions. So, many of the types of expressions in rules are inferred by Byteman. Avoiding some explicit declarations means that a rule which applies to more than one class (e.g. rules which inject into overloaded methods, or through an interface/down a class hierarchy) can work in contexts where the types of some expressions differ. For example, in a rule for CLASS Foo METHOD foo a refreence to parameter variable $1 will have different types for Foo.foo(String) and Foo.foo(Object) . However, a single rule can still usefully be injected into both methods with $1 without having to be explicit about whether it is a String or an Object  signature for the method.

           

          Type inference is also supplemented with automatic type conversion. If it identifies a context where it is appropriate Byteman will automaticallyl:

          • interconvert numeric primitives (byte, short, char, int, long, float, double)
          • convert primitives to/from Numbers (Byte, Short etc)  -- this is normally referred to as boxing and unboxing
          • convert any primitive or Object to String

          So, in your rule above instead of "This was thrown: " + $^ you could have written "This was thrown: " + $^.toString(). Byteman simply recognised that you are using a Throwable as part of a (String + X) expression and inserted the toString() call for you.

           

          regards,

           

           

          Andrew Dinn