How to enable Logback-access in Spring Boot? - spring

I'm trying to enable logback-access in a spring boot app to log all http requests that hit the application.
I've tried implementing this using: https://github.com/akihyro/logback-access-spring-boot-starter
Adding the XML file shown in the example doesn't do anything, is there anything more that needs to be added to enable?
Any other suggestions to achieve the same result would be welcomed :)

you still need to wire a bean to your application...like this code snippet wires the filter to your application:
#SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
// ... your other methods here
#Bean
public CommonsRequestLoggingFilter logFilter() {
CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter();
filter.setIncludeQueryString(true);
return filter;
}
}

I am pretty sure you are talking about the logback logger for SpringBoot. If I am not wrong, this is how you can do this
a. Add the dependency in your POM
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
b. Now there are may ways you can ask spring to configure logback. For example
In the application.properties file
In the logback.xml file
The advantage of using logback.xml file is that, you might have different xml file for different build profile. But in the application.properties, you don’t have this freedom.
Sample entries in the application.properties file from one of my project
logging.level.org.springframework.web = INFO
logging.level.com.company.app = DEBUG
#logging.level.org.hibernate=ERROR
logging.file=logs/spring-boot-logging.log
## Hibernate Logging
logging.level.org.hibernate.SQL = DEBUG
If you are using XML, configuration probably will look like this
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</Pattern>
</layout>
</appender>
<logger name="org.springframework" level="error" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
<logger name="org.springframework" level="info" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
<logger name="org.springframework" level="warn" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
<logger name="com.memorynotfound" level="debug" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
<configuration scan="true"/>
</configuration>
I recommend you to do some Googling for better understating.
Good luck!

Related

Spring boot log level does not work for subpackage

I have a spring boot application where I need to change log level to info for my application and error for the library it uses. Both of them have the same parent package structure:
com.org.product.library
com.org.product.module
I added the following to the application.yml
logging:
level:
com.org.product.library: ERROR
com.org.product.module: INFO
But now the module is also logging only errors.
This is how Logger is invoked:
public static void info(String msgCode, String msg) {
if (isInfoEnabled()) {
getLoggerEngine().info(msgCodeMarker(msgCode), msg);
}
}
static Logger getLoggerEngine() {
//slf4j LoggerFactory
return LoggerFactory.getLogger(Log.class);
}
Also there is this spring-logback.xml configuration in the library:
<logger name="com.org" level="info" additivity="false">
<appender-ref ref="json" />
</logger>
<!-- By default will log warnings and above-->
<!-- set to other level for development if needed -->
<root level="warn">
<appender-ref ref="json" />
</root>

Stopped Logging : Logback SiftingAppender log folder change runtime using MDC in Multitenant spring boot app

I have multi-tenant application followed by microservices created in spring boot version 1.4.3, i have generated tenant wise logs in different folders inside logs folder of tomcat.
A Problem which i am facing is after some time/hours/days/weeks my logs will stop but application work in backgroud. I am trying to find root cause of the same but failed.
In java code some classes using Slf4j and some classes using log4j to print logs.
As mentined i am using SiftingAppender and changing logFolder variable from Filter/Intercepter based on the tenant.
previously i was doing MDC.clear() to remove logFolder from MDC, then i have moved to MDC.remove("logFolder") but that also not worked
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}}" />
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<!-- This is MDC value -->
<!-- We will assign a value to 'logFileName' via Java code -->
<appender name="FILE-THREAD" class="ch.qos.logback.classic.sift.SiftingAppender">
<!-- This is MDC value -->
<!-- We will assign a value to 'logFileName' via Java code -->
<discriminator>
<key>logFolder</key>
<defaultValue>main</defaultValue>
</discriminator>
<sift>
<appender name="FILE-${logFileFolder}" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_FILE}/${logFolder}/enquiryengine.log</file>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
<!-- <file>${LOG_FILE}</file> -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE}/${logFolder}/enquiryengine.log.%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
<maxHistory>15</maxHistory>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
</sift>
</appender>
<springProfile name="development">
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE-THREAD" />
</root>
</springProfile>
<springProfile name="production">
<root level="INFO">
<appender-ref ref="FILE-THREAD" />
</root>
</springProfile>
<springProfile name="staging">
<root level="INFO">
<appender-ref ref="FILE-THREAD" />
</root>
</springProfile>
<springProfile name="testing3">
<root level="INFO">
<appender-ref ref="FILE-THREAD" />
</root>
</springProfile>
<springProfile name="testing">
<root level="INFO">
<appender-ref ref="FILE-THREAD" />
</root>
</springProfile>
<springProfile name="testing2">
<root level="INFO">
<appender-ref ref="FILE-THREAD" />
</root>
</springProfile>
<jmxConfigurator />
</configuration>
public class MyClass extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
MDC.put(UtilConstant.LOG_FOLDER_NAME, "dynamicTenantFolderName");
return true;
}
#Override
public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
MDC.remove(UtilConstant.LOG_FOLDER_NAME);
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
MDC.remove(UtilConstant.LOG_FOLDER_NAME);
}
}
public class TenantRequestFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
MDC.remove(UtilConstant.LOG_FOLDER_NAME);
MDC.put(UtilConstant.LOG_FOLDER_NAME, "dynamicLogFolderName");
// Goes to default servlet
chain.doFilter(requestWrapper, response);
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
#Override
public void destroy() {
MDC.remove(UtilConstant.LOG_FOLDER_NAME);
}
}
As logs are not working so i will not get any stack trace, Expected Result is logs generation should not stop.
The default Timeout for Siftappender is 30 Minutes,
If no logs are written in 30mins then the siftappender gets timeout and no further logs on that MDC will be processed.
To overcome this,
1. You can increase the time limit as per the application's requirement
2. Have a scheduler to print log after particular interval, so that it never gets timeout
Refer Document: http://logback.qos.ch/manual/appenders.html

log4j2 monitorInterval springboot not working

Im trying to get hot reloading to work with my logging level. The monitorInterval Should do the trick for me, but for some reason it doesnt work.
My log4j2.xml file looks like this:
<Configuration monitorInterval="10">
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout
pattern="%d{ISO8601} [%-12.-12t] %-5p [%12.12X{CorrelationId}] [%-30.-30X{Path}] %logger{36}:%L - %msg%n"/>
</Console>
<File name="anywhere" fileName="anywhere.log" append="false">
<PatternLayout>
<Pattern>%d{ISO8601} [%-12.-12t] %-5p [%12.12X{CorrelationId}] [%-30.-30X{Path}] %logger{36}:%L - %msg%n</Pattern>
</PatternLayout>
</File>
</Appenders>
<Loggers>
<logger name="com.cetrea" level="info"/>
<Root level="warn">
<AppenderRef ref="anywhere"/>
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
Im testing it with my rest api, and when i hit this route, it should print out just LOG.info which it does.
private static final Logger LOG = LogManager.getLogger(TokenController.class);
#RequestMapping(value = "/sensitive-data/{token}", method = RequestMethod.GET, produces = "text/plain;charset=UTF-8")
public ResponseEntity getData(#PathVariable("token") String token) {
if (tokenMap.containsKey(token)) {
return ResponseEntity.ok(tokenMap.get(token));
} else {
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
LOG.info("Hit with wrong or expired token at " + timestamp + "");
LOG.debug("debug thing");
return new ResponseEntity("Token not found, or has expired", HttpStatus.NOT_FOUND);
}
}
Now if i change the level to debug, i would expect it to also print out the LOG.debug, but it doesn't. This doesn't take in effect until i restart the program, instead of it hot reloading 10 seconds later.
As it turns out, when it builds it includes the log4j file, and then reads from that, so the file i was editting wasnt read. I added
-Dlog4j.configurationFile="Path to the actual file"
to the runtime settings and then it worked.

Package Filter in Logback.xml

Project Structure
I would like to output log for all queries under every mapper package.
I don't want like to define each mapper package like this since the project will consist of a lot of packages later.
don't want to do
How can i achieve like this?
<logger name="com.example.demo.*.mapper" level="DEBUG">
<appender-ref ref="SAVE-TO-FILE" />
</logger>
You could use a String constant for the logger name instead of letting Logback derive the logger name from the current class. For example, each class in the com.example.demo.*.mapper package would declare a logger like so:
// extract "MAPPER" to a shared constant to maybe provide a MapperLogger utility class
Logger logger = LoggerFactory.getLogger("MAPPER");
Then your logger configuration would be:
<logger name="MAPPER" level="DEBUG">
<appender-ref ref="SAVE-TO-FILE" />
</logger>
Or you could programmatically create loggers for every class in the com.example.demo.*.mapper package and associate each with your SAVE-TO-FILE appender.
I didn't find an answer to that question. That is why I've done some filtering by myself using ch.qos.logback.core.filter.EvaluatorFilter:
<configuration>
<property name="package" value="com.example.demo.*.mapper" />
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator>
<expression>return logger.matches("^" + "${package}".replaceAll("\\*", "\\.*").replaceAll("([^\\\\])\\.", "$1\\\\.") + "$");</expression>
</evaluator>
<OnMismatch>DENY</OnMismatch>
<OnMatch>NEUTRAL</OnMatch>
</filter>
<encoder>
<pattern>%-5level [%d{HH:mm:ss}] [%thread] %-30logger{10} %msg%n</pattern>
</encoder>
</appender>
</configuration>

Querydsl logging queries with bindings

logQuery is called in prepareStatementAndSetParameters mehtod - SQLInsertClause class
protected void logQuery(Logger logger, String queryString, Collection<Object> parameters) {
String normalizedQuery = queryString.replace('\n', ' ');
MDC.put(QueryBase.MDC_QUERY, normalizedQuery);
MDC.put(QueryBase.MDC_PARAMETERS, String.valueOf(parameters));
if (logger.isDebugEnabled()) {
logger.debug(normalizedQuery);
}
}
how can I set debug level to logger ?
That logger there is from SLF4J API. Depending on the logger you have behind the API you use facilities of that underlying logging implementation.
For instance we use Logback Classic (dependency ch.qos.logback:logback-classic) and I can explicitly override what configuration file to use with -Dlogback.configurationFile=devel-logback.xml in JVM parameters. Default mechanism is documented here. My file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date %level [%.60thread] %logger{1} %msg%n</pattern>
</encoder>
</appender>
<logger name="com.mysema.query.jpa.impl.JPAQuery" level="DEBUG"/>
<!-- more loggers -->
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
Also adding -Dlogback.debug=true to JVM arguments adds some debug output when logback is being initialized.

Resources