Using AspectJ to log all methods parameters and return values during application runtime

adevedo's picture
5
Average: 5 (1 vote)

AspectJ is an aspect-oriented extension created at PARC for the Java programming language. It is available in Eclipse Foundation open-source projects, both stand-alone and integrated into Eclipse. AspectJ has become the widely used de-facto standard for AOP by emphasizing simplicity and usability for end users. It uses Java-like syntax and has included IDE integrations for displaying crosscutting structure since its initial public release in 2001. To use AspectJ to log all application methods and methods return values, follow the below guide...

Use the following aspect utility class:

  1. package com.myapp.util;
  2.  
  3. import java.lang.reflect.Field;
  4. import java.util.List;
  5.  
  6. import org.apache.log4j.Logger;
  7.  
  8. public final class AspectUtils {
  9.  
  10.         private static final Logger logger = Logger.getLogger(AspectUtils.class);
  11.  
  12.         private AspectUtils() {
  13.  
  14.         }
  15.  
  16.         public static Logger getLogger(org.aspectj.lang.JoinPoint joinPoint) {
  17.                 try {
  18.                         @SuppressWarnings("rawtypes")
  19.                         Class declaringType = joinPoint.getSignature().getDeclaringType();
  20.                         Field loggerField = declaringType.getDeclaredField("logger");
  21.                         loggerField.setAccessible(true);
  22.                         return (Logger) loggerField.get(null);
  23.                 } catch (NoSuchFieldException e) {
  24.  
  25.                 } catch (Exception e) {
  26.  
  27.                 }
  28.                 return logger;
  29.         }
  30.  
  31.         public static void logParamValues(StringBuilder logLine,
  32.                         String[] paramNames, Object[] paramValues) {
  33.                 for (int i = 0; i < paramValues.length; i++) {
  34.                         logLine.append(paramNames[i]).append("=")
  35.                                         .append(toString(paramValues[i]));
  36.                         if (i < paramValues.length - 1)
  37.                                 logLine.append(", ");
  38.                 }
  39.         }
  40.  
  41.         @SuppressWarnings("rawtypes")
  42.         public static String toString(Object object) {
  43.                 if (object == null)
  44.                         return "<null>";
  45.                 else if (object instanceof String) {
  46.                         if(((String) object).length() > 100)
  47.                                 return ((String) object).substring(0, 100) + "...[more]";
  48.                         else return (String) object;
  49.                 }
  50.                 else if (object instanceof Long)
  51.                         return ((Long) object).toString();
  52.                 else if (object instanceof Boolean)
  53.                         return ((Boolean) object).toString();
  54.                 else if (object instanceof Double)
  55.                         return ((Double) object).toString();
  56.                 else if (object instanceof Integer)
  57.                         return ((Integer) object).toString();
  58.                 else if (object instanceof List)
  59.                         return "items{" + ((List) object).size() + "}";
  60.                 else
  61.                         return "object";
  62.         }
  63. }

the class contains 3 methods, "getLogger" will extract the logger attribute of the method class not to change the logger class name
the 2nd method "logParamValues" format the log of the method in form "methodName(param1=xxxx, param2=xxxx)"
the 3rd method "toString", converts an object to a string format but not the same as the built in toString object method

Use the following enum to prevent logging on specific method, just annotate the method with @NO_LOG and aspectJ will ignore the method :

  1. package com.myapp.util;
  2.  
  3. public @interface NO_LOG {
  4.  
  5. }

now for the aspect file [don't forget to configure aspectJ in your class path]:

  1. import java.util.List;
  2.  
  3. import org.aspectj.lang.reflect.CodeSignature;
  4.  
  5. import com.myapp.util.AspectUtils;;
  6.  
  7. public aspect ServicesLogger {
  8.  
  9.         pointcut logMethod():
  10.                 execution(!@com.myapp.util.NO_LOG *  com.myapp.services..* (..));
  11.  
  12.         before(): logMethod() {
  13.                 Object[] paramValues = thisJoinPoint.getArgs();
  14.                 String[] paramNames = ((CodeSignature) thisJoinPointStaticPart
  15.                                 .getSignature()).getParameterNames();
  16.                 StringBuilder logLine = new StringBuilder(thisJoinPointStaticPart
  17.                                 .getSignature().getName()).append("(");
  18.                 if (paramNames.length != 0)
  19.                         AspectUtils.logParamValues(logLine, paramNames, paramValues);
  20.                 logLine.append(") - started");
  21.                 AspectUtils.getLogger(thisJoinPoint).info(logLine.toString());
  22.         }
  23.  
  24.         @SuppressWarnings("rawtypes")
  25.         after() returning(Object r): logMethod(){
  26.  
  27.                 if (r != null && (!(r instanceof List) || ((List) r).size() != 0)) {
  28.                         StringBuilder rv = new StringBuilder("Return Value : ");
  29.                         rv.append(AspectUtils.toString(r));
  30.                         AspectUtils.getLogger(thisJoinPoint).info(rv.toString());
  31.                 }
  32.  
  33.                 Object[] paramValues = thisJoinPoint.getArgs();
  34.                 String[] paramNames = ((CodeSignature) thisJoinPointStaticPart
  35.                                 .getSignature()).getParameterNames();
  36.                 StringBuilder logLine = new StringBuilder(thisJoinPointStaticPart
  37.                                 .getSignature().getName()).append("(");
  38.                 if (paramNames.length != 0)
  39.                         AspectUtils.logParamValues(logLine, paramNames, paramValues);
  40.                 logLine.append(") - finished");
  41.                 AspectUtils.getLogger(thisJoinPoint).info(logLine.toString());
  42.         }
  43. }

Add new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Enter the characters shown in the image.
By submitting this form, you accept the Mollom privacy policy.