Selenium Meets Log4j2


Welcome to this tutorial on integrating Log4j2 in a Selenium project.

In this tutorial, we will cover the following topics.

What is Log4j2?

It is a Java-based logging utility. As of this writing, Apache Log4j 2.x is the latest version for Log4j and it provides significant improvements over its predecessor, Log4j 1.x.

Getting Started

Configuration of Log4j2 can be accomplished in 1 of 4 ways:

  1. Through a configuration file written in XML, JSON, YAML, or properties format.
  2. Programmatically, by creating a ConfigurationFactory and Configuration implementation.
  3. Programmatically, by calling the APIs exposed in the Configuration interface to add components to the default configuration.
  4. Programmatically, by calling methods on the internal Logger class.

In this tutorial, we’re going to be using option one with a properties configuration file.

The Properties File

The properties file may contain various components including a logger, filter and appender. Furthermore,

  • Each individual component must have a type attribute specified that identifies the component’s Plugin type.
  • The logger element must have a name attribute specified, will usually have a level attribute specified and may also have an additivity attribute specified.
  • The level may be configured with one of TRACE, DEBUG, INFO, WARN, ERROR, ALL or OFF. If no level is specified it will default to ERROR.
  • The additivity attribute may be assigned a value of true or false. If the attribute is omitted the default value of true will be used.
  • Every configuration must have a root logger. If one is not configured the default root LoggerConfig, which has a level of ERROR and has a Console appender attached, will be used. The main differences between the root logger and other loggers are:
    • The root logger does not have a name attribute.
    • The root logger does not support the additivity attribute since it has no parent.

Don’t worry if any or all of this doesn’t make sense now. It will all start making more and more sense the more you work with Log4j2.

Creating A Maven Project

If you are using IntelliJ IDEA, go to File > New > Project > Select Maven > Next > Give project a name > Finish.

Java Maven project setup

Adding Dependencies

Lets begin by adding the Selenium and TestNG dependencies.

Click here for the latest dependency versions and add them to your pom.xml file.

Selenium Java Maven

Next, we need to add the Log4j2 dependencies.

Log4j2 consists of an API and an implementation (Core). You will need to add both dependencies to your pom.xml file. Make sure that you select Apache Log4j Core and Apache Log4j API dependencies and not the Apache Log4j dependency (this is the old Log4j 1.x version).

By now, your pom.xml file should look something like this:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>Log4j2Example</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>3.141.59</version>
        </dependency>

        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>7.1.0</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>7.1.0</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.13.3</version>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.13.3</version>
        </dependency>
    </dependencies>
</project>

Creating A Properties file

Log4j2 expects the properties file to be located under src >main > resources in your project and the file must be named log4j2.properties.

Add the following properties to log messages to the console.

# configuration syntax
status=error
dest=err
name=PropertiesConfig

# publish console logs
appender.console.type=Console
appender.console.name=STDOUT
appender.console.layout.type=PatternLayout
appender.console.layout.pattern=[%-5level] %d{DEFAULT} %c:%L - %m%n

# capture logs
logger.app.name=base
logger.app.level=debug
logger.app.additivity=false
logger.app.appenderRef.console.ref=STDOUT

# root logger
rootLogger.level=info
rootLogger.appenderRef.stdout.ref=STDOUT

Creating A Base Class

Add a new package under src > main > java called base. Create a class called BaseClass inside this package. Add a WebDriver and Logger instance making sure that the Logger is imported from the org.apache.logging.log4j class.

Add a setUp and tearDown method to the BaseClass with some logging statements as follows.

package base;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.openqa.selenium.WebDriver;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;

public class BaseClass {
    public static WebDriver driver;
    public static Logger log = LogManager.getLogger();

    @BeforeSuite
    public void setUp() {
        if (driver == null) {
            log.info("Hello World!");
        }
    }

    @AfterSuite
    public void tearDown() {
        log.info("Goodbye!");
        if (driver != null) {
            driver.quit();
        }
    }
}

Creating Your First Test

Add a new package under src > test > java called com.automation.testcases. Next, create a HelloWorld class in this package.

Create a test called test testHelloWorld and add several logging statements as follows.

package com.automation.testcases;

import base.BaseClass;
import org.testng.annotations.Test;

public class HelloWorld extends BaseClass {

    @Test
    public void testHelloWorld() {
        log.debug("Sample DEBUG message");
        log.error("Sample ERROR message");
        log.info("Sample INFO message");
        log.warn("Sample WARN message");
    }
}

Creating A TestNG Run Configuration

Right-click the HelloWorld class and select Create ‘HelloWorld’

Give your configuration a name, make sure that Class is selected as the Test kind and click OK.

Click the green play button to run your newly created configuration.

If all goes well, the console output should look something like this:

Congratulations! You have successfully configures Log4j2 with your Selenium project.

Exporting Logs To A File

This is great but what if you want to export the logs to a file?

To log messages to a file, simply add a new appender to the properties file of type File with a corresponding logger (logger.app.appenderRef.file.ref). The updated log4j2.properties file should be as follows.

# configuration syntax
status=error
dest=err
name=PropertiesConfig

# publish console logs
appender.console.type=Console
appender.console.name=STDOUT
appender.console.layout.type=PatternLayout
appender.console.layout.pattern=[%-5level] %d{DEFAULT} %c:%L - %m%n

# publish file logs
appender.file.type=File
appender.file.name=LOGFILE
appender.file.fileName=logs/myLog.log
appender.file.layout.type=PatternLayout
appender.file.layout.pattern=[%-5level] %d{DEFAULT} %c:%L - %m%n
appender.file.append=false

# capture logs
logger.app.name=base
logger.app.level=debug
logger.app.additivity=false
logger.app.appenderRef.console.ref=STDOUT
logger.app.appenderRef.file.ref=LOGFILE

# root logger
rootLogger.level=info
rootLogger.appenderRef.stdout.ref=STDOUT

Re-run the test. Notice that a new folder called logs is created and that it contains a file called myLog .log. This log file should contain the same log statements that were printed to the console.

This is all you need to get started with Log4j2. However, if you feel that you haven’t had enough yet, read on! Next, we’ll dive deeper into the contents of the properties file by looking at one line at a time.

Properties File In Detail

status – The level of internal Log4j events that should be logged to the console. Valid values for this attribute are “trace”, “debug”, “info”, “warn”, “error” and “fatal”. Log4j will log details about initialization, rollover and other internal actions to the status logger. Setting status=”trace” is one of the first tools available to you if you need to troubleshoot log4j.

dest – Accepts either “err” for stderr, “out” for stdout, a file path, or a URL.

name – The name of the configuration.

appender.console.type=Console – The appender which publish logs to the console.

appender.console.name=STDOUT – The name of the console appender. This can be any name you choose.

appender.console.layout.type=PatternLayout – An Appender uses a Layout to format a LogEvent into a form that meets the needs of whatever will be consuming the log event. Click here to learn more about PatterLayout.

appender.console.layout.pattern=[%-5level] %d{DEFAULT} %c:%L – %m%n – Let’s break this down

  • %-5level = by default the amount of space allocated for the log level will be 5 characters, the “-“ me means it will be left-aligned
  • %d{DEFAULT} = default date format (example: 2020-01-01 15:00:00,123)
  • %c = Outputs the name of the logger that published the logging event
  • %L = Outputs the line number from where the logging request was issued
  • %m = Outputs the application supplied message associated with the logging event
  • %n = Outputs the platform dependent line separator character or characters

appender.file.append – Whether or not you wish to keep adding to the same file or create a new one each time the test runs.

logger.app.name=base – Refers to the name of the package where the Logger is located.

logger.app.level=debug – Sets the Logger’s LogLevel to DEBUG.

logger.app.additivity=false – Disables additivity
Click here to learn more.

logger.app.appenderRef.console.ref=STDOUT – The name of the Console appender as entered in appender.console.name (the names must match).

logger.app.appenderRef.file.ref=LOGFILE – The name of the File appender as entered in appender.file.name (the names must match).

rootLogger.level=info – Sets the rootLogger’s LogLevel to INFO

rootLogger.appenderRef.stdout.ref=STDOUT – Specified the rootLogger’s appender as entered in appender.console.name or appender.file.name (the names must match).

References

Log4j documentation

Leave a Reply