Log4j difference between dollar and percent patterns in layout

557 views Asked by At

Answering this this question about log4j2 left me more confused than enlightened.

There seem to be several ways of specifying the current date (with custom format) in log4j2 configuration files:

(Interestingly, the log4j2 docs consistently use $${date:...} in their examples, but doubling the dollar character should escape it and make it a literal dollar character followed by a curly brace and the word "date", a colon, the format, and the closing brace.)

What's the difference between one form or the other, if there is a difference? When should one used over the other?

Is there a difference when used together in a single value? The examples contain the following:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
  <Properties>
    <Property name="baseDir">logs</Property>
  </Properties>
  <Appenders>
    <!-- HERE: -->
    <RollingFile name="RollingFile" fileName="${baseDir}/app.log"
          filePattern="${baseDir}/$${date:yyyy-MM}/app-%d{yyyy-MM-dd}.log.gz">
      <PatternLayout pattern="%d %p %c{1.} [%t] %m%n" />
      <CronTriggeringPolicy schedule="0 0 0 * * ?"/>
      <DefaultRolloverStrategy>
        <Delete basePath="${baseDir}" maxDepth="2">
          <IfFileName glob="*/app-*.log.gz" />
          <IfLastModified age="P60D" />
        </Delete>
      </DefaultRolloverStrategy>
    </RollingFile>
  </Appenders>
  <Loggers>
    <Root level="error">
      <AppenderRef ref="RollingFile"/>
    </Root>
  </Loggers>
</Configuration>
  1. Why the double dollar in front of $${date:yyyy-MM}, but only a single dollar with ${baseDir}?
  2. Why ${date:yyyy-MM} and %d{MM-dd-yyyy} and not %d{yyyy-MM} or ${date:MM-dd-yyyy}?

Who can clear the confusion?

1

There are 1 answers

0
Piotr P. Karwasz On BEST ANSWER

Pattern placeholders like %d{...} can be used in:

  • the pattern property of a pattern layout (cf. documentation) and by extension in the pattern resolver of a JSON Template Layout (cf. documentation). These patterns are replaced with a property of the LogEvent being logger,
  • the filePattern property of a rolling file appender (just %i and %d). These patterns are replaced with the index and date pattern of the archived log file being created.

Lookup placeholders ${type:key} on the other hand can be used everywhere in your configuration file and are replaced eagerly when the file is read (cf. lookups). Therefore the fileName property of your rolling file appender will have logs/app.log as value.

There is however a second application for lookups: some properties, including all those that accept % patterns, accept ${...} lookups that will be evaluated at a later time. In order to prevent the evaluation of those lookups at configuration time, you need to escape $ as $$.

That is why the ${baseDir}/$${date:yyyy-MM}/app-%d{yyyy-MM-dd}.log.gz string in your configuration file is:

  1. evaluated as logs/${date:yyyy-MM}/app-%{yyyy-MM-dd}.log.gz at configuration time,
  2. further evaluated as logs/2022-04/app-2022-04-16.log.gz if a rollover occurs today.

If you were to use ${date:yyyy-MM} instead of $${date:yyyy-MM} all log files would be (until reconfiguration occurs) in the logs/2022-04 folder.

The difference between $${date:yyyy-MM-dd} and %d{yyyy-MM-dd} is specific to the rolling file appender: the appender needs to know how often should a rollover occur. It does so by analyzing the %d{...} pattern. That is why in your configuration rollover occurs daily (%d{yyyy-MM-dd}) and not monthly ($${date:yyyy-MM}).

Another difference between those two is in the date they use: $${date:...} uses the current date, while %d{...} uses the date of the previous rollover. These might be off by one rolling period.