Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the default MessageFactory for Log4J

The documentation for org.apache.logging.log4j.Logger says

   /**
     * Logs a message with parameters at the given level.
     *
     * @param level the logging level
     * @param message the message to log; the format depends on the message factory.
     * @param params parameters to the message.
     * @see #getMessageFactory()
     */
    void log(Level level, String message, Object... params);

But:

  1. Which MessageFactory is used when I didn't set any?
  2. Which message format uses the default factory?
  3. How can I set my own factory in case the default factory can't do what I need?

Update:

Please add class names and XML element names to the answer. It is very difficult to find anything about Log4J 2.x on Google without the proper search terms.

like image 286
Martin Avatar asked Sep 15 '14 09:09

Martin


2 Answers

  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.

like image 108
Remko Popma Avatar answered Oct 24 '22 06:10

Remko Popma


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
like image 45
chris922 Avatar answered Oct 24 '22 08:10

chris922