Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
kreyssel committed Mar 11, 2011
1 parent 17668ec commit 0d7fc90
Show file tree
Hide file tree
Showing 4 changed files with 241 additions and 0 deletions.
80 changes: 80 additions & 0 deletions javaagent/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>


<groupId>org.kreyssel.tools.loggingagent</groupId>
<artifactId>loggingagent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>Java Instrument API Example</name>
<description>
Example of how to use the Java Instrument API (Java Agent) to add own logging capabilities.

http://download.oracle.com/javase/6/docs/api/java/lang/instrument/package-summary.html
</description>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<archive>
<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<goals>
<goal>attached</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<descriptors>
<descriptor>src/main/assembly/package.xml</descriptor>
</descriptors>
<archive>
<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<!-- used to modify classes at runtime -->
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.1.GA</version>
</dependency>

<!-- only for using org.slf4j.instrumentation.JavassistHelper class -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-ext</artifactId>
<version>1.6.1</version>
</dependency>
</dependencies>
</project>
40 changes: 40 additions & 0 deletions javaagent/src/main/assembly/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!--
Pack a full jar inclusive javassist and slf4j classes.
-->
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">

<id>jar-with-dependencies</id>

<formats>
<format>jar</format>
</formats>

<includeBaseDirectory>false</includeBaseDirectory>

<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>true</useProjectArtifact>
<useStrictFiltering>true</useStrictFiltering>
<unpack>true</unpack>
<includes>
<include>org.kreyssel.tools.loggingagent:*</include>
<include>javassist:javassist</include>
</includes>
</dependencySet>
<dependencySet>
<outputDirectory>/</outputDirectory>
<unpack>true</unpack>
<includes>
<include>org.slf4j:slf4j-ext</include>
</includes>
<unpackOptions>
<includes>
<include>org/slf4j/instrumentation/JavassistHelper.class</include>
<include>org/slf4j/instrumentation/ToStringHelper.class</include>
</includes>
</unpackOptions>
</dependencySet>
</dependencySets>
</assembly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package org.kreyssel.tools.loggingagent;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtBehavior;
import javassist.CtClass;
import javassist.CtField;
import javassist.NotFoundException;

import org.slf4j.instrumentation.JavassistHelper;

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


/**
* LoggerAgent add java.util.logging statements to classes at runtime using
* <a href="http://www.javassist.org/">javassist</a>.
*
* <p>inspired by http://today.java.net/article/2008/04/22/add-logging-class-load-time-java-instrumentation</p>
*/
public class LoggerAgent implements ClassFileTransformer {

/** classes to always not to instrument */
static final String[] DEFAULT_EXCLUDES = new String[] {"com/sun/", "sun/", "java/", "javax/", "org/slf4j" };

/** only this classes should instrument or leave empty to instrument all classes that not excluded */
static final String[] INCLUDES = new String[] {
// "org/bouncycastle/crypto/encodings/", "org/bouncycastle/jce/provider/JCERSACipher"
};

/** the jul logger definition */
static final String def = "private static java.util.logging.Logger _log;";

/** the jul logging if statement */
static final String ifLog = "if (_log.isLoggable(java.util.logging.Level.INFO))";

/**
* add agent
*/
public static void premain( final String agentArgument, final Instrumentation instrumentation ) {
instrumentation.addTransformer( new LoggerAgent() );
}

/**
* instrument class
*/
public byte[] transform( final ClassLoader loader, final String className, final Class clazz,
final java.security.ProtectionDomain domain, final byte[] bytes ) {

for( String include : INCLUDES ) {

if( className.startsWith( include ) ) {
return doClass( className, clazz, bytes );
}
}

for( int i = 0; i < DEFAULT_EXCLUDES.length; i++ ) {

if( className.startsWith( DEFAULT_EXCLUDES[i] ) ) {
return bytes;
}
}

return doClass( className, clazz, bytes );
}

/**
* instrument class with javasisst
*/
private byte[] doClass( final String name, final Class clazz, byte[] b ) {
ClassPool pool = ClassPool.getDefault();
CtClass cl = null;

try {
cl = pool.makeClass( new java.io.ByteArrayInputStream( b ) );

if( cl.isInterface() == false ) {

CtField field = CtField.make( def, cl );
String getLogger = "java.util.logging.Logger.getLogger(" + name.replace( '/', '.' ) +
".class.getName());";
cl.addField( field, getLogger );

CtBehavior[] methods = cl.getDeclaredBehaviors();

for( int i = 0; i < methods.length; i++ ) {

if( methods[i].isEmpty() == false ) {
doMethod( methods[i] );
}
}

b = cl.toBytecode();
}
} catch( Exception e ) {
System.err.println( "Could not instrument " + name + ", exception : " + e.getMessage() );
} finally {

if( cl != null ) {
cl.detach();
}
}

return b;
}

/**
* modify code and add log statements
*/
private void doMethod( final CtBehavior method ) throws NotFoundException, CannotCompileException {

String signature = JavassistHelper.getSignature( method );
String returnValue = JavassistHelper.returnValue( method );

method.insertBefore( ifLog + "_log.info(\">> " + signature + "\");" );

method.insertAfter( ifLog + "_log.info(\"<< " + signature + returnValue + "\");" );
}
}
1 change: 1 addition & 0 deletions javaagent/src/main/resources/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Premain-Class: org.kreyssel.tools.loggingagent.LoggerAgent

0 comments on commit 0d7fc90

Please sign in to comment.