Using the start timestamp in a RollingFile - log4j2

I have the following RollingFileAppender setup:
<RollingFile name="RollingFile">
<FileName>${LOG_DIR}system.log</FileName>
<FilePattern>${LOG_DIR}system%d{yyyy-MM-dd HH.mm.ss}.log.zip</FilePattern>
<JsonLayout compact="true" eventEol="true" />
<Policies>
<OnStartupTriggeringPolicy />
<CronTriggeringPolicy schedule="0 0 0 * * ?"/>
</Policies>
<!-- roll over strategy, with unlimited files created -->
<DefaultRolloverStrategy fileIndex="nomax" />
</RollingFile>
It does nearly exactly what i want (new log file at midnight or on startup/restart), but unfortunately the timestamps that get assigned to the rolled over log files are sometimes simply incorrect. So for example:
system.log // current log, started at 2022-08-10 at midnight
system2022-08-09 00.00.00.log.zip // started at 2022-08-09 at midnight, so this is fine
system2022-08-08 00.00.00.log.zip // started at 2022-08-08 10.09 am, so this is not fine
system2022-08-08 10.04.57.log.zip // started at 2022-08-08 at 8.55 am, so this is not fine
As you can see system2022-08-08 00.00.00.log.zip is using a completely wrong timestamp and system2022-08-08 10.04.57.log.zip is using the timestamp when the log ended.
I'm not sure what i'm doing wrong here. Appreciate any suggestions on how to properly combine OnStartupTriggeringPolicy and CronTriggeringPolicy to achieve my goal here.

Seems like this behavior is unfortunately a bug in log4j2, and an old one. See my comment here: https://issues.apache.org/jira/browse/LOG4J2-2148
I also posted a solution for log4j2 2.18.0 in there, which will atleast does what i desire - there are still several things wrong in log4j2 itself though.

Related

multiple access to the debug.log file creating unordered files

I am using log4j2.xml for logging. 3 instances of my application are simultaneously writing to the debug.log file (with Rollingfile appender and CronTriggeringPolicy). But debug.log files are not getting generated sequentially and some sequences and logs are missing during multiple access. If I test with single access, it is working as expected.
<Appenders>
<RollingFile name="application" fileName="${log-path}/debug.log"
filePattern="${log-path}/debug.log.%i">
<PatternLayout>
<pattern>[%d{yyyy-MM-dd HH:mm:ss,SSS}]%5p [%t] (%F:%M:%L) - %m%n</pattern>
</PatternLayout>
<Policies>
<CronTriggeringPolicy schedule="0 0/2 * 1/1 * ? *" />
</Policies>
<DefaultRolloverStrategy fileindex="min" min="1" max="5" />
</RollingFile>
That's expected behavior. You could (artificially) get serialized lines, if you separate your log file by thread (the %t you are printing in your pattern).
The lines written with the same %t value, will be in the correct order.
On the other hand, if you are serious about logging properly, you might want to consider using LOG4J's MDC.
When 3 instances of your application are running simultaneously and logging in the same file, you can not expect sequential logs.
Reason is when 3 instances are running, it means 3 separate processes are running and these 3 separate processes are trying to write to a single file.
Writing to a file involves locking the file resource, write and then release the lock. So, sometimes, 1 process will get the lock and write it. Meanwhile, other 2 process will keep waiting and if there buffer will get filled, some logs will get missed and this cycle will keep on going for other processes of the application.
For such situations, you should use some log daemon like rsyslog using log4j2 SyslogAppender or easy solution is to log in separate files by each parallel instance of the application.

Log4j2 RollingFile with daily rotation

Using Log4j2 2.8, is there a way to have my logs rotate daily but so that the current file has a constant name?
Example:
my.log <-- current day (2017-02-13)
my-2017-02-12.log <-- last log
my-2017-02-11.log <-- second to last log
I tried the following configuration without success:
<RollingFile name="RollingFileMain" fileName="my.log"
filePattern="my-%d{yyyy-MM-dd}-%i.log">
<PatternLayout>
<Pattern>%level{length=1} %d{yyyy-MM-dd HH:mm:ss} %c{-3} (%F:%L) %m%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy/>
</Policies>
<DefaultRolloverStrategy max="2"/>
</RollingFile>
Additionally, I get the following exception when I launch my application for the first time on a given day:
2017-02-14 09:28:38,334 main ERROR An exception occurred processing Appender RollingFileMain java.lang.NullPointerException
at org.apache.logging.log4j.core.appender.rolling.AbstractRolloverStrategy.getEligibleFiles(AbstractRolloverStrategy.java:107)
at org.apache.logging.log4j.core.appender.rolling.AbstractRolloverStrategy.getEligibleFiles(AbstractRolloverStrategy.java:96)
at org.apache.logging.log4j.core.appender.rolling.AbstractRolloverStrategy.getEligibleFiles(AbstractRolloverStrategy.java:89)
at org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy.purgeAscending(DefaultRolloverStrategy.java:212)
at org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy.purge(DefaultRolloverStrategy.java:199)
at org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy.rollover(DefaultRolloverStrategy.java:326)
at org.apache.logging.log4j.core.appender.rolling.RollingFileManager.rollover(RollingFileManager.java:310)
at org.apache.logging.log4j.core.appender.rolling.RollingFileManager.rollover(RollingFileManager.java:227)
at org.apache.logging.log4j.core.appender.rolling.RollingFileManager.checkRollover(RollingFileManager.java:207)
at org.apache.logging.log4j.core.appender.RollingFileAppender.append(RollingFileAppender.java:267)
at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:156)
at org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:129)
at org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:120)
at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:84)
at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:448)
at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:433)
at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:417)
at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:403)
at org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy.log(AwaitCompletionReliabilityStrategy.java:63)
at org.apache.logging.log4j.core.Logger.logMessage(Logger.java:146)
at org.apache.logging.log4j.spi.AbstractLogger.logMessageSafely(AbstractLogger.java:2091)
at org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:1988)
at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:1960)
at org.apache.logging.log4j.spi.AbstractLogger.info(AbstractLogger.java:1297)
at my.package.MainKt.main(Main.kt:48)
Please change your filepattern to filePattern="my-%d{yyyy-MM-dd}.log":
The %i is only useful when you use the SizeBasedTriggeringPolicy. If you only have a TimeBasedTriggeringPolicy, Log4j gets confused by the %i...
The issue seems to be a combination of #Remko Popma's answer and a bug in Log4j2 2.8. After applying the filePattern="my-%d{yyyy-MM-dd}.log" and downgrading to version 2.7, everything works as expected.
I submitted an issue regarding the crash here: https://issues.apache.org/jira/browse/LOG4J2-1815

How to use org.perf4j.log4j.AsyncCoalescingStatisticsAppender in log4j2?

Below is the sample used in log4j 1.x. I am not getting any example to convert the same in log4j2.
<appender name="CoalescingStatisticsAppender"
class="org.perf4j.log4j.AsyncCoalescingStatisticsAppender">
<!--
The TimeSlice option is used to determine the time window for which
all received StopWatch logs are aggregated to create a single
GroupedTimingStatistics log. Here we set it to 10 seconds, overriding
the default of 30000 ms
-->
<param name="TimeSlice" value="30000" />
<appender-ref ref="perf4jFileAppender" />
</appender>
The Appender won't work as is in Log4j 2. It would have to be rewritten.
You may be interested to know that Log4j 2 supports nanoTime timestamps in PatternLayout. This, in combination with the low overhead Async Loggers, allow you to use Log4j as a rough profiling tool.

Disable freemarker logs from logs4j

Similar question but i'm using log4j2.
I need a way to disable All logs from freemarker, in their documentation they say we can do it by calling Logger.selectLoggerLibrary(Logger.LIBRARY_NONE) but they say
selectLoggerLibrary must be called early, before FreeMarker could log anything, or else it will not have (consistent) effect.
Where do I call this in a struts2 application? (I tried calling it in prepare() method in my action class but its not working.) or is there any other way to disable the logs?
Question is, why do you need to disable it like that?
You shouldn't need that, so I guess that's where the real problem lies. Is there some kind of malfunction? Because if there isn't, why not just set the freemarker logger category to be ignored in your logger configuration? That's the normal way of doing this, FreeMarker or not.
Anyway, in 2.3.22 (release expected in early 2015) you can use the -Dorg.freemarker.loggerLibrary=none where you start the JVM (that is, you set the org.freemarker.loggerLibrary system property). Otherwise, if you could call that method in a ServletContextListener that's certainly early enough.
Update:
Reacting to the comments... in most applications you will have 3rd party libraries that use various logging "frameworks", like SLF4J, commons-logging, JUL, Log4j, Log4j2. Thus you have to ensure that all these get redirected into the same logger library, which is certainly Log4j2 in your case. I suspect that wasn't properly done in your case, so now multiple logger libraries log to the console, each with its own configuration settings.
FreeMarker 2.3.x uses Log4j 1.x if it detects that org.apache.log4j.Logger is present. Other logger libraries that it also can detect and use (Log4j2 is not amongst them) have lower priority. (FreeMarker 2.4.x will always use SLF4J if it's present.) Thus, if you add org.apache.logging.log4j:log4j-1.2-api to your dependencies, then FM will use org.apache.log4j.Logger, and so log4j-1.2.-api will redirect the FM log messages to Log4j2. That worked for me, with this Log4j2 configuration:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console" />
</Root>
<Logger name="freemarker" level="off">
<AppenderRef ref="Console" />
</Logger>
</Loggers>
</Configuration>
This came up as the first search result for "disable freemarker logging" which I searched for because I got double error logs for template errors, one from within the Freemarker library and one from my own code catching the same exception and logging it. The solution to this is simple and different from the answers already given: call setLogTemplateExceptions(false) on the Freemarker Configuration. In full:
Configuration configuration = new Configuration(Configuration.VERSION_2_3_31);
configuration.setLogTemplateExceptions(false);
The default behavior of logging the exception even though it propagates out of the Freemarker library is mentioned as a quirk on the Freemarker Logging documentation.
Use this statement:
freemarker.log.Logger.selectLoggerLibrary(freemarker.log.Logger.LIBRARY_NONE);

Java Log4J 2 - Configurate own appender in xml

I tried to configurate Log4J2 per xml-file. I want to register an own appender (which shows an speciale panel if errors happend).
With logback it was no problem - till I wanted to use it in my webStart-Project. So I hope it works with log4j2.
With my own configuration I get an CLASS_NOT_FOUND output.
I am looking the log4j2 xml-shema for:
<appender name="myAppender" class="mypackage.myappender">
I tried everything like
<Appenders>
<Myappender name="MyAppender" class="mypackage.myappender">
</Myappender>
</Appenders>
I hope someone can help me.
P.S.: sorry for my bad english
You would need to implement your appender as a log4j2 plugin.
This is not that difficult (just look at some of the existing appenders to see which annotations to use and methods to implement).
You also need to help log4j2 find your plugin by specifying the appender's package in the configuration:
<Configuration packages="com.mycomp.mylog4j2appenderpackage">
<Appenders>
<MyAppender name="MyAppender" />
</Appenders>
...
</Configuration>

Resources