Hey AOP fan, after explaining the basics of AOP in Part 1, we will dive deeper and demonstrate hands-on how to implement smart logging in Spring Boot using AOP.
The complete example can be found on GitHub.
The Problem with Logging Everywhere
As software developers, we know the importance of logging 📝. But scattering log statements everywhere comes with drawbacks:
-
Code duplication as the same logs show up in multiple places
-
Cluttered, harder-to-read class files
-
Modifying logs means changing code directly
Look at this example:
public void updateUser(User user) { // Log method entry log.info("Updating user {}", user.getId()); // Update user logic user.update(); // Log method exit log.info("User updated"); }
Without AOP, your logs might be a mix of different actions, making it hard to filter what's important:
INFO: Updating user 12345 INFO: User updated 12345 INFO: Deleted user 67890
The same logger call shows up everywhere. Yuck!
This leads to a dilemma - log everything and suffer messy code, or omit logging and lose visibility.
There must be a better way! 🤔
Introducing Aspect-Oriented Logging
With AOP, we can modularize cross-cutting concerns like logging away from core functionality. Let's see it in action!
Here are examples and code snippets that illustrate how to use this aspect:
Custom Annotation @Loggable
First, you would define a custom annotation @Loggable which could look something like this:
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Loggable { boolean showValues() default false; String[] showParameters() default {}; String[] hideParameters() default {}; }
Then define the LoggingAspect.
Finally, utilize the smart @Loggable in your application at either the class or method level, e.g., DoctorController:
@Loggable(hideParameters = {"name"}) public class DoctorController { private final DoctorService doctorService; @GetMapping @LogExecution public List<DoctorDto> getAllDoctors() { return doctorService.getAllDoctors(); } @GetMapping("/{id}") public DoctorDto getDoctor(@PathVariable Long id, @RequestParam String name, @RequestParam String date) { return doctorService.getDoctor(id, name, date); } }
Now logging is cleanly separated from core code via AOP!
After Code Sample Output
With AOP, your logs are now consistent and centralized:
DoctorController -> getAllDoctors() Execution time of getAllDoctors is 104ms DoctorController -> getDoctor(id = 1, date = mydate)
This output shows method names and parameters being logged systematically, and the name parameter is hidden, thanks to AOP.
Smart Logging Techniques 🧠
We can take it further by controlling what gets logged based on metadata.
For example:
@Loggable(showParams = {"id"}, hideParams = {"password"}) public void updateUser(Long id, String password) { // User update logic }
Smart Logging Technique Output
With smart logging annotations, you get precise control over logged information:
INFO: Entering UserService.updateUser with params [id=12345] INFO: Exiting UserService.updateUser
Passwords are masked, while IDs are shown, enhancing both security and clarity.
Where to Go from Here
With AOP, we can log smarter, not harder! Some ideas:
- Performance tracing with @Around
- Control logging level via configuration
- Log to different outputs
Remember to keep logging output meaningful to avoid flooding your logs with unnecessary details, which can make it harder to find important information when you need it.
With LoggingAspect, you have a powerful tool to fine-tune your application's logging strategy, so make the most of it to enhance monitoring and debugging capabilities.
The possibilities are endless! What will you build? Let me know in the comments!
Follow us to learn smarter techniques. Subscribe to our news channel and clone our GitHub repository. See you soon!