Recipe21.2.Applying Aspect-Oriented Logging


Recipe 21.2. Applying Aspect-Oriented Logging

Problem

You want to apply logging in a modular and application independent way.

Solution

Create an abstract Logging aspect that extends the generic TRacingAspect from Recipe 21.1. Extend the tracingAspect with abstract pointcut definitions and advice for exception logging to complete the logging aspect, as shown in Example 21-3. The new exception logging abstract pointcut definitions allow specialized subaspects to capture areas of the target application where exception logging needs to take place.

Example 21-3. An abstract logging aspect that defines the generic logging logic to be specialized for your application
public abstract aspect LoggingAspect extends TracingAspect {    protected abstract pointcut exceptionsToBeLogged( );        private pointcut filteredExceptionCapture( ) :        exceptionsToBeLogged( ) &&        !pointsToBeExcluded( );        before( ) : filteredExceptionCapture( )    {       logException(thisJoinPoint);    }        public abstract void logException(JoinPoint joinPoint); }

Discussion

The LoggingAspect aspect inherits all of the behavior from the TRacingAspect shown in Recipe 21.1 but adds some new capabilities specific to logging. The exceptionsToBeLogged() abstract pointcut is provided so specialized subaspects can specify the join points where exception information is to be logged. The logException(JoinPoint) abstract method allows subaspects to implement the exact behavior that will occur when exceptions are logged.

The handler(TypePattern) pointcut is the most appropriate pointcut declaration to use in the specialized subaspects when implementing the abstract exceptionsToBeLogged( ) pointcut. However, no way exists to restrict the exceptionsToBeLogged( ) pointcut to just hand-ler(TypePattern) pointcut definitions.


The filteredExceptionCapture() pointcut then combines the exceptionsToBeLogged( ) pointcut with the pointcutsToBeExcluded() pointcut inherited from the tracingAspect so any join points that have been declared as excluded continue to be excluded from the logging.

Example 21-4 shows how the abstract LoggingAspect in Example 21-3 can be applied to an example application.

Example 21-4. Implementing logging for an example application
public aspect ApplicationLoggingAspect extends LoggingAspect {    public pointcut pointsToBeTraced( ) : call(* *.*(..));        public pointcut pointsToBeExcluded( ) :  call(* java.io.*.*(..));        public pointcut exceptionsToBeLogged( ) :        handler(com.oreilly.aspectjcookbook.PackageA.BusinessException);        protected void traceBefore(JoinPoint joinPoint, Object caller)    {       System.out.println("Log Message: Called " + joinPoint.getSignature( ));    }        protected void traceStaticBefore(JoinPoint joinPoint)    {       System.out.println("Log Message: Statically Called " +        joinPoint.getSignature( ));    }        protected void traceAfter(JoinPoint joinPoint, Object object)    {       System.out.println("Log Message: Returned from " +        joinPoint.getSignature( ));    }        protected void traceStaticAfter(JoinPoint joinPoint)    {       System.out.println("Log Message: Returned from static call to " +           joinPoint.getSignature( ));    }        protected void logException(JoinPoint joinPoint)    {       System.out.println("Log Message: " + joinPoint.getArgs( )[0] +        " exception thrown");    }        private static aspect FormatCallDepthAspect    {       private static int callDepth;              private pointcut captureTraceBefore( ) :           call(protected void TracingAspect.trace*Before(..));              private pointcut captureTraceAfter( ) :           call(protected void TracingAspect.trace*After(..));              after( ) : captureTraceBefore( )       {          callDepth++;       }              before( ) : captureTraceAfter( )       {          callDepth--;       }              private pointcut captureMessageOutput(String message) :           call(* *.println(String)) &&           args(message) &&          within(ApplicationLoggingAspect) &&          !within(FormatCallDepthAspect);              Object around(String originalMessage) : captureMessageOutput                                               (originalMessage)       {          StringBuffer buffer = new StringBuffer( );          for (int x = 0; x < callDepth; x++)          {             buffer.append("  ");          }          buffer.append(originalMessage);                    return proceed(buffer.toString( ));       }    } }

The ApplicationLoggingAspect aspect provides an implementation of the pointsToBeTraced( ) and pointsToBeExcluded() pointcuts to specify the areas of the target application to be logged and excluded from logging. The new exception logging pointcut, exceptionsToBeLogged(), is implemented to meet the requirements of the LoggingAspect.

The FormatCallDepth inner aspect is included in the ApplicationLoggingAspect for convenience to make the logging messages easy to read when they are output through System.out. If you were using a full logging solution, this inner aspect would most likely not be required as the logging API would probably provide formatting options of its own.

You can plug in any logging API you want to use by placing the code that initializes and invokes your logging API in the specialized subaspects of the LoggingAspect aspect.


The abstract LoggingAspect aspect supports multiple subaspects potentially logging parts of your application in different ways at the same time. The code sample in Example 21-5 shows how an additional aspect could be added to logs calls to targets within a specific package using an XML format for the message output.

Example 21-5. Applying multiple logging solutions to the same application
public aspect PackageSpecificLoggingAspect extends LoggingAspect {    declare precedence : ApplicationLoggingAspect,                          PackageSpecificLoggingAspect;        public pointcut pointsToBeTraced( ) :        call(* com.oreilly.aspectjcookbook.PackageA.*.*(..));        public pointcut pointsToBeExcluded( ) : call(void java.io.                                            PrintStream.*(..));        public pointcut exceptionsToBeLogged( ) : handler(PackageA.*);        protected void traceBefore(JoinPoint joinPoint, Object object)    {       System.out.println("<before>" + joinPoint.getSignature( ) +                           "</before>");    }        protected void traceStaticBefore(JoinPoint joinPoint)    {       System.out.println("<before type=\"static\">" +          joinPoint.getSignature( ) + "</before>");    }        protected void traceAfter(JoinPoint joinPoint, Object object)    {       System.out.println("<after>" + joinPoint.getSignature( ) + "</after>");    }        protected void traceStaticAfter(JoinPoint joinPoint)    {       System.out.println("<after type=\"static\">" +           joinPoint.getSignature( ) + "</after>");    }        protected void logException(JoinPoint joinPoint)    {       System.out.println("<exception>" + joinPoint.getSignature( ) +        "</exception>");    }

See Also

The call(Signature) pointcut is described in Recipe 4.1; the handler(TypePattern) pointcut is shown in Recipe Recipe 5.1; the AND (&&) operator and the OR (||) operator are described in Recipes 12.2 and 12.3 respectively; the before( ) form of advice is explained in Recipe 13.3; the around( ) form of advice, including using the proceed( ) method, is discussed in Recipe 13.4; the after( ) form of advice is explained in Recipe Recipe 13.5; using inheritance to implement abstract aspects is explained in Recipe 15.2; defining and using inner aspects is explained in Recipe 15.4.



AspectJ Cookbook
Aspectj Cookbook
ISBN: 0596006543
EAN: 2147483647
Year: 2006
Pages: 203
Authors: Russ Miles

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net