I am trying to develop a javaagent that would instrument code with help of asm-4. For now I'm stucked with a pretty basic problem, the classloader for the javaagent doesn't see asm dependencies and therefor fails. Do I have to provide a jar-with-dependencies (aka maven build plugin) which contains all the needed classes by the agent, or is there another way to add classes to the java agent? Referencing the jar asm-all.jar directly in the classpath didn't help. Building jar-with-dependencies didn't help at first, because Premain-Class attribute couldn't be set with assembly plugin. Help is appreciated ;-)
- 1ok, apparently I found the answer myself: <manifestEntries> <Premain-Class>test.agent.MyAgent</Premain-Class> </manifestEntries> <- the assembly plugin accepts same configuration options as the jar pluginLeon– Leon2013-04-08 06:47:47 +00:00Commented Apr 8, 2013 at 6:47
- 1please write it as answer and accept it, so that the other users can see the answer of your question.aphex– aphex2013-04-08 06:53:33 +00:00Commented Apr 8, 2013 at 6:53
5 Answers
ok, found it by experimenting. The dependent classes should be part of the jar, which can be created by maven assembly plugin, for example:
<plugin> <artifactId>maven-assembly-plugin</artifactId> <version>2.2</version> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> <archive> <index>true</index> <manifest> <addDefaultImplementationEntries>true</addDefaultImplementationEntries> <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries> </manifest> <manifestEntries> <Premain-Class>test.agent.MyAgent</Premain-Class> </manifestEntries> </archive> </configuration> <executions> <execution> <id>make-assembly</id> <!-- this is used for inheritance merges --> <phase>package</phase> <!-- append to the packaging phase. --> <goals> <goal>single</goal> <!-- goals == mojos --> </goals> </execution> </executions> </plugin> Use the jar as javaagent path and everything works fine.
1 Comment
I followed this blog post. Here is how I made it work, to get the size of objects.
/MANIFEST.MF
Manifest-Version: 1.0 Premain-Class: ar.com.docdigital.InstrumentationApp Can-Redefine-Classes: true Can-Retransform-Classes: true Can-Set-Native-Method-Prefix: true in your pom.xml (Note we reference custom MANIFEST)
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifestFile> MANIFEST.MF </manifestFile> <manifest> <addClasspath>true</addClasspath> <mainClass> ar.com.docdigital.App </mainClass> </manifest> </archive> </configuration> </plugin> My Instrumentation Agent:
package ar.com.docdigital; import java.lang.instrument.Instrumentation; /** * * @author juan.fernandez */ public class InstrumentationApp { private static Instrumentation instrumentation; public static void premain(String args, Instrumentation inst) { instrumentation = inst; } public static long getObjectSize(Object o) { return instrumentation.getObjectSize(o); } } My main App:
package ar.com.docdigital;
import static ar.com.docdigital.InstrumentationApp.getObjectSize; /** * * @author juan.fernandez */ public class App { public static void main (String[] args) { System.out.println("Size of CoprimeLong: " + getObjectSize(new CoprimesList.CoprimeLong(1L))); System.out.println("Size of Long: " + getObjectSize(new Long(1L))); } } Putting all together & CLI output:
$ mvn package $ java -javaagent:target/primos-0.1.0-SNAPSHOT.jar -jar target/primos-0.1.0-SNAPSHOT.jar Size of CoprimeLong: 24 Size of Long: 24 1 Comment
I used maven-jar-plugin for my CustomAgent. I dont have any dependent modules/jars so using an assembly plugin is an overkill.
<build> <sourceDirectory>src</sourceDirectory> <finalName>are-agent</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.4</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <addDefaultImplementationEntries>true</addDefaultImplementationEntries> <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries> </manifest> <manifestEntries> <Premain-Class>are.agent.CustomAgent</Premain-Class> <Can-Redefine-Classes>false</Can-Redefine-Classes> <Can-Retransform-Classes>true</Can-Retransform-Classes> </manifestEntries> </archive> </configuration> </plugin> </plugins> <build> Comments
You should add Premain-Class entry to the manifest. I use gradle to build Java projects.
Add this to gradle.build
jar { manifest { attributes( "Premain-Class": "com.training.agent.agentapp.SimplestAgent", "Can-Redefine-Classes": false, "Can-Set-Native-Method-Prefix": false ) } } And then you can run it
java -javaagent:agent.jar -jar application.jar