Method Tracing Aspects
Following aspects enable method tracing by using Spring AOP. The following information will be gathered and logged:
- Types and values of input parameters
- Type and value of return object
- Types and details of exceptions
@Configuration
@Aspect
public class MethodTracingAspect {
private static Logger logger = LoggerFactory.getLogger(MethodTracingAspect.class);
@Autowired private LoggerCache loggerCache;
@PostConstruct
protected void init() {
logger.warn("###-AOP-### DebuggableAspect initialized...");
}
@Before(
"(com.yourcorp.common.aspect.CommonPointcut.servicePackageMethodDebugEnabled()
"
+ "|| com.yourcorp.common.aspect.CommonPointcut.implPackageMethodDebugEnabled())
&& "
+ "!com.yourcorp.common.aspect.CommonPointcut.nonTraceableAnnotationEnabled()")
public void
logDebugInformationMethodBeforeEntering(JoinPoint joinPoint) {
final Logger mLogger = loggerCache.getLogger(joinPoint);
mLogger.debug(
"Entering class:{} - method : {} with input parameters
{}",
joinPoint.getTarget().getClass().getSimpleName(),
joinPoint.getSignature().getName(),
joinPoint.getArgs());
}
@AfterReturning(
value =
"(com.yourcorp.common.aspect.CommonPointcut.servicePackageMethodDebugEnabled()
"
+ "|| com.yourcorp.common.aspect.CommonPointcut.implPackageMethodDebugEnabled())
&& "
+ "!com.yourcorp.common.aspect.CommonPointcut.nonTraceableAnnotationEnabled()",
returning = "result"
)
public void
logDebugInformationMethodAfterReturning(JoinPoint joinPoint, Object result) {
final Logger mLogger = loggerCache.getLogger(joinPoint);
mLogger.debug(
"Returning from class:{} - method : {} with return type:
{} - value {}",
joinPoint.getTarget().getClass().getSimpleName(),
joinPoint.getSignature().getName(),
((MethodSignature)
(joinPoint.getSignature())).getReturnType().getSimpleName(),
result);
}
}
@Configuration
@Aspect
public class ExceptionHandlingAspect
{
@Autowired private LoggerCache loggerCache;
@AfterThrowing(
value = "com.yourcorp.common.aspect.CommonPointcut.servicePackageMethodDebugEnabled()",
throwing = "exception"
)
public void logRecoverableFailureException(
JoinPoint joinPoint,
RecoverableFailureException exception) {
Logger logger = loggerCache.getLogger(joinPoint);
logger.warn("\t " + exception.getFullMessage(), exception);
}
@AfterThrowing(
value = "com.yourcorp.common.aspect.CommonPointcut.servicePackageMethodDebugEnabled()",
throwing = "exception"
)
public void logUnRecoverableFailureException(
JoinPoint joinPoint,
UnRecoverableFailureException exception) {
Logger logger = loggerCache.getLogger(joinPoint);
logger.error("\t " + exception.getFullMessage(), exception);
}
}
|
Common Pointcuts
import org.aspectj.lang.annotation.Pointcut;
/**
* The pointcuts defined here are the service classes most likely logging, metrics and tracing
* concerns will be the applied.
*/
@Aspect
public class CommonPointcut {
// All method in service packages
@Pointcut("execution(* com.yourcorp.app..service.*.*(..))")
public void servicePackageMethodDebugEnabled() {
// no implementation.
}
// All method in impl packages
@Pointcut("execution(* com.yourcorp.app..impl..*.*(..))")
public void implPackageMethodDebugEnabled() {
// no implementation.
}
// Methods with @MethodDebuggingDisable
@Pointcut("@annotation(com.yourcorp.app.common.aspect.debug.MethodDebuggingDisable))")
public void nonTraceableAnnotationEnabled() {
// no implementation.
}
}
|
Custom Annotation
/**
* If a method is very
sensitive to
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodTracingDisable {}
|
Logger Cache
/**
* Cache logger according to type, the logger search operation is expensive.
*/
@Service
public class LoggerCacheImpl implements LoggerCache {
private Map<Class<?>,
Logger> loggerCache = new ConcurrentReferenceHashMap<>();
@Override
@MethodTracingDisable
public Logger
getLogger(JoinPoint joinPoint) {
final Class<?> clazz = joinPoint.getTarget().getClass();
return loggerCache.computeIfAbsent(clazz, e -> LoggerFactory.getLogger(e));
}
}
|