What is the default MessageFactory for Log4J

This thread is already about one year old, but maybe I can still help some guys, because I just had the same problem and found out a way how to set your own default MessageFactory. It's a bit tricky, maybe someone else knows a better way without creating so much classes. But for me it works:

  1. Create your own MessageFactory (extend from AbstractMessageFactory or just use the MessageFactory interface)
  2. Create a new LoggerContext (extend from the LoggerContext class or use the LoggerContext interface
    • Override newInstance(LoggerContext, String, MessageFactory) and return your previously defined MessageFactory if argument messageFactory is null
  3. Create a new ContextSelector (extend from ClassLoaderContextSelector or just use the ContextSelector interface).
    • Override the method createContext(String, URI) and return a new instance of your previously defined LoggerContext
  4. Create a file log4j.component.properties in your classpath and set the property Log4jContextSelector to the fully-qualified-name of your in step 3 created contextSelector
    • Alternative: Don't create the file, just set the system property Log4jContextSelector to the fqn

Some code examples (without any comments):

MessageFactory:

public final class OwnMessageFactory extends AbstractMessageFactory
{
  public static final OwnMessageFactory INSTANCE = new OwnMessageFactory();

  @Override
  public Message newMessage(final String message, final Object... params)
  {
    return new OwnDataMessage(message, params);
  }
}

LoggerContext:

public class OwnLoggerContext extends LoggerContext
{
  // constructors

  protected Logger newInstance(final LoggerContext ctx, final String name, MessageFactory messageFactory)
  {
    if (null == messageFactory)
      messageFactory = OwnMessageFactory.INSTANCE;

    return super.newInstance(ctx, name, messageFactory);
  }

}

ContextSelector:

public class OwnContextSelector extends ClassLoaderContextSelector
{

  @Override
  protected LoggerContext createContext(String name, URI configLocation)
  {
    return new OwnLoggerContext(name, null, configLocation);
  }

}

log4j2.component.properties:

Log4jContextSelector=com.example.OwnContextSelector

  1. If you don't set a message factory, ParameterizedMessageFactory is used by default.
  2. By default, log4j uses a message factory for parameterized messages, so you can do logger.warn("hello {}", user.getName());
  3. You set your own factory by calling LogManager.getLogger(name, messageFactory) when you obtain a logger.

If you want the String.format kind of params (the System.out.printf format) you would use LogManager.getLogger(MyClass.class, new StringFormatterMessageFactory()) to obtain a logger.

If your most common usage is parameterized messages (the {} format), but if you occasionally want more control over the output format as afforded by the string formatter, you can declare your logger normally (so it uses {} parameterized messages), and use the Logger.printf methods.

Example:

class MyClass {
    private static Logger logger = LogManager.getLogger(MyClass.class);

    public void someMethod() {
        // use printf here to precisely control the number of digits displayed
        logger.printf(Level.INFO, "pi: %.5f", Math.PI);
    }
}

This is all in code. Configuration (XML or otherwise) is not involved.