Oredev 2015 - Taming Java Agents

Preview:

Citation preview

Taming Java Agents@antonarhipov

MeAnton Arhipov

@antonarhipov

anton@zeroturnaround.com

ZeroTurnaround

JRebel, XRebel

Agenda

• Overview of Java agent technology

• Instrumentation API

• Attach API

• HacksApplicationshttp://xkcd.com/138/

BTrace

Pretty much every APM tool today uses Java Agents to instrument the application

A lightweight profiler for Java web apps

A lightweight profiler for Java web apps

A lightweight profiler for Java web apps

A lightweight profiler for Java web apps

A lightweight profiler for Java web apps

A lightweight profiler for Java web apps

my.war

ClassLoader

getResource("hello.html"); read("src/main/.../hello.html");

rebel.xml

• Maps the running application to IDE workspace• Reloads Java classes and framework configurations in

a running JVM process

This slide is intentionally left blank

public static void main(String[] args) { for (String arg : args) { new Thread(new Runnable() { public void run() { //.... } }).start();

Java app

public static void main(String[] args) { for (String arg : args) { new Thread(new Runnable() { public void run() { //..... } }).start();

RULE  trace  thread  start  CLASS  java.lang.Thread  METHOD  start()  IF  true  DO  traceln("***  start  for  thread:  "+  $0.getName())  ENDRULE

Java app

Bytemanrule

public static void main(String[] args) { for (String arg : args) { new Thread(new Runnable() { public void run() { //..... } }).start();

RULE  trace  thread  start  CLASS  java.lang.Thread  METHOD  start()  IF  true  DO  traceln("***  start  for  thread:  "+  $0.getName())  ENDRULE

> java -javaagent:byteman.jar=script:thread.btm,boot:byteman.jar \ -Dorg.jboss.byteman.transform.all org.my.AppMain2 foo bar baz *** start for thread: foo foo *** start for thread: bar bar *** start for thread: baz baz

Java app

Bytemanrule

public static void main(String[] args) { for (String arg : args) { new Thread(new Runnable() { public void run() { //..... } }).start();

RULE  trace  thread  start  CLASS  java.lang.Thread  METHOD  start()  IF  true  DO  traceln("***  start  for  thread:  "+  $0.getName())  ENDRULE

Java app

Bytemanrule

public static void main(String[] args) { for (String arg : args) { new Thread(new Runnable() { public void run() { //..... } }).start();

RULE  trace  thread  start  CLASS  java.lang.Thread  METHOD  start()  IF  true  DO  traceln("***  start  for  thread:  "+  $0.getName())  ENDRULE

> java -classpath byteman-install.jar \ org.jboss.byteman.agent.install.Install 13101

Java app

Bytemanrule

Install agent:

public static void main(String[] args) { for (String arg : args) { new Thread(new Runnable() { public void run() { //..... } }).start();

RULE  trace  thread  start  CLASS  java.lang.Thread  METHOD  start()  IF  true  DO  traceln("***  start  for  thread:  "+  $0.getName())  ENDRULE

> java -classpath byteman-install.jar \ org.jboss.byteman.agent.install.Install 13101

Java app

Bytemanrule

> java -classpath byteman-submit.jar \ org.jboss.byteman.agent.submit.Submit -l thread.btm

Install agent:

Submit rules:

http://byteman.jboss.org

Java Agent Overview

import java.lang.instrument.ClassFileTransformer;import java.lang.instrument.Instrumentation;

public class Agent {

public static void premain(String args, Instrumentation inst) { inst.addTransformer(new ClassFileTransformer { … }); }

public static void agentmain(String args, Instrumentation inst) { premain(args, inst); }

}

META-­‐INF/MANIFEST.MF  Premain-­‐Class:  Agent

$>  java  –javaagent:agent.jar  application.Main

java.lang.instrument.ClassFileTransformer

public class MyTransformer implements ClassFileTransformer { public void byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain pd, byte[] classfileBuffer){

ClassPool cp = ClassPool.getDefault(); CtClass ct = cp.makeClass(new ByteArrayInputStream(classfileBuffer));

// transform the bytes as required, // for instance - with Javassist return ct.toBytecode(); }}

Class loading

Instrumentation

Class loading

ClassFileTransformer

ClassFileTransformer

ClassFileTransformer

Instrumentation

Class loading

ClassFileTransformer

ClassFileTransformer

ClassFileTransformer

Javassist

ASM

Instrumentation

Bytebuddy

https://github.com/zeroturnaround/callspy

Instrumentation API

java.lang.instrument.Instrumentation

void addTransformer(ClassFileTransformer transformer, boolean canRetransform);

void appendToBootstrapClassLoaderSearch(JarFile jarfile);void appendToSystemClassLoaderSearch(JarFile jarfile);

Class[] getAllLoadedClasses();Class[] getInitiatedClasses(ClassLoader loader); void redefineClasses(ClassDefinition... classes);void retransformClasses(Class<?>... classes);

JVM JVM

Process 1 Process 2

Agent

-cp tools.jar

Attach API

• Executed when the agent attaches to the running JVM

• Instrumentation parameter is optional

• META-INF/MANIFEST.MF is required

• Requires support for loading agents in JVM

• Allows adding the code to JVM post-factum

public static void agentmain(String args, Instrumentation inst)

import com.sun.tools.attach.VirtualMachine;

//attach to target VMVirtualMachine vm = VirtualMachine.attach("2177");

//get system properties in the target VMProperties props = vm.getSystemProperties();

//load agent into the VMvm.loadAgent("agent.jar", "arg1=x,arg2=y");

//detach from VMvm.detach();

http://docs.oracle.com/javase/7/docs/jdk/api/attach/spec/com/sun/tools/attach/VirtualMachine.html

https://gist.github.com/nickman/6494990

https://github.com/antonarhipov/attach-and-transform-with-mbeans

https://speakerdeck.com/antonarhipov

http://www.slideshare.net/arhan

@antonarhipovanton@zeroturnaround.com

Resourceshttp://byteman.jboss.org

http://www.javassist.org

https://github.com/zeroturnaround/callspy

https://github.com/antonarhipov/attach-and-transform-with-mbeans

https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html

http://docs.oracle.com/javase/8/docs/jdk/api/attach/spec/com/sun/tools/attach/VirtualMachine.html

http://asm.ow2.org/ http://bytebuddy.net/