Can't disable quartz-scheduler logging using SLF4J - java

After adding quartz-scheduler to a project, Tomcat's server log is being spammed with the following message:
[INFO] [talledLocalContainer] 12:15:06.319
[DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG
o.quartz.core.QuartzSchedulerThread - batch acquisition of 0 triggers
I'm trying to disable that log message, which repeats every 25-seconds or so. I've been through a number of other answers to this same question, such as:
Disable quartz logging
stop quartz debug logging log4j
Disabling Log4J Output in Java
...and none of the approaches suggested are working.
I have the following dependencies declared in pom.xml:
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
And I've added the following log4j.properties settings to my project:
log4j.rootLogger=OFF
log4j.logger.quartz=OFF
log4j.logger.o.quartz=OFF
log4j.logger.org.quartz=OFF
...and also the following simplelogger.properties:
org.slf4j.simpleLogger.defaultLogLevel=error
In addition to attempting the programmatic solution suggested on one of the linked answers, which should disable all logging and goes roughly like:
List<Logger> loggers = Collections.<Logger>list(LogManager.getCurrentLoggers());
loggers.add(LogManager.getRootLogger());
for ( Logger logger : loggers ) {
logger.setLevel(Level.OFF);
}
That seems to disable everything except the log message from quartz when it runs.
Is there a way to get rid of the log message from quartz, short of modifying the quartz source-code to remove it?

The logging entry above doesn't look like Log4J. I think thats ACL or JUL. When you are using Slf4j to Log4J, you also need to redirect these frameworks to Slf4j. Add these dependencies to your project as well:
<!--Redirect Apache Commons Logging to Slf4J -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.5</version>
</dependency>
<!--Redirect Java Util Logging to Slf4J -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.5</version>
</dependency>
Read this doc page about redirecting Jul to Slf4J, too. Be sure to exclude any existing commons-logging.jar files from your project, through Maven.
(From the Slf4J documentation page)
And if all else fails, try the following code:
//see if we can find the offending logger through slf4j's LoggerFactory
org.slf4j.Logger logger =
LoggerFactory.getLogger(Class.forName("org.quartz.core.QuartzSchedulerThread"));
if (logger != null && logger instanceof ch.qos.logback.classic.Logger) {
//the slf4j Logger interface doesn't expose any configuration API's, but
//we can cast to a class that does; so cast it and disable the logger
((ch.qos.logback.classic.Logger)logger).setLevel(
ch.qos.logback.classic.Level.OFF);
}

Related

Is it possible to exclude transitive runtime scope dependency from dependencies in POM?

I have a spring boot project which is having runtime transitive dependency on slf4j and log4j. Because of this I am seeing slf4j multiple binding warning and then an IllegalArgumentExceptionIllegalArgumentException. You can find below entire exception message :
SLF4J: Found binding in [jar:file:/Users/pulkit/.m2/repository/com/xyz/platform/event/PlatformLibrary/1.0.1/PlatformLibrary-1.0.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/Users/pulkit/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
[2021-03-04 08:41:59,594] INFO Kotlin reflection implementation not found at runtime, related features won't be available. (org.springframework.core.KotlinDetector)
Exception in thread "main" java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback or the competing implementation (class org.slf4j.impl.Log4jLoggerFactory loaded from file:/Users/pulkit/.m2/repository/com/xyz/platform/event/PlatformLibrary/1.0.1/PlatformLibrary-1.0.1.jar). If you are using WebLogic you will need to add 'org.slf4j' to prefer-application-packages in WEB-INF/weblogic.xml: org.slf4j.impl.Log4jLoggerFacto
I read other answers related to same issue and tried excluding the slf4j binding from the platform library which is a private repo but I it doesn't seems to be working. Below is the exclusion block which I added in pom.xml:
<dependency>
<groupId>com.xyz.platform.event</groupId>
<artifactId>PlatformLibrary</artifactId>
<version>1.0.1</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
But this doesn't seems to be working however I am able to exclude the dependency from spring-boot-starter-web which works fine though probably due to older version it doesn't take use the property logging.pattern.console anymore.
Can somebody please suggest what can be done in this case?
I could see following in dependency tree
but for private library/package I couldn't see any dependency inside it, may be because it's dependency scope is runtime.
Note: I have changed the path of repo since it is a private repo.

How to use custom logger with Logback and SLF4J

I have existing project with very standart Logback implementation.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class SomeClass{
Logger log = LoggerFactory.getLogger(getClass());
void someMethod(){
log.info("some log message");
}
}
This is used in many places and in code I dont have sources. ch.qos.logback.classic.Logger is used as implementation.
I want to use my own implementation of Logger (I wanted to extend ch.qos.logback.classic.Logger but it's final) and use it applicatio wide without modifying the code (which I don't have anyway).
I would expect that configuration of LoggerFactory in logback.xml would be possible, but it doesn't seem so.
I'm using maven artifacts
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
I could not find straight way of doing it. I came over XLogger and logback-ext but it seems I would need to modify all factory usages.

Control myBatis logs destination file and level

I'm working on a spring-based application which has to communicate with a SQL database through mybatis: all right but the logs destination.
For some reason mybatis logs to the wrong file, could you help me to figure out why? Here's my configuration:
log4j.properties:
### Appenders
# Console appender
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Threshold=WARN
log4j.appender.console.layout=org.apache.log4j.PatternLayout
# Application file appender
log4j.appender.main=org.apache.log4j.RollingFileAppender
log4j.appender.main.File=logs/app.log
log4j.appender.main.layout=org.apache.log4j.PatternLayout
log4j.appender.main.MaxFileSize=10MB
log4j.appender.main.MaxBackupIndex=15
# Libs file appender
log4j.appender.libs=org.apache.log4j.RollingFileAppender
log4j.appender.libs.File=logs/app_libs.log
log4j.appender.libs.layout=org.apache.log4j.PatternLayout
log4j.appender.libs.MaxFileSize=10MB
log4j.appender.libs.MaxBackupIndex=15
### Loggers & additivity
# Application
log4j.additivity.our.company.basepackage=false
log4j.logger.our.company.basepackage=TRACE,main,console
# Root logger
log4j.rootLogger=INFO,libs
pom.xml snippet
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
<scope>runtime</scope>
</dependency>
I find TRACE-level rows of mybatis ("org.apache.ibatis.logging.jdbc.BaseJdbcLogger.trace(BaseJdbcLogger.java:145)") in the file "app.log".
I excluded commons-logging from spring-core, and with a dependency tree I don't see commons-logging. Why isn't mybatis logging to the file "app_libs.log"? Why does mybatis not respect the specified level?
Thank you.
Edit 1
The code with which the database gets queried has been generated with mybatis-generator, and the generated code lives somewhere under the package "our.company.basepackage".
Since the question was posted, I didn't stop to think about this, until now: I found the reason of that behaviour.
The decisive suggestion is that "the code has been generated with mybatis-generator", and it has been generated in the same subpackage of the application: this means that the *Mapper classes, used for querying the databaes, effectively are in the application package and so their logs are treated as logs of "our.company.basepackage" and not as logs of "org.apache.ibatis".
The "org.apache.ibatis" in logs rows was misleading me.
After this small insight, I added the following to my log4j.properties:
log4j.additivity.our.company.basepackage.persistence.mybatis=false
log4j.logger.our.company.basepackage.persistence.mybatis=INFO,libs
With these 2 more lines, everything works properly, i.e. no more "org.apache.ibatis" rows in app.log.
I hope that this can be useful to someone other using mybatis-generator.

Unable to disable logging messages

I have some trouble getting rid of debug messages generated by Spring (similiar to the following ones; there are thousands of those entries):
19:58:08.380 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'propertyPlaceholderConfigurer'
19:58:08.380 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'propertyPlaceholderConfigurer'
19:58:08.383 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'appConfig'
19:58:08.383 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'appConfig'
19:58:08.383 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'appConfig' to allow for resolving potential circular references
19:58:08.384 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'appConfig'
In related questions, there were many suggestions involving log4j, web.xml, ....
However, I am not using any of those - I simply instantiate an AnnotationConfigApplicationContext and start creating beans.
In my pom.xml file, there are no references to any logging framework - I only include the spring dependencies:
<!-- Spring and Transactions -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- ... -->
<artifactId>spring-tx</artifactId>
<!-- ... -->
<artifactId>spring-boot-starter</artifactId>
<!-- ... -->
<artifactId>spring-web</artifactId>
<!-- ... -->
I read somewhere that Spring seems to use "Commons logging" by default, which I unsuccessfully tried to disable using (as shown in Turn Off Apache Common Logging ):
System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.NoOpLog");
In addition, I tried to exclude the commons logging in my pom.xml by adding:
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
Still no luck, however.
Next, I tried including a dependency to log4j, hoping this would override the default logging. As the format of the messages stayed the same, it seems that this attempt was also not successfull.
What could I try next?
First: Is slf4j on classpath?
SLF4J is another log abstraction for Java, which also could be used together with Spring framework. Many libraries / products have switched to slf4j.
Are there any dependencies with 'slf4j' in its name? Try mvn dependency:tree -Dverbose=true, and look if slf4j appears. If so, look at slf4j website for more information about its setup.
Second: which log4j config file is used?
Hint to detect if log4j is used, and if a log4j config file is somewhere on the classpath:
Try to set property log4j.debug to 'true'.
When using mvn exec:java, simply add -Dlog4j.debug=true to command line.
If this is a Junit test with the maven surefire plugin, try set systemProperties in Surefire plugin itself: http://maven.apache.org/surefire/maven-surefire-plugin/examples/system-properties.html

Send/redirect/route java.util.logging.Logger (JUL) to Logback using SLF4J?

Is it possible to have a typical call to java.util.logging.Logger and have it route to Logback using SLF4J? This would be nice since I wouldn't have to refactor the old jul code line by line.
EG, say we have this line:
private static Logger logger = Logger.getLogger(MahClass.class.getName());
//...
logger.info("blah blah blah");
It would be nice to configure this to call through SLF4J.
It's very easy and not a performance issue anymore.
There are two ways documented in the SLF4J manual. There are also precise examples in the Javadocs
Add jul-to-slf4j.jar to your classpath. Or through maven dependency:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.0</version>
</dependency>
If you don't have logging.properties (for java.util.logging), add this to your bootstrap code:
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
If you have logging.properties (and want to keep it), add this to it:
handlers = org.slf4j.bridge.SLF4JBridgeHandler
In order to avoid performance penalty, add this contextListener to logback.xml (as of logback version 0.9.25):
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
<!-- reset all previous level configurations of all j.u.l. loggers -->
<resetJUL>true</resetJUL>
</contextListener>
...
</configuration>

Categories