Search code examples
log4jlogbacklog4j2

Right-justify compound/composite expression in Log4j pattern layout?


I want my log to look like this:

      ClassName.methodName() - just did something
ClassName.methodNameLonger() - just did something else

I know you can right-justify just the method name with %-17M but I end up with this:

ClassName.methodName      () - just did something
ClassName.methodNameLonger() - just did something else

Is there a way to justify multiple elements as a single block such that the padding appears only at the very beginning?

I'm not sure it's possible looking at the reference: https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html

Further details

If I try to right-justify the class name, I get:

ClassName      .      methodName() - just did something
ClassName      .methodNameLonger() - just did something else
ClassNameLonger.methodNameLonger() - just did something else

which isn't terrible, but still it's not able to treat multiple fields (including the literal text ()) as a contiguous unit to be justified.


Solution

  • As mentioned in another answer, Log4j does not support this.


    However, logback does.

    <configuration>
    
      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender" scan="true">
        <encoder>
          <pattern>%-5level %20(%logger{0}.%method\(\)) - %msg%n</pattern>
        </encoder>
      </appender>
    
      <root level="debug">
        <appender-ref ref="STDOUT" />
      </root>
    
    </configuration>
    

    Full documentation here:

    http://logback.qos.ch/manual/layouts.html#Parentheses

    Parentheses are special

    In logback, parentheses within the pattern string are treated as grouping tokens. Thus, it is possible to group a sub-pattern and apply formatting directives on that sub-pattern. As of version 0.9.27, logback supports composite conversion words such as %replace which can transform sub-patterns.

    For example, the pattern

    %-30(%d{HH:mm:ss.SSS} [%thread]) %-5level %logger{32} - %msg%n
    

    will group the output generated by the sub-pattern %d{HH:mm:ss.SSS} [%thread] so that it is right-padded if less than 30 characters.

    If without the grouping the output was

    13:09:30 [main] DEBUG c.q.logback.demo.ContextListener - Classload hashcode is 13995234
    13:09:30 [main] DEBUG c.q.logback.demo.ContextListener - Initializing for ServletContext
    13:09:30 [main] DEBUG c.q.logback.demo.ContextListener - Trying platform Mbean server
    13:09:30 [pool-1-thread-1] INFO  ch.qos.logback.demo.LoggingTask - Howdydy-diddly-ho - 0
    13:09:38 [btpool0-7] INFO c.q.l.demo.lottery.LotteryAction - Number: 50 was tried.
    13:09:40 [btpool0-7] INFO c.q.l.d.prime.NumberCruncherImpl - Beginning to factor.
    13:09:40 [btpool0-7] DEBUG c.q.l.d.prime.NumberCruncherImpl - Trying 2 as a factor.
    13:09:40 [btpool0-7] INFO c.q.l.d.prime.NumberCruncherImpl - Found factor 2
    

    with the "%-30()" grouping it would be

    13:09:30 [main]            DEBUG c.q.logback.demo.ContextListener - Classload hashcode is 13995234
    13:09:30 [main]            DEBUG c.q.logback.demo.ContextListener - Initializing for ServletContext
    13:09:30 [main]            DEBUG c.q.logback.demo.ContextListener - Trying platform Mbean server
    13:09:30 [pool-1-thread-1] INFO  ch.qos.logback.demo.LoggingTask - Howdydy-diddly-ho - 0
    13:09:38 [btpool0-7]       INFO  c.q.l.demo.lottery.LotteryAction - Number: 50 was tried.
    13:09:40 [btpool0-7]       INFO  c.q.l.d.prime.NumberCruncherImpl - Beginning to factor.
    13:09:40 [btpool0-7]       DEBUG c.q.l.d.prime.NumberCruncherImpl - Trying 2 as a factor.
    13:09:40 [btpool0-7]       INFO  c.q.l.d.prime.NumberCruncherImpl - Found factor 2
    

    The latter form is more comfortable to read.

    If you need to treat the parenthesis character as a literal, it needs to be escaped by preceding each parenthesis with a backslash. As in, \(%d{HH:mm:ss.SSS} [%thread]\).