Vlad
Vlad

Reputation: 662

log4j2 logging works only in one class

I want enable logging in classes JarClassLoader and Menu.

In Menu class it works (log is printed to file and console). But logging doesn't work in JarClassLoader (logging does not work either in the console or in the file).

For simplicity, I added the message only to the class constructor of JarClassLoader and one message at the beginning of main(String[] args) method.

log4j2.properties

name=PropertiesConfig
property.filename=classloading/menu-module/logs
appenders=console, file

appender.console.type=Console
appender.console.name=STDOUT
appender.console.layout.type=PatternLayout
appender.console.layout.pattern=[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n

appender.file.type=File
appender.file.name=LOGFILE
appender.file.fileName=${filename}/propertieslogs.log
appender.file.layout.type=PatternLayout
appender.file.layout.pattern=[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n

rootLogger.level=info
rootLogger.appenderRefs=stdout
rootLogger.appenderRef.stdout.ref=STDOUT

loggers=file
logger.file.name=com.example.classloading
logger.file.level=info
logger.file.appenderRefs=file
logger.file.appenderRef.file.ref=LOGFILE

JarClassLoader

package com.example.classloading;

import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class JarClassLoader extends ClassLoader {

    private static final Logger log = LogManager.getLogger(JarClassLoader.class);

    private HashMap<String, Class<?>> cache = new HashMap<String, Class<?>>();
    private String jarFileName;
    private String packageName;
    private static String WARNING = "Warning : No jar file found. Packet unmarshalling won't be possible. Please verify your classpath";

    public JarClassLoader(String jarFileName, String packageName) {         
        log.info(">> inside JarClassLoader");

        this.jarFileName = jarFileName;
        this.packageName = packageName;

        cacheClasses();
    }

    private void cacheClasses() {
        try {
            JarFile jarFile = new JarFile(jarFileName);
            Enumeration entries = jarFile.entries();
            while (entries.hasMoreElements()) {
                JarEntry jarEntry = (JarEntry) entries.nextElement();
                // simple class validation based on package name
                if (match(normalize(jarEntry.getName()), packageName)) {
                    byte[] classData = loadClassData(jarFile, jarEntry);
                    if (classData != null) {
                        Class<?> clazz = defineClass(stripClassName(normalize(jarEntry.getName())), classData, 0, classData.length);
                        cache.put(clazz.getName(), clazz);
                        System.out.println("== class " + clazz.getName() + " loaded in cache");
                    }
                }
            }
        }
        catch (IOException IOE) {
            System.out.println(WARNING);
        }
    }

    public synchronized Class<?> loadClass(String name) throws ClassNotFoundException {
        Class<?> result = cache.get(name);
        if (result == null)
            result = cache.get(packageName + "." + name);
        if (result == null)
            result = super.findSystemClass(name);    
        System.out.println("== loadClass(" + name + ")");    
        return result;
    }

    private String stripClassName(String className) {
        return className.substring(0, className.length() - 6);
    }

    private String normalize(String className) {
        return className.replace('/', '.');
    }

    private boolean match(String className, String packageName) {
        return className.startsWith(packageName) && className.endsWith(".class");
    }

    private byte[] loadClassData(JarFile jarFile, JarEntry jarEntry) throws IOException {
        long size = jarEntry.getSize();
        if (size == -1 || size == 0)
            return null;

        byte[] data = new byte[(int)size];
        InputStream in = jarFile.getInputStream(jarEntry);
        in.read(data);

        return data;
    }
}

Menu

package com.example.classloading;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Scanner;

public class Menu {

    private static final Logger log = LogManager.getLogger();

    public static void main(String[] args) {

        int select;
        do {
            log.info(">> menu started");

            System.out.println("=== MENU ===");
            System.out.println("This is a simple multi-module project that can dynamically load modules.");
            System.out.println("1. Load and run simple-module");
            System.out.println("2. Load and run module in jar from ...");
            System.out.println("0. EXIT");

            Scanner scanner = new Scanner(System.in);
            select = scanner.nextInt();

            switch (select) {
                case 1: {
                    JarClassLoader jarClassLoader = new JarClassLoader("classloading/simple-module/target/simple-module-1.0-SNAPSHOT.jar", "com.example.classloading");
                    try {
                        Class<?> clas = jarClassLoader.loadClass("com.example.classloading.SimpleModule");
                        Module sample = (Module) clas.newInstance();
                        sample.run();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
                }
                case 2: {
                    System.out.print("    Path to jar: ");
                    String jarFileName = scanner.next();
                    System.out.print("    Package name: ");
                    String packageName = scanner.next();
                    System.out.print("    Class to load and run: ");
                    String classToLoad = scanner.next();

                    JarClassLoader jarClassLoader = new JarClassLoader(jarFileName, packageName);
                    try {
                        Class<?> clas = jarClassLoader.loadClass(classToLoad);
                        Module sample = (Module) clas.newInstance();
                        sample.run();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
                }
            }
        } while (select != 0);
    }

}

output


So, why does not logging work in the JarClassLoader class?

Upvotes: 0

Views: 1401

Answers (1)

Ad Infinitum
Ad Infinitum

Reputation: 3706

I have run your code and there is no problem with the logging. When I run the exact code, you have, the output is as follows;

[INFO ] 2017-04-09 20:07:15.208 [main] Menu - >> menu started
=== MENU ===
This is a simple multi-module project that can dynamically load modules.
1. Load and run simple-module
2. Load and run module in jar from ...
0. EXIT
1
[INFO ] 2017-04-09 20:07:20.681 [main] JarClassLoader - >> inside JarClassLoader

In your screenshot, I did not see that you have entered "1" or "2" in your console as the selection. As long as you do not enter anything from the console, the java program waits for an input and because of this reason, it never reaches to the line, in where logging is done.

Upvotes: 1

Related Questions