Table of Contents

About

Log4j is a debugging logger.

version:

  • 1.2 (2015 switch to 2.x)
  • 2

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

  • The name of this Logger will be the full qualified class name or where it reside. If the class is located at “com.example.app.MyClass”, the name will be the same
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

  • First via a java property:
-Dlog4j.configuration=file:/etc/schema-registry/log4j.properties

File

Format supported:

  • properties
  • xml
  • yaml

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);