9

I'm wondering if it is possible in Log4j 2.0 library to pad more conversion specifiers concatenated together.

For example, this pattern

%d{HH:mm:ss,SSS} %-5p [%-10t] %-22c - %m%n

produces something like

12.25.34,788 INFO  [SomeThread] my.path.to.Class       - First logged message
12.25.34,789 FATAL [Thread2   ] other.path.SecondClass - Second logged message
12.25.34.790 WARN  [Scheduler ] my.other.path.Class    - Another message

Now imagine I want to pad not only the conversion specifiers, but also whole parts of the pattern. In this case, for example, I want to pad [%-10t] %-22c.

12.25.34,788 INFO  [SomeThread] my.path.to.Class    - First logged message
12.25.34,789 FATAL [Thread2] other.path.SecondClass - Second logged message
12.25.34.790 WARN  [Scheduler] my.other.path.Class  - Another message

The notation could be something like

%d{HH:mm:ss,SSS} %-5p %-32{[%t] %c} - %m%n

(note %-35{...} - I want to pad whole content of this conversion specifier, just as one item)

I found this similar question, but there is no answer how to pad custom parts of the pattern, only answer with sample class extending PatternLayout to generate a string in format Class:method.


Additionally, I want to add padding between the two elements, as follows ([%t] is left-justified, %c is right-justified):

12.25.34,788 INFO  [SomeThread]    my.path.to.Class - First logged message
12.25.34,789 FATAL [Thread2] other.path.SecondClass - Second logged message
12.25.34.790 WARN  [Scheduler]  my.other.path.Class - Another message

It seems like the log4j library does not support it. So my question is: How can I achieve it? Possibly you can write a sample code. I believe it will help someone else, too.

Community
  • 1
  • 1
jjurm
  • 501
  • 6
  • 11
  • Even if it doesn't really answer your question, Logback can do that, using the `%-30([%t] %c)` pattern. In case you are ready to switch from Log4j2 to Logback... See http://logback.qos.ch/manual/layouts.html#Parentheses. Since Log4j2 seems to want to be as powerful as Logback, maybe it will also handle it in a future release ;) – xav Jul 02 '14 at 19:53

2 Answers2

6

I created a custom converter that may work for what you are looking to do. It allows you to group patterns within a pattern, and treat the groups as if they are a single entity. For example, the notation

%d{HH:mm:ss,SSS} %-5p %-32grp{[%t] %c} - %m%n

would produce output similar to your first request:

12.25.34,788 INFO  [SomeThread] my.path.to.Class    - First logged message
12.25.34,789 FATAL [Thread2] other.path.SecondClass - Second logged message
12.25.34.790 WARN  [Scheduler] my.other.path.Class  - Another message

Unfortunately there doesn't seem to be any way for the converter to know how "long" it is supposed to be, so it can't inherently handle your second request for the output to be both left and right justified. However, you can modify your pattern to mimic the behavior with something like:

%d{HH:mm:ss,SSS} %-5p %-16grp{[%t]} %16grp{%c} - %m%n

Here is the converter I wrote:

@Plugin(name="GroupingPatternConverter", category="Converter")
@ConverterKeys({"grp"})
public class GroupingPatternConverter extends LogEventPatternConverter {

    private final String pattern;

    public static GroupingPatternConverter newInstance(String[] options) {
        return new GroupingPatternConverter("grp", "grp", options);
    }

    private GroupingPatternConverter(String name, String style, String[] options) {
        super(name, style);
        if (options != null && options.length > 0) {
            this.pattern = options[0];
        } else {
            this.pattern = null;
        }
    }

    @Override
    public void format(LogEvent event, StringBuilder toAppendTo) {
        if (this.pattern == null) {
            return;
        }

        PatternParser parser = new PatternParser(null, "Converter", LogEventPatternConverter.class);
        List<PatternFormatter> formatters = parser.parse(this.pattern);

        StringBuilder groupBuilder = new StringBuilder();
        for (PatternFormatter formatter : formatters) {
            formatter.format(event, groupBuilder);
        }

        toAppendTo.append(groupBuilder.toString());
    }
}
littlezz
  • 240
  • 2
  • 5
  • Thank you very much, it looks great, but I can't get it working, the same issue as described [here](http://stackoverflow.com/questions/16243084/failure-to-add-a-custom-converter-to-log4j). I have everything set as mentioned there, but can't use custom Plugin/Converter. Maybe some supernatural force don't want me to run it :D – jjurm Jul 29 '14 at 11:18
  • jjurm, see Remko's answer to my question here: http://stackoverflow.com/questions/24918810/log4j2-configuration-will-not-load-custom-pattern-converter I can confirm that packaging the custom converter using Maven will work. However, if you are not familiar with Maven it looks like the "packages" attribute will work again in version 2.0.1. Good luck! – littlezz Jul 30 '14 at 13:18
  • Thanks, as for new, today I already saw the answer and because I don't want to wait for the next release, I'm actually setting up Maven :) I will then try your converter and let you know – jjurm Jul 30 '14 at 14:07
  • I still haven't tried your (or any other) plugin beacuse of some problems with the annotation processing. I would be grateful if you would mind helping me here: http://stackoverflow.com/questions/25065580/log4j2-custom-plugins-annotation-processing-with-maven-assembly-plugin – jjurm Jul 31 '14 at 17:58
  • Now (again with your help) I run my program and the log4j library succesfully loaded the plugin. However, if I use `%grp` in the configuration, my program stops responding immediately after running it, without printing any output to console. The only one thing I can do is to forcibly kill the process. Then I removed `%-50grp{...}` from the configuration and everything worked. So I assume the problem is in your code. Now I do not have time to do anything with it, but later I will try to figure out the problem. – jjurm Aug 01 '14 at 19:57
3

As of RC2, Log4j2 does not support this. You can raise a feature request on the Log4j2 Jira issue tracker. A patch would be great!

Meanwhile, if you want to align the start of the actual message, you could have a config where the minimum (padding) value is equal to the maximum (truncate) value for both the thread name and the logger name. I realize this is not ideal but this can be achieved with just configuration.

Remko Popma
  • 35,130
  • 11
  • 92
  • 114
  • Thanks for your answer, but I am not ready to accept it. I am sure it would be possible with some custom classes extending PatternLayout, but I am not very skilled in the log4j yet to do it myself. – jjurm Jul 02 '14 at 07:11
  • That is fine. I'm sure you will be able to develop the skills if you invest the time. :-) If you currently don't want to or can't invest the time, your best bet is to raise a feature request to the log4j team. – Remko Popma Jul 02 '14 at 10:58
  • @RemkoPopma Good idea to raise a feature request. As I said above in my comment, Logback already handles it. [ PS: I've just made you go for 2,000 reputation points with my +1 ;) ] – xav Jul 02 '14 at 19:55