-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
241 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
120 changes: 120 additions & 0 deletions
120
javaagent/src/main/java/org/kreyssel/tools/loggingagent/LoggerAgent.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 + "\");" ); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Premain-Class: org.kreyssel.tools.loggingagent.LoggerAgent |