creating async and sync loggers on condition in log4j2 - java

My log4j2.xml looks like below.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%sn] [%t] %-5level %logger{36} - %msg%n" />
</Console>
<RandomAccessFile name="randomAccessFile" fileName="temp\\logs.log" immediateFlush="false" append="false">
<!-- <PatternLayout pattern="%d %p %class{2.} [%t] %location %m %ex%n" /> -->
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</RandomAccessFile>
<JDBC name="databaseAppender" tableName="app_logs" bufferSize="1000">
<!-- <DataSource jndiName="java:/comp/env/jdbc/testLog" /> -->
<!-- <BurstFilter level="TRACE" rate="20" maxBurst="2" /> -->
<ConnectionFactory class="com.mc.loggerProvider.ConnectionFactory" method="getDatabaseConnection" />
<Column name="LOG_ID" pattern="%u{TIME}" isUnicode="false" />
<Column name="LOG_TIMESTAMP" isEventTimestamp="true" isUnicode="false" />
<!-- <Column name="CORR_ID" pattern="%X{CORR_ID}" isUnicode="false" /> -->
<Column name="LOG_LEVEL" pattern="%level" isUnicode="false" />
<Column name="LOGGER_NAME" pattern="%logger" isUnicode="false" />
<Column name="MESSAGE" pattern="%msg %ex{full}" isUnicode="false" />
<!-- <Column name="EXCEPTION" pattern="%ex{full}" isUnicode="false" /> -->
</JDBC>
</Appenders>
<Loggers>
<Logger name="console" level="trace" includeLocation="false" additivity="false">
<AppenderRef ref="console" />
</Logger>
<AsyncLogger name="asyncFile" level="trace" includeLocation="false" additivity="false">
<AppenderRef ref="randomAccessFile" />
</AsyncLogger>
<Logger name="syncFile" level="trace" includeLocation="false" additivity="false">
<AppenderRef ref="randomAccessFile" />
</Logger>
<AsyncLogger name="asyncDB" level="trace" includeLocation="false" additivity="false">
<AppenderRef ref="databaseAppender" />
</AsyncLogger>
<Logger name="syncDB" level="trace" includeLocation="false" additivity="false">
<AppenderRef ref="databaseAppender" />
</Logger>
<AsyncLogger name="asyncDBasyncFile" level="trace" includeLocation="false" additivity="false">
<AppenderRef ref="databaseAppender" />
<AppenderRef ref="randomAccessFile"></AppenderRef>
</AsyncLogger>
<Logger name="syncDBsyncFile" level="trace" includeLocation="false" additivity="false">
<AppenderRef ref="databaseAppender" />
<AppenderRef ref="randomAccessFile"></AppenderRef>
</Logger>
<Root level="info" includeLocation="false">
<AppenderRef ref="console" />
</Root>
</Loggers>
</Configuration>
As there are couple of loggers I have defined already for sync/async file/DB logging purpose. The problem which I am facing here when I want to use any of the loggers I cant define a name for those.
LogManager.getLogger("asyncDB") -- will give me logger with name asyncDB
However, the convention says to create loggers with class name as it will be easier to debug if you write %logger in logging output.
LogManager.getLogger(MyClass.class)
My requirement asks me to create a logger with class name however that should be asynchronous or synchronous based on users requirement.
I have created a small class name LogProvider having method registerFor which is again having arguments of type AppendersType. Below is the code.
public class LogProvider {
public static Logger registerFor(AppendersType type) {
switch (type) {
case DATABASE_ASYNC:
return LogManager.getLogger("asyncDB");
case DATABASE_SYNC:
return LogManager.getLogger("syncDB");
case FILE_ASYNC:
return LogManager.getLogger("asyncFile");
case FILE_SYNC:
return LogManager.getLogger("syncFile");
case FILE_DATABASE_SYNC:
return LogManager.getLogger("syncDBsyncFile");
case FILE_DATABASE_ASYNC:
return LogManager.getLogger("asyncDBasyncFile");
default:
break;
}
return null;
}
I want to make use of asyncLoggers but having a name of class and not the name which is defined in XML file.

Related

How to configure log4j2.xml from file to stdout?

Here is my current log4j2.xml file :
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info">
<Properties>
<Property name="logFilename">abc</Property>
<Property name="metricsLogFilename">abc-metrics</Property>
<Property name="pattern">%d [%X{idreq} %X{iduser} %X{codeenv}] %-5p
[%c{1}] : %m%n</Property>
<Property name="metricsPattern">%d : %m%n</Property>
<Property name="level">${sys:LOG4J_LEVEL:-info}</Property>
</Properties>
<Appenders>
<Console name="console" target="SYSTEM_OUT" follow="true" >
<PatternLayout pattern="${pattern}" />
</Console>
<RollingRandomAccessFile name="file"
fileName="${tex:appLogFilePath}${logFilename}.log"
filePattern="${tex:appLogFilePath}${logFilename}-%i.log.gz">
<PatternLayout pattern="${pattern}" />
<Policies>
<SizeBasedTriggeringPolicy size="10MB" />
</Policies>
<DefaultRolloverStrategy max="1" />
</RollingRandomAccessFile>
<RollingRandomAccessFile name="metricsFile"
fileName="${tex:appLogFilePath}${metricsLogFilename}.log"
filePattern="${tex:appLogFilePath}${metricsLogFilename}-%i.log.gz"
immediateFlush="false">
<PatternLayout pattern="${metricsPattern}" />
<Policies>
<SizeBasedTriggeringPolicy size="10MB" />
</Policies>
<DefaultRolloverStrategy max="1" />
</RollingRandomAccessFile>
</Appenders>
<Loggers>
<Logger name="com.myClass.common" level="info" additivity="false">
<AppenderRef ref="console" />
<AppenderRef ref="file" />
</Logger>
<Logger name="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" level="${level}" additivity="false">
<AppenderRef ref="console" />
<AppenderRef ref="file" />
</Logger>
<Logger name="metrics" level="info" additivity="false">
<AppenderRef ref="metricsFile" />
</Logger>
<Root level="${level}">
<AppenderRef ref="console" />
<AppenderRef ref="file" />
</Root>
</Loggers>
I want to switch to stdout instead of file logs. What should I change ? (I've never used log4j)
The reason why I want to have it stdout is because I'll need to deploy my app on heroku, and on heroku we need to use system out logging.
As per current configuration, except metrics, your are logging at both places - in a file as well as on console. For metrices, you are logging in file only.
If you can want to log only at console, remove other appender and their references from logger configuration. For metrices, you have to refer console appender.
Update file may look like -
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info">
<Properties>
<Property name="pattern">%d [%X{idreq} %X{iduser} %X{codeenv}] %-5p
[%c{1}] : %m%n</Property>
<Property name="level">${sys:LOG4J_LEVEL:-info}</Property>
</Properties>
<Appenders>
<Console name="console" target="SYSTEM_OUT" follow="true" >
<PatternLayout pattern="${pattern}" />
</Console>
</Appenders>
<Loggers>
<Logger name="com.myClass.common" level="info" additivity="false">
<AppenderRef ref="console" />
</Logger>
<Logger name="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" level="${level}" additivity="false">
<AppenderRef ref="console" />
</Logger>
<Logger name="metrics" level="info" additivity="false">
<AppenderRef ref="console" />
</Logger>
<Root level="${level}">
<AppenderRef ref="console" />
</Root>
</Loggers>

Log4j2 logs into user home folder

I'm trying to save log4j2 logs into user home folder because the user has not right to write where the application is installed.
This is the relevant part of my log4j settings. Unfortunately it doesn't resolve user.home and so it creates the folder $user.home where the application is running.
<?xml version="1.0" encoding="UTF-8"?>
<configuration name="defaultConfiguration" status="warn" strict="true" monitorInterval="270">
<properties>
<property name="patternlayout">%d{dd/MM/yyyy HH:mm:ss} %5p %c{1}:%L - %m%n
</property>
<property name="filename">${user.home}/niro/logs/niroDesk.log</property>
<property name="filenamePattern">${user.home}/niro/logs/niroDesk.log-%d{yyyy-MM-dd}.log.gz
</property>
</properties>
<appenders>
<appender name="Console" type="Console" target="SYSTEM_OUT">
<layout type="PatternLayout" pattern="${patternlayout}" />
</appender>
<!-- Log su file ogni giorno, e mantenimento degli ultimi 5 files -->
<RollingFile name="File" fileName="${filename}" filePattern="${filenamePattern}" bufferedIO="true" immediateFlush="true" append="true">
<PatternLayout pattern="${patternlayout}" />
<Policies>
<TimeBasedTriggeringPolicy />
</Policies>
<DefaultRolloverStrategy>
<Delete basePath="${user.home}/niro/logs" maxDepth="2">
<IfFileName glob="niroDesk*.log.gz" />
<IfLastModified age="7d" />
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
<appender name="AsyncFile" type="async" blocking="true" bufferSize="128">
<appender-ref ref="File" />
</appender>
</appenders>
<loggers>
<root level="error">
<appender-ref ref="Console" />
<appender-ref ref="AsyncFile" />
</root>
<logger level="warn" name="org.springframework" additivity="false">
<appender-ref ref="Console" />
<appender-ref ref="AsyncFile" />
</logger>
</loggers>
</configuration>
%d{dd/MM/yyyy HH:mm:ss} %5p %c{1}:%L - %m%n
${user.home}/niro/logs/niroDesk.log
${user.home}/niro/logs/niroDesk.log-%d{yyyy-MM-dd}.log.gz
<appenders>
<appender name="Console" type="Console" target="SYSTEM_OUT">
<layout type="PatternLayout" pattern="${patternlayout}" />
</appender>
<!-- Log su file ogni giorno, e mantenimento degli ultimi 5 files -->
<RollingFile name="File" fileName="${filename}" filePattern="${filenamePattern}" bufferedIO="true" immediateFlush="true" append="true">
<PatternLayout pattern="${patternlayout}" />
<Policies>
<TimeBasedTriggeringPolicy />
</Policies>
<DefaultRolloverStrategy>
<Delete basePath="${user.home}/niro/logs" maxDepth="2">
<IfFileName glob="niroDesk*.log.gz" />
<IfLastModified age="7d" />
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
<appender name="AsyncFile" type="async" blocking="true" bufferSize="128">
<appender-ref ref="File" />
</appender>
</appenders>
<loggers>
<root level="error">
<appender-ref ref="Console" />
<appender-ref ref="AsyncFile" />
</root>
<logger level="warn" name="org.springframework" additivity="false">
<appender-ref ref="Console" />
<appender-ref ref="AsyncFile" />
</logger>
</loggers>
There is a way to solve this issue?
I solved the issue. You sould use ${sys:user.home} instead of ${user.home}.

Log file not being generated/written to

I previously had this working where it would log to a file on my C: drive however trying to get this working into a logs folder using the CATALINA_HOME environment variable doesn't seem to work.
CATALINA_HOME environment variable is set to C:\apache-tomcat\bin and I was hoping to store the logs in C:\apache-tomcat\logs
Have I done something silly with my configuration file?
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Properties>
<Property name="LOG_DIR">${sys:CATALINA_HOME}../logs</Property>
<Property name="ARCHIVE">${LOG_DIR}/archive</Property>
<Property name="PATTERN">%d{dd/MMM/yyyy HH:mm:ss.SSS} [%t] %X{id} %X{username} %-5level %c{36} %l: %msg%n</Property>
</Properties>
<Appenders>
<Console name="CONSOLE" target="SYSTEM_OUT">
<PatternLayout pattern="${PATTERN}" />
</Console>
<RollingFile name="FileAppender" fileName="${LOG_DIR}/application.log"
filePattern="${ARCHIVE}/application.log.%d{yyyy-MM-dd-hh-mm}.gz">
<PatternLayout pattern="${PATTERN}" />
<TimeBasedTriggeringPolicy />
</RollingFile>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="FileAppender" />
<AppenderRef ref="CONSOLE" />
</Root>
<Logger name="uk.co" level="INFO" additivity="false">
<appender-ref ref="FileAppender" />
<appender-ref ref="CONSOLE" />
</Logger>
</Loggers>
<Logger name="org.hibernate" level="INFO" additivity="false">
<appender-ref ref="FileAppender" />
<appender-ref ref="CONSOLE" />
</Logger>
<Logger name="org.apache" level="INFO" additivity="false">
<appender-ref ref="FileAppender" />
<appender-ref ref="CONSOLE" />
</Logger>
<Logger name="org.springframework" level="INFO" additivity="false">
<appender-ref ref="FileAppender" />
<appender-ref ref="CONSOLE" />
</Logger>
</Configuration>
Resolved by changing ${sys:CATALINA_HOME} to ${env:CATALINA_HOME}
Also added a missing / thank to RC

How to configure log4j2's additivity to respect parent's level?

I think this code explains well enough what I'm trying to do
package us.benanderson;
public class MyClass {
private static final Logger LOG = LogManager.getLogger(MyClass.class);
...
// within a method
LOG.debug("only output to appFile");
LOG.error("output to both appFile and errorFile");
This is what I'd guess should be my config
<Loggers>
<Logger name="us.benanderson" level="debug" additivity="true">
<AppenderRef ref="appFile" />
</Logger>
<Root level="error">
<AppenderRef ref="errorFile" />
</Root>
</Loggers>
However, I'm finding that when additivity="true", debug messages are also output to errorFile. When additivity="false" nothing is output to errorFile. Is there any way to do what I'm trying to do?
I think the simplest way to achieve what you want is to put a level directly on the appender-ref. This eliminates the need to have a named logger in your config, simplifying the configuration a little.
Named loggers are still useful if you want to redirect log events for a certain package to a separate appender.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<File name="appFile" fileName="logs/appFile.log" append="true">
<PatternLayout pattern="%-5p %d{ABSOLUTE} [%t] %c - %m%n" />
</File>
<File name="errorFile" fileName="logs/errorFile.log" append="true">
<PatternLayout pattern="%-5p %d{ABSOLUTE} [%t] %c - %m%n" />
</File>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="appFile" level="debug" />
<AppenderRef ref="errorFile" level="error" />
</Root>
</Loggers>
</Configuration>
Threshold filters and filter combinations can be especially useful if you want to do more unusual filtering. For example, if you want to send only INFO and WARN level events to a certain appender, excluding TRACE/DEBUG, and also excluding ERROR and FATAL level events(!), you could do this:
<Console name="only-info-warn">
<PatternLayout pattern="%-5p %c %message %n" />
<Filters>
<!-- First deny error and fatal messages -->
<ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL"/>
<ThresholdFilter level="fatal" onMatch="DENY" onMismatch="NEUTRAL"/>
<!-- Then accept info, warn, error, fatal and deny debug/trace -->
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
</Console>
Use a filter.
Here's a configuration that outputs everything to C:/Logs/Log.log, and additionally outputs debug only to C:/Logs/Debug.log:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="true">
<appender name="general-out" class="org.apache.log4j.FileAppender">
<param name="File" value="C:/Logs/Log.log"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p %c{1} : %m%n"/>
</layout>
</appender>
<appender name="debug-out" class="org.apache.log4j.FileAppender">
<param name="File" value="C:/Logs/Debug.log"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p %c{1} : %m%n"/>
</layout>
<filter class="org.apache.log4j.varia.LevelMatchFilter">
<param name="LevelToMatch" value="debug"/>
<param name="AcceptOnMatch" value="true"/>
</filter>
<filter class="org.apache.log4j.varia.DenyAllFilter"/>
</appender>
<root>
<appender-ref ref="debug-out" />
<appender-ref ref="general-out" />
</root>
</log4j:configuration>
The key part here is this:
<filter class="org.apache.log4j.varia.LevelMatchFilter">
<param name="LevelToMatch" value="debug"/>
<param name="AcceptOnMatch" value="true"/>
</filter>
<filter class="org.apache.log4j.varia.DenyAllFilter"/>
This allows things logged with debug, and then denies anything else.
Source: http://wiki.apache.org/logging-log4j/LogByLevel
Since you are using Log4j 2, you may want to use a ThresholdFilter. Using this filter, your configuration file can be as follows:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<File name="appFile" fileName="logs/appFile.log" append="true">
<PatternLayout pattern="%d %-5p (%c.java:%L).%M - %m%n" />
<ThresholdFilter level="DEBUG" />
</File>
<File name="errorFile" fileName="logs/errorFile.log" append="true">
<PatternLayout pattern="%d %-5p (%c.java:%L).%M - %m%n" />
<ThresholdFilter level="ERROR" />
</File>
</Appenders>
<Loggers>
<Logger name="us.benanderson" level="debug">
<AppenderRef ref="appFile" />
</Logger>
<Root level="error">
<AppenderRef ref="errorFile" />
</Root>
</Loggers>
</Configuration>
Based on your requirements; shouldn't the configuration be as below(with comments):-
<Loggers>
<!-- Do not trickle down 'debug' logs to parent logger using additivity as false; keeping them only in appFile -->
<Logger name="us.benanderson" level="debug" additivity="false">
<AppenderRef ref="appFile" />
</Logger>
<!-- Error messages by default go to both appfile and errorFile -->
<Root level="error">
<AppenderRef ref="errorFile" />
<AppenderRef ref="appFile" />
</Root>
</Loggers>
If you are specifically worried about error logs from "us.benanderson" package; you could try having a separate logger for 'error' level. So the configuration would look like :-
<Loggers>
<Logger name="us.benanderson" level="debug" additivity="false">
<AppenderRef ref="appFile" />
</Logger>
<!-- Not specifying additivity here would default to 'true'; hence the error logs would also be relayed to the root/errorFile -->
<Logger name="us.benanderson" level="error">
<AppenderRef ref="appFile" />
</Logger>
<Root level="error">
<AppenderRef ref="errorFile" />
</Root>
</Loggers>

Loggers to Multiple Appenders at Different Thresholds by Logger

I have two appenders. One is attached to the console and one is to a log file. But that's not really that important. The issue I have is I want everything to go to the file at INFO level. The console is different however. There a bunch of loggers I don't want touching the console at WARN or INFO level because they spray a lot more information than the user needs.
So lets say I have three loggers A, B, C. A, B, and C should all go to the file appenders at INFO level. A should go to the console for INFO, B should go to the console for WARN and C should go to the console for ERROR. What does a log4j config to do this look like?
Something like this should work:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<RollingFile name="RollingFile" fileName="logs/app.log" filePattern="logs/app-%d{MM-dd-yyyy}.log.gz"
ignoreExceptions="false">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<TimeBasedTriggeringPolicy />
</RollingFile>
<Console name="STDOUT" target="SYSTEM_OUT" ignoreExceptions="false">
<PatternLayout pattern="%m%n"/>
</Console>
</Appenders>
<Loggers>
<Logger name="A" level="trace" additivity="false">
<AppenderRef ref="STDOUT" level="info" />
<AppenderRef ref="RollingFile" level="info"/>
</Logger>
<Logger name="B" level="trace" additivity="false">
<AppenderRef ref="STDOUT" level="warn" />
<AppenderRef ref="RollingFile" level="info"/>
</Logger>
<Logger name="C" level="trace" additivity="false">
<AppenderRef ref="STDOUT" level="error" />
<AppenderRef ref="RollingFile" level="info"/>
</Logger>
<Root level="trace">
<AppenderRef ref="STDOUT" level="trace" />
<AppenderRef ref="RollingFile" level="trace"/>
</Root>
</Loggers>

Categories

Resources