Log4j 2 : can't use the ContextMapLookup in RollingFileAppender fileName and filePattern - java

I am working on logging with log4j 2.0.2. I am trying to use the ContextMapLookup into the fileName and filePattern attribute of a RollingFileAppender but I can't make it work.
Here is my (simplified) Map initialization in a REST facade :
#GET
public Response logSomething(#QueryParam("param") String param) {
ThreadContext.put("someName", "default");
LOGGER.info("Param from query: {}", param);
ThreadContext.clearMap();
return Response.ok().build();
}
And here is my (simplified to) configuration file :
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %5p %c{1}:%L - %m%n" />
</Console>
<RollingFile name="Rolling"
fileName="logs/${ctx:someName}-webapps-metrics.log"
filePattern="logs/archives/${ctx:someName}-webapps-metrics-%i.log" >
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %m%n"/>
<SizeBasedTriggeringPolicy size="5 KB"/>
</RollingFile>
</Appenders>
<Loggers>
<!-- My Logger using rollingFile -->
<Logger name="com.ipanematech.rest.MyRESTFacade" level="info" additivity="false">
<AppenderRef ref="Rolling" />
</Logger>
<Root level="warn">
<AppenderRef ref="STDOUT" />
</Root>
</Loggers>
</Configuration>
A file named "{ctx" is created in the directory. It seems that the expression to get the context does not work in these attributes.
I tried to use the context in the PatternLayout of my appender and it worked well.
In fileName and filePattern, I tried different syntaxes but not one worked:
${ctx:someName} (like in the example above)
$${ctx:someName}
%X{someName}

The RoutingAppender does what you want. See the log4j2 FAQ page for a detailed example.

Related

log4j2 logger config level does not override root logger level

According to log4j documentation, if I define a logger config for package com.a.b.c with level ERROR with root logger level set to DEBUG, only ERROR logs should come from classes in com.a.b.c while other classes should print DEBUG logs. Therefore I have the below log4j2-test.xml.
However, in my case INFO level logs from classes in com.a.b.c are still being printed. Did I misunderstand anything? What should I do to make classes in com.a.b.c print ERROR logs while all other classes print INFO logs?
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="debug" name="PropertiesConfig" packages="org.apache.logging.log4j.test">
<Properties>
<Property name="basePath">target/</Property>
</Properties>
<ThresholdFilter level="trace"/>
<Appenders>
<Console name="consoleLogger" target="SYSTEM_OUT">
<PatternLayout pattern="%d{dd-MM-yyyy HH:mm:ss.SSS} %style{[%t]}{magenta} %highlight{%-5level}{TRACE=cyan, DEBUG=green, INFO=yellow, WARN=blue, ERROR=red} [%-60.60c] : %m%n" />
</Console>
<File name="fileLogger" fileName="${basePath}app.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %level [%t] [%c] [%M] [%l] : %msg%n" />
</File>
</Appenders>
<Loggers>
<Root level="INFO" >
<AppenderRef ref="consoleLogger" />
<AppenderRef ref="fileLogger" />
</Root>
<Logger name="com.a.b.c" level="ERROR" additivity="false">
<AppenderRef ref="consoleLogger" />
<AppenderRef ref="fileLogger" />
</Logger>
</Loggers>
</Configuration>
I figured this out. The class in question is (weirdly) not using its own class name when getting the logger. Typically it is LoggerFactory.getLogger(com.a.b.c) but in my case the class is doing LoggerFactory.getLogger(java.io.Console), thus our logger config <Logger name="com.a.b.c" level="ERROR" additivity="false"> will not apply to logs coming from this class. I had to add a logger config for the class java.io.Console.

Migrating from log4j 1.2 to log4j2

I am in the process of migrating my application from log4j 1.2 to log4j2-2.8.1 version.
Following is the existing 1.x configuration in log4j.properties file.
log4j.appender.JSERRORFILE=org.apache.log4j.DailyRollingFileAppender
log4j.appender.JSERRORFILE.File=${log4j.loglocation}/jserror.log
log4j.appender.JSERRORFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.JSERRORFILE.layout.ConversionPattern=%d %-5p %c - %m%n
log4j.logger.com.app.JavascriptLogger=ERROR,JSERRORFILE
log4j.additivity.com.app.JavascriptLogger=false
Converted this to equivalent xml configuration log4j2.xml :
<RollingFile name="JSERRORFILE" fileName="${log-path}/jserror.log">
<PatternLayout pattern="%d %-5p %c - %m%n" />
</RollingFile>
<Logger name="com.app.JavascriptLogger" level="ERROR" additivity="false">
<AppenderRef ref="JSERRORFILE"/>
</Logger>
After conversion,I keep getting the following error :
org.apache.logging.log4j.core.config.ConfigurationException: Arguments given for element RollingFile are invalid
Any help would be appreciated.
You need to tell the RollingFile appender when to rollover (trigger policy) and what the result of a rollover should look like.
If you want to rollover at some regular interval (TimeBasedTriggeringPolicy or CronTriggeringPolicy) you need to specify a filePattern containing a SimpleDateFormat-like string. If you want to rollover to prevent large files (SizeBasedTriggeringPolicy), you need to specify a filePattern containing %i.
The filePattern is the relative or absolute path of the location you want the old (rolled over) file to be moved to.
Example:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<CronTriggeringPolicy schedule="0 0 0 * * ?"/>
<SizeBasedTriggeringPolicy size="250 MB"/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
The cron expression above fires once a day.
For details and more examples see the RollingFile appender section of the user manual.

log4j2 logging to console only

I have a maven web project which requires logging.
I decided to use log4j2 for that purpose and added the required entries in the pom.xml file
Then I created the log4j2.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<RollingFile name="RollingFile" fileName="${logs.path}/text.log"
filePattern="${logs.path}/%d{YYYYMMdd}-text.%i.log">
<PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n" />
<Policies>
<SizeBasedTriggeringPolicy size="100 MB" />
</Policies>
<DefaultRolloverStrategy max="20" />
</RollingFile>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} %-5p %c{1}:%L - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Logger name="root" level="info" additivity="false">
<appender-ref ref="RollingFile" level="info" />
<appender-ref ref="Console" level="info" />
</Logger>
<Root level="info" additivity="false">
<AppenderRef ref="RollingFile" />
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
I'm starting tomcat with -Dlogs.path="C:\mylogs", where C:\mylogs exists and has public read/write access.
The console logger is working fine, I can see the correct output in my console, the issue is that the file isn't being created, so I have no logfile, everything gets logged to catalina.out only, and the tomcat startup logs don't show errors for log4j.
What am I missing? is there some additional configuration I need to do in order to log to file?
I went through the documentation. You must refer to system properties with sys:, and it seems that tomcat properties are seen as system properties, so I replaced ${logs.path} with ${sys:logs.path} and it worked.
To create a log file with the log4j2 config you first need to define your appender. Here's an example:
<RollingFile name="MGMT"
fileName="${logdir}/mgmt.log"
filePattern="${logdir}/mgmt.%d{yyyy-MM-dd}.log">
<PatternLayout pattern="${layout}"/>
<CronTriggeringPolicy schedule="0 0 0 * * ?"/>
<DefaultRolloverStrategy>
<Delete basePath="${logdir}" maxDepth="1">
<IfFileName glob="mgmt.*.log" />
<IfAccumulatedFileCount exceeds="10" />
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
Afterwards you just need to define a logger that will use it:
<Logger name="the package or name that is displayed in the log line"
level="ALL"
additivity="false">
<AppenderRef ref="MGMT"/>
</Logger>
If you have a log that has com.company.test as package set that package as name for the logger. It's important that they match.
The field additivity will define if you want to pass the catched log to its parent ( true ) or just let this logger handle it ( false )
EDIT:
your config file might need this:
<Configuration status="info">
<Properties>
<Property name="logdir">${sys:catalina.base}/logs</Property>
<Property name="layout">%d [%t] %-5p %c- %m%n</Property>
</Properties>
<Appenders>
If you don't want to use this you have to define the path static like <RollingFile name="MGMT"
fileName="C:\path\file.log"

log4j 2: log file being created, but not being written to

I am using log4j 2. I am trying to determine why my log file is not being written to, but my console is. This is the output I have to the console:
2016-04-25 12:26:07,142 INFO [main] helperCode.LogPlus (LogPlus.java:50) -
----------------------------------------------------------------------------
------------ The test is starting now at 2016-04-25-12-26-07-135 -----------
----------------------------------------------------------------------------
2016-04-25 12:26:07,151 INFO [main] helperCode.LogPlus (LogPlus.java:50) -
--------------------------------------------------------------------------
------------ METHOD loginBadPasswordGoodUsername_3 starting: ------------
--------------------------------------------------------------------------
The issues I've considered already:
The output is not repeating itself, so the log output being redirected is not an issue.
I am NOT using java.util.logging.Logger anywhere in my project;
The output of the log file is formatted in log4j style rather than JUL style, so I know that JUL is not overriding it;
Here is my XML config file:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<File name="FileLogger" fileName="${sys:logFilePath}" append="false">
<PatternLayout pattern="%d %t %-5p %c{2} - %m%n" />
</File>
<Async name="Async">
<AppenderRef ref="FileLogger" />
</Async>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n" />
</Console>
</Appenders>
<Loggers>
<Logger name="automationFramework" level="trace">
<AppenderRef ref="FileLogger" />
</Logger>
<Root level="trace">
<AppenderRef ref="STDOUT" />
</Root>
</Loggers>
</Configuration>
I am directing the output to the file located at the system variable "logFilePath".
I am not sure what is going on, and the config files shown on answers for similar questions are not in XML format, so I am not sure how to commute the config file code to XML.
In your case as mentioned in the comment you do not have the package called applicatiionFramework. So change the name attribute by the package name of the classes where you want to record log events.
<Logger name="your package" level="trace">
<AppenderRef ref="FileLogger" />
<Root level="trace">
<AppenderRef ref="STDOUT" />
</Root>
</Logger>
For more information visit log4j-manual-configuration
Glad the other answer helped. Do you need the named logger though? Why not just have the root logger? Also, you declared an Async Appender but are not using it. Is that on purpose? This is what I would suggest:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<File name="FileLogger" fileName="${sys:logFilePath}" append="false">
<PatternLayout pattern="%d %t %-5p %c{2} - %m%n" />
</File>
<Async name="Async">
<AppenderRef ref="FileLogger" />
</Async>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n" />
</Console>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="STDOUT" level="info" />
<AppenderRef ref="Async" />
</Root>
</Loggers>
</Configuration>
Note that you can also specify a level on the AppenderRef. I made the Console Appender level INFO to illustrate this point.
If you want the log to show location information and use Async loggers or appenders then you need to specify includeLocation="true" on the Async Appender.
For the complete noob, like myself, this line in Unknown's answer above:
<Logger name="your package" level="trace">
is the key. When it says "your package" it really means the "package foo.bar" you declared at the top of the .java file where you created the Logger, not the class name you passed to create the Logger, like:
LOGGER = LogManager.getLogger(MyClass.class.getName());
It took me a ridiculous amount of time today to get my log4j2 output going to a file, playing with various "name" values until the light bulb went on.

log4j2 - how to change file dynamically?

I've implemented async logging with log4j 2, but now I need to change log filename every hour, eg 2015-11-19/log-12.00.log, 2015-11-19/log-13.00, etc. (Soulutions I've found didn't work, may be I did something wrong).
I have following log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- Don't forget to set system property
-DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
to make all loggers asynchronous. -->
<Configuration status="WARN">
<Appenders>
<!-- Async Loggers will auto-flush in batches, so switch off immediateFlush. -->
<RandomAccessFile name="RandomAccessFile" fileName="async.log" immediateFlush="false" append="true">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m %ex%n</Pattern>
</PatternLayout>
</RandomAccessFile>
</Appenders>
<Loggers>
<Root level="info" includeLocation="false">
<AppenderRef ref="RandomAccessFile"/>
</Root>
</Loggers>
</Configuration>
How to achive this?
You should have a look at TimeBasedTriggeringPolicy. Basically it causes a rollover once the date/time pattern no longer applies to the active file.
Have't tried this but this should work for you.
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="WARN" >
<appenders>
<Async name="Async">
<AppenderRef ref="logfile" />
</Async>
<RollingRandomAccessFile name="logfile" fileName="async.log" filePattern="log-%d{HH}.00.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m %ex%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
</Policies>
<DefaultRolloverStrategy max="24"/>
</RollingRandomAccessFile>
</appenders>
<loggers>
<root level="INFO" includeLocation="false">
<AppenderRef ref="Async"/>
</root>
</loggers>
</configuration>
The TimeBasedTriggeringPolicy interval attribute controls how often a rollover should occur based on the most specific time unit in the date pattern. In you case it is hours that is %d{HH} from file pattern.

Categories