Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set up the spring boot logger to scheduled tasks only?

I have a spring boot project, so I set up the hibernate logger to log all queries in a request like this:

In my application.properties file

logging.level.org.hibernate.type=trace
logging.level.org.hibernate.SQL=debug
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=trace

This works fine, All my requests show the log for the hibernate queries.

But I also have a scheduled task to run every one second like this:

@Scheduled(cron = "${* * * * * *}")
public void task() {
  ...
}

So, I want to turn off the hibernate queries log only for this task execution to avoid mess up my requests output log.

How can I set up the logger to do this?! Thanks.

like image 814
danielgatis Avatar asked Aug 12 '20 15:08

danielgatis


People also ask

How do I schedule a task in spring boot?

Java Cron ExpressionThe @EnableScheduling annotation is used to enable the scheduler for your application. This annotation should be added into the main Spring Boot application class file. The @Scheduled annotation is used to trigger the scheduler for a specific time period.

How do I start and stop a scheduler in spring boot?

The schedulers do not start or stop. In the real world, it is necessary to stop and restart the scheduler without restarting the spring boot application. The ScheduledAnnotationBeanPostProcessor class allows you to programmatically start and stop the scheduler without having to restart the spring boot application.

What is the default logging in Spring Boot?

When Spring Boot starters are used, Logback is used for logging by default. The default Logback implementation logs the output to the console at the info level. Logback routing is included as well to ensure support for Apache Commons Logging, Java Util Logging, Log4J and SLF4J.

What is @Spring Boot scheduling tasks tutorial?

Spring Boot scheduling tasks tutorial shows how to schedule tasks with @Scheduled in a Spring Boot application. Spring Bootis a popular framework for building enterprise applications in Java, Kotlin, or Groovy.

Where does the Spring-Boot-starter-logging starter pull from?

When using Spring Boot 2.x, the spring-boot-starter-logging starter pulls in the spring-jcl module, which contains the Apache Commons Logging provider. If using Spring Boot 1.x, Apache Commons Logging em> needs to be imported explicitly.

How does Logback work in Spring Boot starters?

When using starters, Logback is used for logging by default. Spring Boot preconfigures it with patterns and ANSI colors to make the standard output more readable. Let's now run the application and visit the http://localhost:8080/ page, and see what happens in the console:


3 Answers

If you're using Slf4j and logback, you can filter based on the Mapped Diagnostic Context (http://logback.qos.ch/manual/mdc.html).

The MDC is thread-local, and you can put any key-value pairs in it that you want to use in the logger. E.g:

@Scheduled(cron = "${* * * * * *}")
public void task() {
  MDC.put("DONOTLOG", "true")
  try {
    ....
  } finally {
    MDC.remove("DONOTLOG");
  }
}

You can use this in a custom logback filter (http://logback.qos.ch/manual/filters.html), by putting this in your logback.xml:

<configuration>
  <appender name="...">

    <filter class="...SampleFilter" />

  </appender>

SampleFilter:

public class SampleFilter extends Filter<ILoggingEvent> {

  @Override
  public FilterReply decide(ILoggingEvent event) {    
    if (event.getMDCPropertyMap().containsKey("DONOTLOG")) {
      return FilterReply.DENY;
    } else {
      return FilterReply.NEUTRAL;
    }
  }
}
like image 105
GeertPt Avatar answered Oct 31 '22 16:10

GeertPt


I don't think you will be able to achieve your result.

Even if you manage to switch off the logging levels for hibernate at runtime, it will switch off the log level globally in the application for hibernate because it is tied to the caller class loader

It means if there concurrent executions of hibernate calls where you want to log in the first synchronous execution and you don't want in the second concurrent asynchronous execution, they are going to interfere with each other and you will get non deterministic results

like image 41
Kavithakaran Kanapathippillai Avatar answered Oct 31 '22 16:10

Kavithakaran Kanapathippillai


I assume you are using Slf4j.

This library does not support that functionally out of the box.

The capacity of changing the logger level at runtime largely depends on the underlying logging libraries (Logback, Log4J2, etcetera) configured.

But Spring Boot provides an underlying logging system that handles all this stuff for us. We can use that underlying logging system to achieve the functionally that you need.

You can do something like the following example:

@Scheduled(cron = "${* * * * * *}")
public void task() {
  // At the beginning of the method, disable logging levels
  final List<String> loggerNames = Arrays.asList("org.hibernate.SQL", "org.hibernate.type", "org.hibernate.type.descriptor.sql.BasicBinder");
Map<String, LogLevel> previousLogLevels = new HashMap();
loggerNames.forEach(loggerName -> {
  final LoggerConfiguration loggerConfiguration = loggingSystem.getLoggerConfiguration(loggerName);
  final LogLevel logLevel = loggerConfiguration.getEffectiveLevel();
  previousLogLevels.put(loggerName, logLevel);
  loggingSystem.setLogLevel(loggerName, LogLevel.OFF);
});
  
  try {
    // Do your stuff
    ...
  } finally {
    // Restore the logging levels to the original ones
    previousLogLevels.forEach((loggerName, logLevel) -> loggingSystem.setLogLevel(loggerName, logLevel));
  }
}

You must inject a bean of type LoggingSystem in your scheduled task bean so you can reference it in the code.

This functionally can be easily reused in different contexts: if you need to, you can create an aspect for that, for instance, freeing the business logic from this need.

Edit

After read the @KavithakaranKanapathippillai answer, and read again, carefully, your question, I fully understand your need.

He is right: please, be aware that with this setup you will modify the logging level of the affected logs globally, not only for the async task, and the rest of the code will be also affected for the change, so it will be always a chance for lost some "normal" application code log traces if that "normal" code uses Hibernate and is executed while the async task is running.

If this is important or not will largely depend on how much the async task is running - I suppose it runs very fast if it is executed every second but, on the other hand, it runs a lot times - and how many transactions your application receives.

like image 27
jccampanero Avatar answered Oct 31 '22 14:10

jccampanero