Table of Contents

Java - Log4j

About

Log4j is a debugging logger.

version:

Dependency

dependencies {
    compile 'org.apache.logging.log4j:log4j-api:2.13.0'
    compile 'org.apache.logging.log4j:log4j-core:2.13.0'
}

Usage

Get a logger

protected static final Logger parentLogger = LogManager.getLogger();

Concept

Markers

markers (log4j.Marker class) are objects that are used to add easily filterable information to log messages. Markers can be hierarchical - each Marker may have a parent. This allows for broad categories being subdivided into more specific categories. An example might be a Marker named “Error” with children named “SystemError” and “ApplicationError”.

Markers must be unique.

// A parent
Marker SQL_MARKER = MarkerManager.getMarker("SQL");
// A query marker
Marker QUERY_MARKER = MarkerManager.getMarker("SQL_QUERY").setParents(SQL_MARKER);
// A debug message with a marker
logger.debug(QUERY_MARKER, "SELECT * FROM {}", table);

Configuration

Set

By default, Log4j looks for a configuration file named log4j2.xml (not log4j.xml) in the classpath.

The order on how log4j search the configuration can be found in the AutomaticConfiguration section

-Dlog4j.configuration=file:/etc/schema-registry/log4j.properties

File

Format supported:

xml

Doc

The default configuration xml would look like that.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="error">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

Code

public class Main
{

    private final static Logger logger = Logger.getLogger(Main.class);

    public static void main(final String[] args) throws Exception
    {
        
        // Minimal Configuration
        System.setProperty("log4j.debug","true");
        org.apache.log4j.BasicConfigurator.configure();

        if (args.length != 1)
        {
            logger.error("Please provide an argument");
            return;
        }
...

Example

How to dynamically create different log file

see Log4j - How to route message to log file created dynamically

Multiple Thread Programmatic

A constructor code where the logger is declared as class variable private Logger threadLogger

// Logger Name is normally hierarchic "com.foo.bar"
// We add the thread name
String loggerName = QueryExecutor.class.getCanonicalName()+"."+threadName;
LOGGER = Logger.getLogger(loggerName);

// Log4j properties
Properties log4jProp = new Properties();

// Once a message is accepted by the logger,
// it's sent to one or several appenders (to a file, to the console, to a mail server, etc.).
final String appenderName = "FileAppender";
// Set logger level to DEBUG and its only appender.
log4jProp.setProperty("log4j.logger."+loggerName, "DEBUG, " + appenderName);


// File Appender
log4jProp.setProperty("log4j.appender." + appenderName,"org.apache.log4j.FileAppender");
// Properties are the set method (File equivalent to setFile)
String timeStamp = new SimpleDateFormat("yyyy.MM.dd_HH.mm.ss").format(new Date());
String logFileName = loggerName+"_"+timeStamp+".log";
log4jProp.setProperty("log4j.appender." + appenderName + ".File", logFileName);
// Above Warning
// The levels of logging are TRACE, DEBUG, INFO, WARN, ERROR and FATAL.
// See org.apache.log4j.Level
log4jProp.setProperty("log4j.appender." + appenderName + ".Threshold","WARN");
// Layout is org.apache.log4j.PatternLayout
log4jProp.setProperty("log4j.appender." + appenderName + ".layout","org.apache.log4j.PatternLayout");
// See org.apache.log4j.PatternLayout#setConversionPattern date in ISO 8601 format, thread name, level, logger, message
log4jProp.setProperty("log4j.appender." + appenderName + ".layout.ConversionPattern","%d [%t] %-5p %c - %m%n");

PropertyConfigurator.configure(log4jProp);

Dynamic with Builder

Note that a rolling file appender added this way cannot use lookup value

RollingFileAppender rollingFileAppender = RollingFileAppender.newBuilder()
      .withCreateOnDemand(true)
      .setName("analytics-" + contextEventFileNameExpression)
      .withFileName("logs/analytics.jsonl")
      .withFilePattern("logs/analytics/$${date:yyyy-MM}/analytics-%d{yyyy-dd-MM}-%i.jsonl")
      .setIgnoreExceptions(false)
      .setFilter(
        ThresholdFilter.createFilter(
          Level.INFO,
          Filter.Result.ACCEPT,
          Filter.Result.DENY)
      )
      .setLayout(
        PatternLayout
          .newBuilder()
          .withPattern("%m%n")
          .build()
      )
      .withPolicy(
        /**
         * It causes a rollover once the date/time pattern no longer applies to the active file.
         * https://logging.apache.org/log4j/2.x/manual/appenders.html#timebased-triggering-policy
         */
        TimeBasedTriggeringPolicy
          .newBuilder()
          .build()
      )
      .setConfiguration(config)
      .build();
config.addAppender(rollingFileAppender);