Logging Made Easy

Sudharshan S.R.
Nerd For Tech
Published in
4 min readFeb 17, 2021

Logging has become an integral part of any application, be it a web service or a standalone application. Proper log statements are a gold mine for debuggers and programmers who look into codes developed by fellow developers.

There are various use cases where log comes in handy, but the main purpose that logging serves is as follows:

  • It helps to track the errors, thus saves time in providing a fix for the same.
  • When a program terminates abruptly (Not an ideal use case but still it happens!), based on the log statement we can see which method or class executed before the application went down.
  • To analyse performance of any method, by noting the time taken to process the whole method.

Error logs are the most commonly used logs and they are mostly written inside the catch block. These contain the error message which resulted in termination of the application.

Now for scenarios two and three developers often write a log statement at the start of the method/block and then finish off with the ending of the method. This process repeats for almost all the methods present in the class. What if I say we have an easier solution available using Spring AOP(Aspect Oriented Programming) ?.

Spring’s Aspect Oriented Programming provides an easy way to wrap up functionalities around a method or class, thus acting as an interceptor (for explanation sake , we’ll refer it so),which implements itself before/after a method executes itself.

Spring AOP Terminology
  • Advice- Refers to the functionality that the interceptor needs to implement
  • Point cut- Refers to the points at which the interceptor needs to be called.
  • Join Points- Refers to the point at which the execution of the particular method or logic changes. Thus acting as the joining point between two different execution and thus the name ‘Join Points’.

So now let’s implement a simple Spring Boot Web service which uses AOP to create user-defined Annotations to print entry exit loggers with and without method parameters.

STEP 1

First we need to add the AOP dependency. I’m using a Gradle project , the corresponding dependency can be found online here

STEP 2

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SimpleLogger {
}
  • We need to define a user defined annotation.
  • Using this annotation we can specify which method needs an entry exit logger.

STEP 3

@Around("@annotation(com.medium.example.logger.SimpleLogger)")
public Object entryExitLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
final Logger logger = LoggerFactory.getLogger(ServiceAspect.class.getName());
logger.info(">>> Enter {} {} ", proceedingJoinPoint.getSignature().getDeclaringTypeName(), proceedingJoinPoint.getSignature().getName());
Object proceed = proceedingJoinPoint.proceed();
logger.info("<<< Exit {} {} ", proceedingJoinPoint.getSignature().getDeclaringTypeName(), proceedingJoinPoint.getSignature().getName());
return proceed;
}
  • Define the advice. This refers to the logic that needs to be implemented while using the above created annotation
  • ‘@Around’ here implies that we need the logic to be implemented when the method (which will be annotated by the simpleLogger), execution starts and before the method execution ends. Thus around the method.
  • Similarly the logic for parameterizedLogger is also implemented. This will print the parameters that are being passed to the method, in addition to the entry exit logger.
  • proceedingJoinPoint object contains the details of the method which has been annotated, thus we can derive the class name (getDeclaringTypeName) and the method name (getName()) from the Signature object present in the proceedingJoinPoint.
  • The method parameters of the annotated method can also be extracted from the proceedingJoinPoint object.

STEP 4

@Service
public class LoggerService {

@SimpleLogger
public void simpleLogging(){

}

@ParameterisedLogger
public String parameterisedLogging(String name) {
return "Hello "+name;
}
}
  • We annotate the methods using the annotations we created.
  • Here we have a simple service class which has no logger statements of it’s own but just the annotation.

RESULT

>>> Enter com.medium.example.service.LoggerService simpleLogging
<<< Exit com.medium.example.service.LoggerService simpleLogging
>>> Enter com.medium.example.service.LoggerService parameterisedLogging with parameters [medium]
<<< Exit com.medium.example.service.LoggerService parameterisedLogging
  • As visible we have the logger statements being printed for the service.
  • Both , the simple logger and parameterised logger are visible and working as the entry exit loggers, without any logger statements present in the service.

CONCLUSION

Thus we can very easily reduce the lines of code by defining simple annotations to take care of entry exit logging. This will not only enhance code readability but also improve the efficiency as we do not need to declare logger object in each class.

Similarly we can use the same concept to analyse the performance of the method. We can declare a separate annotation and club an advice with it. Thus whenever needed we can use that performance annotation, for whichever method we want.

--

--

Sudharshan S.R.
Nerd For Tech

Programmer, Data Enthusiast, Software Engineer By profession , Avid Anime Fan, New Tech Fanatic, Foodie