[slf4j-dev] svn commit: r1214 - in slf4j/trunk/slf4j-ext/src/main/java/org/slf4j: agent instrumentation
ravn at slf4j.org
ravn at slf4j.org
Sat Oct 25 16:16:41 CEST 2008
Author: ravn
Date: Sat Oct 25 16:16:41 2008
New Revision: 1214
Modified:
slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/agent/AgentPremain.java
slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/instrumentation/JavassistHelper.java
slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/instrumentation/LogTransformer.java
Log:
now comforms to slf4j formatting
Modified: slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/agent/AgentPremain.java
==============================================================================
--- slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/agent/AgentPremain.java (original)
+++ slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/agent/AgentPremain.java Sat Oct 25 16:16:41 2008
@@ -12,71 +12,81 @@
public class AgentPremain {
- private static final String START_MSG = "Start at {}";
- private static final String STOP_MSG = "Stop at {}, execution time = {} ms";
-
- public static void premain(String agentArgument,
- Instrumentation instrumentation) {
-
- System.err.println("THIS JAVAAGENT IS NOT RELEASED YET. DO NOT USE IN PRODUCTION ENVIRONMENTS.");
- LogTransformer.Builder builder = new LogTransformer.Builder();
- builder = builder.addEntryExit(true);
-
- if (agentArgument != null) {
- Properties args = parseArguments(agentArgument);
-
- if (args.containsKey("verbose")) {
- builder = builder.verbose(true);
- }
-
- if (args.containsKey("time")) {
- printStartStopTimes();
- }
-
- if (args.containsKey("ignore")) {
- builder = builder.ignore(args.getProperty("ignore").split(","));
- }
-
- if (args.containsKey("level")) {
- builder = builder.level(args.getProperty("level"));
- }
-
- // ... more agent option handling here
- }
-
- instrumentation.addTransformer(builder.build());
- }
-
- private static Properties parseArguments(String agentArgument) {
- Properties p = new Properties();
- try {
- byte[] bytes = agentArgument.replaceAll(";", "\n").getBytes();
- p.load(new ByteArrayInputStream(bytes));
- } catch (IOException e) {
- throw new RuntimeException(
- "Could not load arguments as properties", e);
- }
- return p;
- }
-
- /**
- * Print the start message with the time NOW, and register a shutdown hook
- * which will print the stop message with the time then and the number of
- * milliseconds passed since.
- *
- */
- private static void printStartStopTimes() {
- final long start = System.currentTimeMillis();
- System.err.println(format(START_MSG, new Date()));
-
- Thread hook = new Thread() {
- public void run() {
- long timePassed = System.currentTimeMillis() - start;
- String message = format(STOP_MSG, new Date(), timePassed);
- System.err.println(message);
- }
- };
- Runtime.getRuntime().addShutdownHook(hook);
- }
+ private static final String START_MSG = "Start at {}";
+ private static final String STOP_MSG = "Stop at {}, execution time = {} ms";
+ /**
+ * JavaAgent premain entry point as specified in the MANIFEST.MF file. See
+ * {@link http://java.sun.com/javase/6/docs/api/java/lang/instrument/package-summary.html} for details.
+ *
+ * @param agentArgument
+ * string provided after "=" up to first space
+ * @param instrumentation
+ */
+ public static void premain(String agentArgument,
+ Instrumentation instrumentation) {
+
+ System.err.println("THIS JAVAAGENT IS NOT RELEASED YET. "
+ + "DO NOT USE IN PRODUCTION ENVIRONMENTS.");
+
+ LogTransformer.Builder builder = new LogTransformer.Builder();
+ builder = builder.addEntryExit(true);
+
+ if (agentArgument != null) {
+ Properties args = parseArguments(agentArgument);
+
+ if (args.containsKey("verbose")) {
+ builder = builder.verbose(true);
+ }
+
+ if (args.containsKey("time")) {
+ printStartStopTimes();
+ }
+
+ if (args.containsKey("ignore")) {
+ builder = builder.ignore(args.getProperty("ignore").split(","));
+ }
+
+ if (args.containsKey("level")) {
+ builder = builder.level(args.getProperty("level"));
+ }
+
+ // ... more agent option handling here
+ }
+
+ instrumentation.addTransformer(builder.build());
+ }
+
+ private static Properties parseArguments(String agentArgument) {
+ Properties p = new Properties();
+ try {
+ byte[] bytes = agentArgument.replaceAll(";", "\n").getBytes();
+ p.load(new ByteArrayInputStream(bytes));
+ } catch (IOException e) {
+ String s = "Could not load arguments as properties";
+ throw new RuntimeException(s, e);
+ }
+ return p;
+ }
+
+ /**
+ * Print the start message with the time NOW, and register a shutdown hook
+ * which will print the stop message with the time then and the number of
+ * milliseconds passed since.
+ *
+ */
+ private static void printStartStopTimes() {
+ final long start = System.currentTimeMillis();
+ System.err.println(format(START_MSG, new Date()));
+
+ Thread hook = new Thread() {
+ @Override
+ public void run() {
+ long timePassed = System.currentTimeMillis() - start;
+ String message = format(STOP_MSG, new Date(), timePassed);
+ System.err.println(message);
+ }
+ };
+ Runtime.getRuntime().addShutdownHook(hook);
+ }
}
\ No newline at end of file
Modified: slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/instrumentation/JavassistHelper.java
==============================================================================
--- slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/instrumentation/JavassistHelper.java (original)
+++ slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/instrumentation/JavassistHelper.java Sat Oct 25 16:16:41 2008
@@ -10,105 +10,103 @@
public class JavassistHelper {
- public static String returnValue(CtBehavior method)
- throws NotFoundException {
+ public static String returnValue(CtBehavior method) throws NotFoundException {
- String returnValue = "";
- if (methodReturnsValue(method)) {
- returnValue = " returns: \" + $_ + \"";
- }
- return returnValue;
- }
-
- private static boolean methodReturnsValue(CtBehavior method)
- throws NotFoundException {
-
- if (method instanceof CtMethod == false) {
- return false;
- }
-
- CtClass returnType = ((CtMethod) method).getReturnType();
- String returnTypeName = returnType.getName();
-
- boolean isVoidMethod = "void".equals(returnTypeName);
-
- boolean methodReturnsValue = isVoidMethod == false;
- return methodReturnsValue;
- }
-
- public static String getSignature(CtBehavior method)
- throws NotFoundException {
-
- CtClass parameterTypes[] = method.getParameterTypes();
-
- CodeAttribute codeAttribute = method.getMethodInfo().getCodeAttribute();
-
- LocalVariableAttribute locals = null;
-
- if (codeAttribute != null) {
- locals = (LocalVariableAttribute) codeAttribute
- .getAttribute("LocalVariableTable");
- }
-
- String methodName = method.getName();
-
- StringBuffer sb = new StringBuffer(methodName + "(\" ");
- for (int i = 0; i < parameterTypes.length; i++) {
- if (i > 0) {
- sb.append(" + \", \" ");
- }
-
- CtClass parameterType = parameterTypes[i];
- boolean isArray = parameterType.isArray();
- CtClass arrayOf = parameterType.getComponentType();
- if (isArray) {
- while (arrayOf.isArray()) {
- arrayOf = arrayOf.getComponentType();
- }
- }
-
- sb.append(" + \"");
- sb.append(parameterNameFor(method, locals, i));
- sb.append("\" + \"=");
-
- // use Arrays.asList() to render array of objects.
- if (isArray && !arrayOf.isPrimitive()) {
- sb.append("\"+ java.util.Arrays.asList($" + (i + 1) + ")");
- } else {
- sb.append("\"+ $" + (i + 1));
- }
- }
- sb.append("+\")");
-
- String signature = sb.toString();
- return signature;
- }
-
- static String parameterNameFor(CtBehavior method,
- LocalVariableAttribute locals, int i) {
- if (locals == null) {
- return Integer.toString(i + 1);
- }
-
- int modifiers = method.getModifiers();
-
- int j = i;
-
- if (Modifier.isSynchronized(modifiers)) {
- // skip object to synchronize upon.
- j++;
- // System.err.println("Synchronized");
- }
- if (Modifier.isStatic(modifiers) == false) {
- // skip "this"
- j++;
- // System.err.println("Instance");
- }
- String variableName = locals.variableName(j);
- if (variableName.equals("this")) {
- System.err.println("this returned as a parameter name for "
- + method.getName() + ", names are probably shifted.");
- }
- return variableName;
- }
+ String returnValue = "";
+ if (methodReturnsValue(method)) {
+ returnValue = " returns: \" + $_ + \".";
+ }
+ return returnValue;
+ }
+
+ private static boolean methodReturnsValue(CtBehavior method)
+ throws NotFoundException {
+
+ if (method instanceof CtMethod == false) {
+ return false;
+ }
+
+ CtClass returnType = ((CtMethod) method).getReturnType();
+ String returnTypeName = returnType.getName();
+
+ boolean isVoidMethod = "void".equals(returnTypeName);
+
+ boolean methodReturnsValue = isVoidMethod == false;
+ return methodReturnsValue;
+ }
+
+ public static String getSignature(CtBehavior method) throws NotFoundException {
+
+ CtClass parameterTypes[] = method.getParameterTypes();
+
+ CodeAttribute codeAttribute = method.getMethodInfo().getCodeAttribute();
+
+ LocalVariableAttribute locals = null;
+
+ if (codeAttribute != null) {
+ locals = (LocalVariableAttribute) codeAttribute
+ .getAttribute("LocalVariableTable");
+ }
+
+ String methodName = method.getName();
+
+ StringBuffer sb = new StringBuffer(methodName + "(\" ");
+ for (int i = 0; i < parameterTypes.length; i++) {
+ if (i > 0) {
+ sb.append(" + \", \" ");
+ }
+
+ CtClass parameterType = parameterTypes[i];
+ boolean isArray = parameterType.isArray();
+ CtClass arrayOf = parameterType.getComponentType();
+ if (isArray) {
+ while (arrayOf.isArray()) {
+ arrayOf = arrayOf.getComponentType();
+ }
+ }
+
+ sb.append(" + \"");
+ sb.append(parameterNameFor(method, locals, i));
+ sb.append("\" + \"=");
+
+ // use Arrays.asList() to render array of objects.
+ if (isArray && !arrayOf.isPrimitive()) {
+ sb.append("\"+ java.util.Arrays.asList($" + (i + 1) + ")");
+ } else {
+ sb.append("\"+ $" + (i + 1));
+ }
+ }
+ sb.append("+\")");
+
+ String signature = sb.toString();
+ return signature;
+ }
+
+ static String parameterNameFor(CtBehavior method,
+ LocalVariableAttribute locals, int i) {
+ if (locals == null) {
+ return Integer.toString(i + 1);
+ }
+
+ int modifiers = method.getModifiers();
+
+ int j = i;
+
+ if (Modifier.isSynchronized(modifiers)) {
+ // skip object to synchronize upon.
+ j++;
+ // System.err.println("Synchronized");
+ }
+ if (Modifier.isStatic(modifiers) == false) {
+ // skip "this"
+ j++;
+ // System.err.println("Instance");
+ }
+ String variableName = locals.variableName(j);
+ if (variableName.equals("this")) {
+ System.err.println("this returned as a parameter name for "
+ + method.getName() + " index " + j + ", names are probably shifted.");
+ }
+ return variableName;
+ }
}
Modified: slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/instrumentation/LogTransformer.java
==============================================================================
--- slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/instrumentation/LogTransformer.java (original)
+++ slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/instrumentation/LogTransformer.java Sat Oct 25 16:16:41 2008
@@ -25,213 +25,212 @@
*/
public class LogTransformer implements ClassFileTransformer {
- // http://rwhansen.blogspot.com/2007/07/theres-builder-pattern-that-joshua.html
- public static class Builder {
+ // http://rwhansen.blogspot.com/2007/07/theres-builder-pattern-that-joshua.html
+ public static class Builder {
- /**
- * Build and return the LogTransformer corresponding to the options set
- * in this Builder.
- *
- * @return
- */
- public LogTransformer build() {
- if (verbose) {
- System.err.println("Creating LogTransformer");
- }
- return new LogTransformer(this);
- }
-
- boolean addEntryExit;
-
- /**
- * Should each method log entry (with parameters) and exit (with
- * parameters and returnvalue)?
- *
- * @param b
- * value of flag
- * @return
- */
- public Builder addEntryExit(boolean b) {
- addEntryExit = b;
- return this;
- }
-
- boolean addVariableAssignment;
-
- private Builder addVariableAssignment(boolean b) {
- System.err.println("cannot currently log variable assignments.");
- addVariableAssignment = b;
- return this;
- }
-
- boolean verbose;
-
- /**
- * Should LogTransformer be verbose in what it does? This currently list
- * the names of the classes being processed.
- *
- * @param b
- * @return
- */
- public Builder verbose(boolean b) {
- verbose = b;
- return this;
- }
-
- String[] ignore = { "sun/", "java/", "javax/", "org/slf4j/",
- "ch/qos/logback/", "org/apache/log4j/", "apple/", "com/sun/"};
-
- public Builder ignore(String[] strings) {
- this.ignore = strings;
- return this;
- }
-
- private String level = "info";
-
- public Builder level(String level) {
- level = level.toLowerCase();
- if (level.equals("info") || level.equals("debug")
- || level.equals("trace")) {
- this.level = level;
- } else {
- if (verbose) {
- System.err.println("level not info/debug/trace : " + level);
- }
- }
- return this;
- }
- }
-
- private String level;
- private String levelEnabled;
-
- private LogTransformer(Builder builder) {
- this.addEntryExit = builder.addEntryExit;
- this.addVariableAssignment = builder.addVariableAssignment;
- this.verbose = builder.verbose;
- this.ignore = builder.ignore;
- this.level = builder.level;
- this.levelEnabled = "is" + builder.level.substring(0, 1).toUpperCase()
- + builder.level.substring(1) + "Enabled";
- }
-
- private static final String _LOG = "_log";
-
- private boolean addEntryExit;
- private boolean addVariableAssignment;
- private boolean verbose;
- private String[] ignore;
-
- public byte[] transform(ClassLoader loader, String className,
- Class<?> clazz, ProtectionDomain domain, byte[] bytes) {
-
- try {
- return transform0(className, clazz, bytes);
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- return bytes;
- }
- }
-
- /**
- * transform0 sees if the className starts with any of the namespaces to
- * ignore, if so it is returned unchanged. Otherwise it is processed by
- * doClass(...)
- *
- * @param className
- * @param clazz
- * @param bytes
- * @return
- */
- private byte[] transform0(String className, Class<?> clazz, byte[] bytes) {
- for (int i = 0; i < ignore.length; i++) {
- if (className.startsWith(ignore[i])) {
- return bytes;
- }
- }
- if (verbose) {
- System.err.println("Loggifying " + className);
- }
- return doClass(className, clazz, bytes);
- }
-
- /**
- * The transform(...) method calls doClass(...) if the class name does not
- * start with any of the prefixes it has been told to ignore.
- *
- * doClass() first creates a class description from the byte codes. If it is
- * a class (i.e. not an interface) the methods defined have bodies, and a
- * static final logger object is added with the name of this class as an
- * argument, and each method then gets processed with doMethod(...) to have
- * logger calls added.
- *
- *
- *
- * @param name
- * class name (slashes separate, not dots)
- * @param clazz
- * @param b
- * @return
- */
- private byte[] doClass(String name, Class<?> clazz, byte[] b) {
- ClassPool pool = ClassPool.getDefault();
- CtClass cl = null;
- try {
- cl = pool.makeClass(new ByteArrayInputStream(b));
- if (cl.isInterface() == false) {
-
- String pattern1 = "private static org.slf4j.Logger {};";
- String loggerDefinition = format(pattern1, _LOG);
- CtField field = CtField.make(loggerDefinition, cl);
-
- String pattern2 = "org.slf4j.LoggerFactory.getLogger({}.class);";
- String replace = name.replace('/', '.');
- String getLogger = format(pattern2, replace);
-
- cl.addField(field, getLogger);
- System.out.println(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) {
- String pattern = "Could not instrument {}, exception : {}";
- System.err.println(format(pattern, name, e.getMessage()));
- e.printStackTrace(System.err);
- } finally {
- if (cl != null) {
- cl.detach();
- }
- }
- return b;
- }
-
- private void doMethod(CtBehavior method) throws NotFoundException,
- CannotCompileException {
-
- String signature = JavassistHelper.getSignature(method);
- String returnValue = JavassistHelper.returnValue(method);
-
- if (addEntryExit) {
- String messagePattern = "if ({}.{}()) {}.{}(\">> {}\");";
- Object[] arg1 = new Object[] { _LOG, levelEnabled, _LOG, level,
- signature };
- String before = MessageFormatter.arrayFormat(messagePattern, arg1);
- //System.out.println(before);
- method.insertBefore(before);
-
- String messagePattern2 = "if ({}.{}()) {}.{}(\"<< {}{}\");";
- Object[] arg2 = new Object[] { _LOG, levelEnabled, _LOG, level,
- signature, returnValue };
- String after = MessageFormatter.arrayFormat(messagePattern2, arg2);
- //System.out.println(after);
- method.insertAfter(after);
- }
- }
+ /**
+ * Build and return the LogTransformer corresponding to the options set in
+ * this Builder.
+ *
+ * @return
+ */
+ public LogTransformer build() {
+ if (verbose) {
+ System.err.println("Creating LogTransformer");
+ }
+ return new LogTransformer(this);
+ }
+
+ boolean addEntryExit;
+
+ /**
+ * Should each method log entry (with parameters) and exit (with parameters
+ * and returnvalue)?
+ *
+ * @param b
+ * value of flag
+ * @return
+ */
+ public Builder addEntryExit(boolean b) {
+ addEntryExit = b;
+ return this;
+ }
+
+ boolean addVariableAssignment;
+
+ private Builder addVariableAssignment(boolean b) {
+ System.err.println("cannot currently log variable assignments.");
+ addVariableAssignment = b;
+ return this;
+ }
+
+ boolean verbose;
+
+ /**
+ * Should LogTransformer be verbose in what it does? This currently list the
+ * names of the classes being processed.
+ *
+ * @param b
+ * @return
+ */
+ public Builder verbose(boolean b) {
+ verbose = b;
+ return this;
+ }
+
+ String[] ignore = { "sun/", "java/", "javax/", "org/slf4j/",
+ "ch/qos/logback/", "org/apache/log4j/", "apple/", "com/sun/" };
+
+ public Builder ignore(String[] strings) {
+ this.ignore = strings;
+ return this;
+ }
+
+ private String level = "info";
+
+ public Builder level(String level) {
+ level = level.toLowerCase();
+ if (level.equals("info") || level.equals("debug")
+ || level.equals("trace")) {
+ this.level = level;
+ } else {
+ if (verbose) {
+ System.err.println("level not info/debug/trace : " + level);
+ }
+ }
+ return this;
+ }
+ }
+
+ private String level;
+ private String levelEnabled;
+
+ private LogTransformer(Builder builder) {
+ this.addEntryExit = builder.addEntryExit;
+ this.addVariableAssignment = builder.addVariableAssignment;
+ this.verbose = builder.verbose;
+ this.ignore = builder.ignore;
+ this.level = builder.level;
+ this.levelEnabled = "is" + builder.level.substring(0, 1).toUpperCase()
+ + builder.level.substring(1) + "Enabled";
+ }
+
+ private static final String _LOG = "_log";
+
+ private boolean addEntryExit;
+ private boolean addVariableAssignment;
+ private boolean verbose;
+ private String[] ignore;
+
+ public byte[] transform(ClassLoader loader, String className, Class<?> clazz,
+ ProtectionDomain domain, byte[] bytes) {
+
+ try {
+ return transform0(className, clazz, bytes);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ return bytes;
+ }
+ }
+
+ /**
+ * transform0 sees if the className starts with any of the namespaces to
+ * ignore, if so it is returned unchanged. Otherwise it is processed by
+ * doClass(...)
+ *
+ * @param className
+ * @param clazz
+ * @param bytes
+ * @return
+ */
+ private byte[] transform0(String className, Class<?> clazz, byte[] bytes) {
+ for (int i = 0; i < ignore.length; i++) {
+ if (className.startsWith(ignore[i])) {
+ return bytes;
+ }
+ }
+ if (verbose) {
+ System.err.println("Loggifying " + className);
+ }
+ return doClass(className, clazz, bytes);
+ }
+
+ /**
+ * The transform(...) method calls doClass(...) if the class name does not
+ * start with any of the prefixes it has been told to ignore.
+ *
+ * doClass() first creates a class description from the byte codes. If it is a
+ * class (i.e. not an interface) the methods defined have bodies, and a static
+ * final logger object is added with the name of this class as an argument,
+ * and each method then gets processed with doMethod(...) to have logger calls
+ * added.
+ *
+ *
+ *
+ * @param name
+ * class name (slashes separate, not dots)
+ * @param clazz
+ * @param b
+ * @return
+ */
+ private byte[] doClass(String name, Class<?> clazz, byte[] b) {
+ ClassPool pool = ClassPool.getDefault();
+ CtClass cl = null;
+ try {
+ cl = pool.makeClass(new ByteArrayInputStream(b));
+ if (cl.isInterface() == false) {
+
+ String pattern1 = "private static org.slf4j.Logger {};";
+ String loggerDefinition = format(pattern1, _LOG);
+ CtField field = CtField.make(loggerDefinition, cl);
+
+ String pattern2 = "org.slf4j.LoggerFactory.getLogger({}.class);";
+ String replace = name.replace('/', '.');
+ String getLogger = format(pattern2, replace);
+
+ cl.addField(field, getLogger);
+ // System.out.println(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) {
+ String pattern = "Could not instrument {}, exception : {}";
+ System.err.println(format(pattern, name, e.getMessage()));
+ e.printStackTrace(System.err);
+ } finally {
+ if (cl != null) {
+ cl.detach();
+ }
+ }
+ return b;
+ }
+
+ private void doMethod(CtBehavior method) throws NotFoundException,
+ CannotCompileException {
+
+ String signature = JavassistHelper.getSignature(method);
+ String returnValue = JavassistHelper.returnValue(method);
+
+ if (addEntryExit) {
+ String messagePattern = "if ({}.{}()) {}.{}(\">> {}\");";
+ Object[] arg1 = new Object[] { _LOG, levelEnabled, _LOG, level, signature };
+ String before = MessageFormatter.arrayFormat(messagePattern, arg1);
+ // System.out.println(before);
+ method.insertBefore(before);
+
+ String messagePattern2 = "if ({}.{}()) {}.{}(\"<< {}{}\");";
+ Object[] arg2 = new Object[] { _LOG, levelEnabled, _LOG, level,
+ signature, returnValue };
+ String after = MessageFormatter.arrayFormat(messagePattern2, arg2);
+ // System.out.println(after);
+ method.insertAfter(after);
+ }
+ }
}
\ No newline at end of file
More information about the slf4j-dev
mailing list