Search code examples
mavenlog4j2maven-module

Different log4j2 logging levels for maven project with multiple modules


I am having a Maven project with a few different modules (a core module and some other modules dealing various functionalities) for which I would like to set different logging levels using log4j2 (ex: for core module I would like to have detailed logs (DEBUG) but for the other ones I would like to keep a minimum set of logs (INFO)).

Here is how the project structure looks like:

  project
 +- root
    +- pom.xml
    +- module-core
    |  +- pom.xml
    |  +- src 
    |  |  +- main
    |  |     +- java
    |  |     +- resources
    |  |  +- test
    |  |     +- java
    |  +- target  
    +- module-A
    |  +- pom.xml
    |  +- src
    |  |  +- main
    |  |     +- java
    |  |  +- test
    |  |     +- java
    |  +- target
    +- module-B
    |  +- pom.xml
    |  +- src
    |  |  +- main
    |  |     +- java
    |  |  +- test
    |  |     +- java
    |  +- target

Log4j2 dependencies are placed in the root pom.xml file and log4j2.xml is placed into module-core under resources folder.

Would it be possible to customize and specify desired logging levels into the above log4j2.xml file?

Here is the log4j2.xml content:

<?xml version="1.0" encoding="UTF-8"?>

<properties>
    <property name="filters">org.openqa,org.apache.maven,sun.reflect,java.lang.reflect,java.utils,org.testng</property>
    <property name="logMsgPattern">%highlight{%-5p | %d{HH:mm:ss} |} (%F:%L) %highlight{| %M ||} %m%n%xEx{filters(${filters})}</property>
</properties>

<Appenders>
    <File name="FILE" fileName="target/logs/logfile.log" append="true">
        <PatternLayout pattern="%-5p | %d{HH:mm:ss} | (%F:%L) | %M - %m%n"/>
    </File>

    <Console name="CONSOLE" target="SYSTEM_OUT">
        <PatternLayout pattern="%highlight{%-5p | %d{HH:mm:ss:fff} |} (%F:%L) %highlight{| %M ||} %m%n%xEx{filters(${filters})}"/>
    </Console>

</Appenders>

<Loggers>

    <Root level="INFO" additivity="false">
        <AppenderRef level="INFO" ref="CONSOLE" />
    </Root>

    <Logger name="module-core.*" level="DEBUG" additivity="false">
        <AppenderRef level="DEBUG" ref="CONSOLE" />
    </Logger>

    <Logger name="module-A.*" level="INFO" additivity="false">
        <AppenderRef level="INFO" ref="CONSOLE" />
    </Logger>

</Loggers>

The problem is that Root level="INFO" overrides the Logger section for module-core and keeps displaying INFO Logs across all the project.

Is there a way to ignore the root level section and force log4j2 to display the logs only for my desired sections within the modules only?

Thanks!


Solution

  • Maven is a build tool and Log4j is a library that comes into play in runtime.

    Hence it's not clear what exactly you're trying to achieve.

    In order to get correct definitions of log4j its definitions (configurations) have to appear in the artifact, and maven "ends" when the artifact is prepared (ok, there are install and deploy but they do just "mechanical" actions on an already-prepared artifact and do not change it).

    Now artifacts can be roughly divided into 2 types:

    • Application intended to be deployed on server (usually these are WARs, EARs, spring-boot-applications, etc)
    • Libraries intended for internal usage by the applications of your project or libraries that are supposed to be publicly accessible (like log4j itself, hibernate, spring, etc.)

    Usually, only the first type of artifacts has logging definitions (log4j2.xml, whatever). Libraries while being able to use the logging framework, do not have their own definitions, because only the application that uses the library "knows" how to "serve" the logs (appenders, patterns to be applied and so forth)

    Now, applying this knowledge to your question: I assume that module-core is a library, but module-a & module-b are applications.

    If so, they should have their own log4j2.xml in the classpath in runtime. Usually, people place the configuration file into src/main/resources of these modules and they're done - each log4j2.xml can be different. Alternatively, they import the file from some "shared" location, if the goal is to preserve the same log4j behavior (again, in runtime) between the applications.

    Now Having said all that, maven run tests during the build and this is actually the only place where you see maven running your code actually during the build.

    Tests in maven have a different classpath, so if the goal is to establish the different behavior of log4j in tests you should place the logging configurations into src/test/resources. Neither this file nor tests themselves won't be packaged into the production artifact.

    This practice is applicable to both "libraries" and "applications"