Spring always print logs at DEBUG level when running Maven - spring

I am using slf4j, logback for logging in my Spring application. I have configured to exclude common-logging and add the jcl-over-slf4j bridge.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.3</version>
</dependency>
My logback.xml looks like the following:
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
<logger name="com.my" level="DEBUG" />
The problem is when running maven builds, classes from spring always prints in DEBUG level which pollutes the console with verbose information. This doesn't happen when running the app with Tomcat though.
Also, if I extend a class of Spring, e.g. HttpSessionRequestCache, logging statements from the Spring classes are executed, as if it get the level from the child class! This does happen when running with Tomcat.
How to make Maven honor the logback.xml configuration?

Related

How can I get AWS Lambda and Spring Boot 2.1.5 to use Log4j2.xml and log to Cloudwatch?

In order to log to cloudwatch in a lambda, one must use this log4j2.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration packages="com.amazonaws.services.lambda.runtime.log4j2">
<Appenders>
<Lambda name="Lambda">
<PatternLayout>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %X{AWSRequestId} %-5p %c{1}:%L - %m%n</pattern>
</PatternLayout>
</Lambda>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Lambda" />
</Root>
</Loggers>
</Configuration>
Also the following items must be in the pom.xml:
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.1.5.RELEASE</version>
</parent>
...
<dependency>
<artifactId>aws-lambda-java-log4j2</artifactId>
<groupId>com.amazonaws</groupId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.2</version>
</dependency>
Of course none of this works for me. It seems Spring uses Logback and I have tried shutting that off using these instructions. Nothing seems to work.
Any tips?
Got it! I read a post/rant where a guy noticed that AWS used a "5 year old jar" for the Cloudwatch/Lambda logging (can't find it now). So I found a Log4j2 jar that is compatible with 1.2 (log4j-1.2-api) and it worked. I had to shut off Logback in Spring and activate Log4j2. Below should take you all the way.
<dependency>
<artifactId>spring-boot-starter</artifactId>
<groupId>org.springframework.boot</groupId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<artifactId>aws-lambda-java-log4j2</artifactId>
<groupId>com.amazonaws</groupId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId>
<version>2.11.2</version>
</dependency>
...
PS. You might need to fix this as well: log4j2 ERROR StatusLogger Unrecognized conversion specifier

How to force spring boot to log to the container via SLF4J?

I have a spring boot application running on Wildfly 10 that I wish to "force" logging through the container. The ultimate goal is to control logging via standalone.xml config having org.springframework.* with INFO level and my own code as DEBUG level. After many SO questions and googling the best solution I achieved is:
My own code logs correctly and is "captured" by the container.
Spring framework is always in DEBUG and ignores whatever is defined in the container root logger.
org.hibernate.SQL is always in DEBUG and also ignores the application server.
I always get the spring auto-configuration report.
My configuration so far is:
<!-- Handlers and formatters ommited for brevity -->
<subsystem xmlns="urn:jboss:domain:logging:3.0">
<add-logging-api-dependencies value="true"/>
<use-deployment-logging-config value="false"/>
<logger category="com.arjuna">
<level name="INFO"/>
</logger>
<logger category="org.jboss.as.config">
<level name="INFO"/>
</logger>
<logger category="org.jboss.logging" use-parent-handlers="false">
<level name="DEBUG"/>
<handlers>
<handler name="FILE"/>
</handlers>
</logger>
<logger category="MYAPP" use-parent-handlers="false">
<level name="DEBUG"/>
<handlers>
<handler name="MYAPP"/>
</handlers>
</logger>
<root-logger>
<level name="INFO"/>
<handlers>
<handler name="CONSOLE"/>
<handler name="FILE"/>
</handlers>
</root-logger>
</subsystem>
As for the POM I followed many answers here to try and remove any trace of spring logback implementations and forcing it to use SL4J. The ideia was to exclude commons-logging and starter-logging packages for every spring-boot-starter.
I ommited some packages for space, but even my own utility jar's ommit those two artifacts in their own POM's (for each used starter).
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
</dependencies>
Also, I have tried using jboss-deployment-structure.xml, albeit to no avail. Current configuration is:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
<deployment>
<exclude-subsystems>
<subsystem name="logging" />
</exclude-subsystems>
<exclusions>
<module name="org.apache.commons.logging" />
<module name="org.apache.log4j" />
<module name="org.jboss.logging" />
<module name="org.jboss.logging.jul-to-slf4j-stub" />
<module name="org.jboss.logmanager" />
<module name="org.jboss.logmanager.log4j" />
<module name="org.slf4j" />
<module name="org.slf4j.impl" />
</exclusions>
</deployment>
</jboss-deployment-structure>
I also checked the final maven build and:
jcl-over-slf4j is present
SLF4-API is NOT present.
jboss-logging-3.3.1.Final is present (added via hibernate 5 dependencies)
I think I'm missing something obvious but I can't understand what it is. What might it be?
Thank you.

Externalize logback.xml in Spring MVC

I use SL4J for logging in my Java Spring MVC Web Application. I have the logback.xml file under /src/main/resources. In my pom.xml file, I have the following related to logging:
<properties>
<org.slf4j-version>1.6.4</org.slf4j-version>
<logback.version>1.0.1</logback.version>
</properties>
And the following dependencies:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<!-- logback -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
</dependencies>
Now logging is working fine for me. But now I am trying to move the logback.xml file outside the war file so that I do not have to change the war file to change the logging level. I was trying to move the file to ${catalina.base}/conf/. I was unable to find a way to specify the path of the file which would be ${catalina.base}/conf/logback.xml. I have found a couple of similar questions, but I couldint find a solution that I could use:
Externalized the location of logback.xml in Spring Boot using application.properties and
logback externalization. Is there any way I can move the file under the conf folder under tomcat and specify its path so that I can keep this logback.xml ouside the war file
It is not good idea to put logging properties in tomcat config folder. Better to put it inside application folder/war.
But there is a way to locate logback.xml from external directory by setting a property in your spring application properties file.
For example in application.properties add
logging.config=file:/home/user/tomcat/conf/logback.xml

How direct all internal Springboot logging to log4j?

I would like to have all the internal Springboot log messages directed to log4j so that the messages follow my log4j properties (i.e. they go to the console and my log4j file using my layout).
I attempted to configure Springboot to use only log4j logging per this guide: http://spring.io/blog/2009/12/04/logging-dependencies-in-spring/
I have successfully setup log4j to log to the console and to file when using a log4j logger object.
However, it appears that Springboot is still using slf4j when it logs internally. I tried removing the slf4j dependencies, but Springboot fails to startup with a missing class exception.
How can I direct all the internal Springboot logging to log4j?
Have you tried this from the official docs?
http://docs.spring.io/spring-boot/docs/1.2.2.RELEASE/reference/htmlsingle/#howto-configure-log4j-for-logging
Basically you have to exclude the logback stuff that comes by default with the starter poms.
Quoted here for reference:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
</dependency>
If you are using spring-boot, I recommend following the spring documentation, which I found easier than your reference.
I have log4j working, and it prints messages like:
[2015-03-06 15:34:54 INFO ] [main] [tomcat.TomcatEmbeddedServletContainer] Tomcat initialized with port(s): 8080 (http)
Not sure if that's what you mean by internal messages.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>1.1.4.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- add slf4j interfaces to classpath this is for log4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.4</version>
<scope>runtime</scope>
</dependency>
<!-- add log4j to classpath -->
<!-- does the logging -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
Add log4j.properties under resources
log4j.rootLogger=INFO, Console, File
# Direct log messages to stdout
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.Target=System.out
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %m%n
log4j.appender.File=org.apache.log4j.RollingFileAppender
log4j.appender.File.append=true
log4j.appender.File.file=/tmp/projectdir/logfile-ws.log
log4j.appender.File.threshold=INFO
log4j.appender.File.layout=org.apache.log4j.PatternLayout
log4j.appender.File.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %m%n
log4j.appender.File.MaxFileSize=100MB
log4j.appender.File.MaxBackupIndex=1

Why am I not getting logging from Spring Security?

I am trying to test my #PreAuthorize tags that are placed on the methods in my Spring Controller. I am not getting any logging information as to the decisions being made by Spring on whether to allow or disallow a call. Currently I am being allowed into a method and I want to debug why I am being allowed even though I don't have the role.
I am using Spring Framework 3.2.3, Spring Security 3.1.4, Logback 1.0.13, Logback Spring 0.1.1.
Here is my logback file:
...
<appender name="MAIN" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/logs/main_log.txt</file>
<append>true</append>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>TRACE</level>
</filter>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} | %p | %c %M | %m%n</pattern>
</encoder>
<rollingPolicy>
<fileNamePattern>/logs/main_log.txt.%d</fileNamePattern>
</rollingPolicy>
</appender>
<logger name="org.springframework" level="TRACE"/>
<logger name="my.package" level="TRACE"/>
<root level="WARN">
<appender-ref="MAIN"/>
</root>
I have the listener set up properly in my web.xml file. I know this because I am getting log messages from the package my.package as well as WARN messages from 3rd party software.
Any ideas as to how I can see the decisions being made by the #PreAuthorize annotation?
Your configuration seeems fine, but Spring unfortunately uses commons logging. Follow the official documentation on how to use SLF4J (+ log4j or logback).
http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/overview.html#overview-not-using-commons-logging
Just don't add commons-logging jar or if you use Maven exlude it like shown in the documentation. Then you need a bridge between commons-logging and SLF4J (jcl-over-slf4j.jar).
Cut out from my (working) configuration:
<logger name="org.springframework" level="DEBUG" additivity="false">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</logger>
pom.xml:
<!-- Logging -->
<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>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.0.13</version>
<scope>runtime</scope>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
In order to use Pre-PostAuthorize annotations, it's necessary to enable their use in spring configuration, as they are off by default.
This is how to enable these annotations when using the global-method-security XML element (see here for further details):
<global-method-security pre-post-annotations="enabled"/>

Resources