// pom.xml <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.5</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.30</version> </dependency> // log4j.properties log4j.rootLogger=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n // ApplicationConfig.java @Configuration @PropertySource("classpath:application.properties") @ComponentScan(basePackages = "com.frankmoley.lil.fid") @EnableAspectJAutoProxy // Enable AOP public class ApplicationConfig { } // Loggable annotation @Target(ElementType.METHOD) // annotation should work on methods @Retention(RetentionPolicy.RUNTIME) // annotation should be loaded during runtime public @interface Loggable { } // Service @Service public class GreetingService { @Value("${app.greeting}") private String greeting; public GreetingService(){ super(); } @Loggable // This is the joinpoint : Where the aspected behavior is stitched public String getGreeting(String name){ return greeting + " " + name; } } // Aspect class @Component @Aspect // ensure for component scanning public class LoggingAspect { private static final Logger LOGGER = LoggerFactory.getLogger(LoggingAspect.class); @Pointcut("@annotation(Loggable)") // connect with the annotation. The annotation is the pointcut (will trigger this aspect) public void executeLogging(){} // The original Advise : the logic that will run when annotation is called @Before(value = "executeLogging()") // Pre-Advise: the logic that will run before execution of original advise public void logMethodCall(JoinPoint joinPoint){ StringBuilder message = new StringBuilder("Method: "); // *root-start message.append(joinPoint.getSignature().getName()); Object[] args = joinPoint.getArgs(); if (null!=args && args.length>0){ Arrays.asList(args).forEach(arg->{ message.append(arg).append(" | "); }); // *root-end } LOGGER.info(message.toString()); } @AfterReturning(value = "executeLogging()", returning = "returnValue") // Post-Advise: the logic that will run after execution of original advise public void logMethodCall(JoinPoint joinPoint, Object returnValue){ // same as *root-start to *root-end // .. just work with returnValue if(returnValue instanceof Collection){ // *return-start message.append(", returning: ").append(((Collection)returnValue).size()).append(" instance(s)"); }else{ message.append(", returning: ").append(returnValue.toString()); } LOGGER.info(message.toString()); // *return-end } @Around(value = "executeLogging()") // Most Flexible : Anything before original advise, anything after original advise returning value, anything after original advise returning exception public Object logMethodCall(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); Object returnValue = joinPoint.proceed(); long totalTime = System.currentTimeMillis()-startTime; // same as *root-start to *root-end // same as *return-start to *return-end return returnValue; } }logging: level: org: springframework: security: DEBUGlogging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG logging.level.org.springframework.jdbc.core.StatementCreatorUtils=TRACElogging.level.org.springframework.web=INFO logging.level.org.hibernate=ERROR logging.level.net.guides=DEBUGspring.jpa.properties.hibernate.format_sql=truelogging.level.org.springframework.security=DEBUGimport org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MyApp { private static final Logger logger = LoggerFactory.getLogger(MyApp.class); public static void main(String[] args) { SpringApplication.run(MyApp.class, args); // Logging example logger.trace("This is a TRACE level message."); logger.debug("This is a DEBUG level message."); logger.info("This is an INFO level message."); logger.warn("This is a WARN level message."); logger.error("This is an ERROR level message."); } }@RestController public class LoggingController { Logger logger = LoggerFactory.getLogger(LoggingController.class); @RequestMapping("/") public String index() { logger.trace("A TRACE Message"); logger.debug("A DEBUG Message"); logger.info("An INFO Message"); logger.warn("A WARN Message"); logger.error("An ERROR Message"); return "Howdy! Check out the Logs to see the output..."; } } Lombok has annotations for that. Annotate your class with @Slf4j and a static log fiedl will be generated.We can use logging with Spring Boot by specifying log levels on the application.properties file. Spring Boot loads this file when it exists in the classpath and it can be used to configure both Spring Boot and application code. Spring Boot, by default, includes spring-boot-starter-logging as a transitive dependency for the spring-boot-starter module. By default, Spring Boot includes SLF4J along with Logback implementations. If Logback is available, Spring Boot will choose it as the logging handler. You can easily configure logging levels within the application.properties file without having to create logging provider-specific configuration files such as logback.xml or log4j.properties.