I'm working on a spring boot project, which use log4j2 for logging. The log4j2.xml is stored in DB, so I have to retrieve it before using.
It looks like below:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<!-- setting -->
<Properties>
<Property name="merchantdb">/syslog/translog/merchantdb/</Property>
<Property name="pattern1">%d{yyyy-MM-dd HH:mm:ss}[%5p][%C{2}][%t] %m%n</Property>
<Property name="pattern2">%d{yyyy-MM-dd HH:mm:ss}[%5p][%C{2}.%M()] %m%n</Property>
</Properties>
<!-- appender setting -->
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${pattern1}"/>
</Console>
<RollingFile name="merchantdb" filePattern="${merchantdb}/merchantdb.log.%d{yyyy-MM-dd}">
<PatternLayout pattern="${pattern1}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
</Policies>
<DirectWriteRolloverStrategy/>
</RollingFile>
<RollingFile name="merchantdb_io" filePattern="${merchantdb}/merchantdb_io.log.%d{yyyy-MM-dd}">
<PatternLayout pattern="${pattern2}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
</Policies>
<DirectWriteRolloverStrategy/>
</RollingFile>
<RollingFile name="merchantdb_i" filePattern="${merchantdb}/merchantdb_i.log.%d{yyyy-MM-dd}">
<PatternLayout pattern="${pattern2}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
</Policies>
<DirectWriteRolloverStrategy/>
</RollingFile>
<RollingFile name="merchantdb_o" filePattern="${merchantdb}/merchantdb_o.log.%d{yyyy-MM-dd}">
<PatternLayout pattern="${pattern2}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
</Policies>
<DirectWriteRolloverStrategy/>
</RollingFile>
<RollingFile name="rmds" filePattern="${merchantdb}/rmds.log.%d{yyyy-MM-dd}">
<PatternLayout pattern="${pattern2}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
</Policies>
<DirectWriteRolloverStrategy/>
</RollingFile>
<Socket name="socket" host="10.77.249.230" port="20002" reconnectionDelay="5000" immediateFlush="true">
<JsonLayout compact="true" includeStacktrace="true" charset="UTF-8" eventEol="true" locationInfo="true" objectMessageAsJsonObject="true" stacktraceAsString="true">
<KeyValuePair key="hostName" value="$${hostName}"/>
</JsonLayout>
</Socket>
</Appenders>
<Loggers>
<Logger name="merchantdb" level="all" additivity="false">
<AppenderRef ref="merchantdb"/>
<AppenderRef ref="Console"/>
<AppenderRef ref="socket"/>
</Logger>
<Logger name="merchantdb_io" level="all" additivity="false">
<AppenderRef ref="merchantdb_io"/>
<AppenderRef ref="Console"/>
<AppenderRef ref="socket"/>
</Logger>
<Logger name="merchantdb_i" level="all" additivity="false">
<AppenderRef ref="merchantdb_i"/>
<AppenderRef ref="Console"/>
<AppenderRef ref="socket"/>
</Logger>
<Logger name="merchantdb_o" level="all" additivity="false">
<AppenderRef ref="merchantdb_o"/>
<AppenderRef ref="Console"/>
<AppenderRef ref="socket"/>
</Logger>
<Logger name="com.alibaba.druid.pool" level="all" additivity="false">
<AppenderRef ref="rmds"/>
</Logger>
</Loggers>
</Configuration>
I know there are multiple ways to initialize *.xml. It did work when using URI to initialize. However, I found myself having problem with initialize with ConfigurationSource. It seems the config doesn't set properly when using ConfigurationSource, logger still print in default format.
Below is my code, is there anything that I miss?
Thanks a lot.
#Configuration
public class ConfigLoader {
public static Logger logger;
#Bean
#DependsOn("ds_settingsDB")
public Logger log4j2() throws IOException {
System.out.println("loading Log4j2");
FileWriter fw = null;
LoggerContext context = null;
try {
String fieldvalue = SettingsDB.get("Log4J2.xml");
//initBySource(fieldvalue); //this doesn't works
initByFilePath(fieldvalue); //this works
logger = LogManager.getFormatterLogger("merchantdb");
logger.info("log4j2 load complete");
return logger;
}catch(Exception e) {
throw new EipException(e);
} finally {
if(fw!=null){
fw.close();
}
}
}
private LoggerContext initBySource(String fieldvalue) throws Exception {
InputStream in = new ByteArrayInputStream(fieldvalue.getBytes("utf-8"));
ConfigurationSource source = new ConfigurationSource(in);
LoggerContext ctx = Configurator.initialize(null, source);
return ctx;
}
private LoggerContext initByFilePath(String fieldvalue) throws Exception {
FileWriter fw = null;
LoggerContext ctx = null;
String filePath = "C:\\apconf\\log4j2zzz.xml";
fw = new FileWriter(filePath);
fw.write(fieldvalue);
fw.flush();
File file = new File(filePath);
if(file.exists()){
ctx = Configurator.initialize(null, filePath);
}
return ctx;
}
}
My app is using spring log4j2 and uses slf4j api to write log to separate log file "application.log". This app gets deployed to tomcat v8 along with other apps. All app share common log4j2 configuration and writes to common logfile 'application.log'. We have a log rotation policy of 250 mb and when the log file rotates the logs are not written to the logfile surprising only one app among all the app is able to write to the log file. I'm able to reproduce this locally too. Can you please help in fixing this issue.
The other
Please find the log4j2.xml config below.
JAR VERSIONS
slf4j-api 1.7.21
log4j-slf4j-impl 2.5
log4j-api 2.5
log4j-core 2.5
log4j-web 2.5
Log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration name="api-config" status="trace" monitorInterval="30">
<Properties>
<Property name="logdir">/Users/kramesan/microservices-config/logs</Property>
</Properties>
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%X{_requestId} %X{authToken} %X{urlEmployeeId} %X{urlCompanyId} [%X{authEmplIds}] [%X{authCompanyIds}] %d{yyy
y-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
</Console>
<RollingFile name="ApplicationLogRollingFile" fileName="${logdir}/application.log"
filePattern="${logdir}/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
<JSONLayout locationInfo="true" complete="true" compact="true" eventEol="true" properties="true" />
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="250 MB" />
</Policies>
<DefaultRolloverStrategy max="20" />
</RollingFile>
<RollingFile name="AuditLogRollingFile" fileName="${logdir}/audit/api-audit.log"
filePattern="${logdir}/audit/$${date:yyyy-MM}/api-audit-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout>
<Pattern>%X{_requestId} %X{authToken} %X{urlEmployeeId} %X{urlCompanyId} [%X{authEmplIds}] [%X{authCompanyIds}] %m%n</Pattern>
</PatternLayout>
<!-- JSONLayout locationInfo="true" complete="true" compact="true" eventEol="true" properties="true" -->
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="250 MB" />
</Policies>
<DefaultRolloverStrategy max="20" />
</RollingFile>
<Async name="ApplicationLogAsync" bufferSize="262144">
<AppenderRef ref="ApplicationLogRollingFile"/>
</Async>
<Async name="AuditLogAsync" bufferSize="262144">
<AppenderRef ref="AuditLogRollingFile"/>
</Async>
</Appenders>
<Loggers>
<!-- All the 3rd Party frameworks -->
<Logger name="org.springframework" level="warn" />
<Logger name="org.hibernate" level="warn" />
<!-- common package name for all the business application level code -->
<Logger name="com.trinet" level="info" />
<!-- Audit Loggger This is used for spring aspect to log before and after execution -->
<Logger name="AuditLogger" level="info">
<AppenderRef ref="AuditLogAsync" />
</Logger>
<Root level="info">
<AppenderRef ref="ApplicationLogAsync" />
</Root>
</Loggers>
</Configuration>
Please, edit your Logger name. Logger name property needs package path.
AS-IS
...
<Logger name="AuditLogger" level="info">
...
TO-BE
...
<Logger name="com.foo.bar.AuditLogger" level="info" additivity="false">
...
or
...
<Logger name="com.foo.bar.*" level="info" additivity="false">
...
I think you'd better write property additivity Because your Logger works two times com.foo.bar.AuditLogger Logger and Root Logger. so you additivity to false then it works each.
reference link : Additivity
In my controller I get an id as request param. Is there a way to use this id to identify all the log entries of this particular request?
#ResponseBody
#RequestMapping(value="/anyRequest", method = RequestMethod.GET)
public String doAnything(#RequestParam(value="Id", required = true) long id) {
logger.info(id);
return "";
}
Means anywhere of this entry should be the id value:
2017-02-28 08:30:41.035 INFO 23050 --- [http-bio-1084-exec-20] AnyServiceImpl ...
Im using logback and have this configuration:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<springProfile name="dev">
<property name="FILE_PATH" value="C:\\DATA\\temp" />
</springProfile>
<appender name="FILE-AUDIT"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${FILE_PATH}/service.log</file>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n
</Pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>service.%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>25MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>90</maxHistory>
</rollingPolicy>
</appender>
<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<charset>UTF-8</charset>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n</Pattern>
</encoder>
</appender>
<logger name="Service" level="info"
additivity="false">
<appender-ref ref="FILE-AUDIT" />
<appender-ref ref="consoleAppender" />
</logger>
<root level="info">
<appender-ref ref="FILE-AUDIT" />
<appender-ref ref="consoleAppender" />
</root>
</configuration>
And I use the logger in this way:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
Is there any Spring out of the box magic?
Use MDC to achieve this.
Controller Method:
#ResponseBody
#RequestMapping(value="/anyRequest", method = RequestMethod.GET)
public String doAnything(#RequestParam(value="Id", required = true) long id) {
try {
MDC.put("id", id);
logger.info(id);
return "";
} finally {
org.slf4j.MDC.clear();
}
}
Logback.xml:
<Pattern>[%X{id}] %d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n</Pattern>
Is there a way to log some custom #Query method?
Here is example of my code:
#Query(value = "SELECT * FROM transfer WHERE char_length(internal_id) = 5 " +
"AND internal_id REGEXP '^[0-9]+$' AND project_id = :projectId order by created_at desc limit 1", nativeQuery = true)
Transfer findLastWithDefaultOurIdForProject(#Param("projectId") String projectId);
It's written in interface that extends spring-data PagingAndSortingRepository.
I have tried to log it with adding these lines in property file:
log4j.logger.org.hibernate.SQL=DEBUG
log4j.logger.org.hibernate.type=TRACE
but I only get queries without real values passed from my service to repository interface?
Try this configuration:
application.properties
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.database=h2
Add logback.xml file under src/main/resources to configure Hibernate to show parameters passed to the SQL Query:
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<logger name="org.springframework.web" level="DEBUG"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
</encoder>
</appender>
<logger name="org.hibernate.SQL" additivity="false" >
<level value="DEBUG" />
<appender-ref ref="STDOUT" />
</logger>
<logger name="org.hibernate.type" additivity="false" >
<level value="TRACE" />
<appender-ref ref="STDOUT" />
</logger>
</configuration>
You can find the working Demo Project in my GitHub repository.
The problem is your application properties. http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-logging.html#boot-features-custom-log-levels
You have the wrong prefix on the properties.
logging.level.org.hibernate.SQL=DEBUG logging.level.org.hibernate.type=TRACE
I have a problem with configuration on Logback in a Spring Boot application. I want my consoleAppender to look like the default Spring Boot console appender. How to inherit pattern from Spring Boot default console appender?
Below is my consoleAppender configuration
<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern class="org.">
%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
Once you have included the default configuration, you can use its values in your own logback-spring.xml configuration:
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
<!-- use Spring default values -->
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
…
</configuration>
You can find Spring Boot logback console logging pattern in defaults.xml file:
spring-boot-1.5.0.RELEASE.jar/org/springframework/boot/logging/logback/defaults.xml
Console pattern:
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wEx
</Pattern>
</layout>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>
If you are using application.yml for your config, you can set the logging pattern this way:
logging:
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} | %-5level | %logger{1.} | %msg%n"
level:
org.springframework: WARN
com.ulisesbocchio.jasyptspringboot: WARN
com.example.test: DEBUG
You can override the logging level on the command line. For example:
$ java -Dlogging.level.com.example.test=TRACE -jar my-example.jar
It's been some time since this question was asked but since I had the problem myself recently and couldn't find an answer I started digging a bit deeper and found a solution that worked for me.
I ended up using the debugger and take a look at the default appenders attached to the logger.
I found this pattern to be working as desired for me:
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %5p 18737 --- [%t] %-40.40logger{39} : %m%n%wEx</pattern>
EDIT: The pattern is not entirely correct, I saw that runtime some values had already been instantiated (in this case 18737 ---) i will look into the proper variable to substitute there. It does contain the format for fixed length columns though
EDIT 2: Ok, I took another look at the debugger contents. This you can also do yourself by looking at the contents of a logger instance:
Debugger(eclipse) Logger Contents
So I ended up using the pattern used in the consoleAppender:
%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(18971){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wEx
As can be seen here:
Debugger: detailed contents of the encoder pattern
Logging pattern can be configured using application.properties file
Example :
# Logging pattern for the console
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %msg%n
You can use below pattern :
%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${sys:PID} --- [%15.15t] %-40.40logger{1.} : %m%n%wEx
Note that you can also customize the imported properties.
But beware that at least with spring boot 1.4.3 if you want to customize the properties imported from the defaults.xml, then the customization should be placed BEFORE the include.
For example this customizes the priority to 100 character wide:
<configuration scan="true">
<property name="LOG_LEVEL_PATTERN" value="%100p" />
<!-- use Spring default values -->
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
</layout>
</appender>
<logger name="hu" level="debug" additivity="false">
<appender-ref ref="CONSOLE" />
</logger>
<root level="warn">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
But this is NOT:
<configuration scan="true">
<!-- use Spring default values -->
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<property name="LOG_LEVEL_PATTERN" value="%100p" />
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
</layout>
</appender>
<logger name="hu" level="debug" additivity="false">
<appender-ref ref="CONSOLE" />
</logger>
<root level="warn">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
For those who'd like to use Łukasz Frankowski's answer (which looks like the cleanest solution here), but in a groovy version, the "problematic" {$PID:- } part can be expanded like in the following:
logback-spring.groovy
import ch.qos.logback.classic.PatternLayout
import ch.qos.logback.core.ConsoleAppender
import org.springframework.boot.logging.logback.ColorConverter
import org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter
import org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter
import static ch.qos.logback.classic.Level.INFO
conversionRule("clr", ColorConverter)
conversionRule("wex", WhitespaceThrowableProxyConverter)
conversionRule("wEx", ExtendedWhitespaceThrowableProxyConverter)
appender("STDOUT", ConsoleAppender) {
layout(PatternLayout) {
def PID = System.getProperty("PID") ?: ''
pattern = "%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID}){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wEx"
}
}
root(INFO, ["STDOUT"])
This worked for me, adding following line to resources/log4j2.properties file
appender.console.layout.pattern = %d{ISO8601} - info: %msg%n ( your custom pattern goes here )
The spring documentation has an example of the logback.xml that defines the default.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
<logger name="org.springframework.web" level="DEBUG"/>
</configuration>