Matteo NNZ
Matteo NNZ

Reputation: 12685

Log4j does not output to file when called by Spring Boot (but it does when called on command line)

Problem summary

I have a service which can be called by two entry points: a main() of a console app, and a rest endpoint.

The service is supposed to log to a file via a SL4J Logger.

When I call the app via command line (java -jar myArtifact.jar <some execution parameters>) it works fine, the file is correctly filled.

When I do a request via the Spring rest endpoint, I see the output of my logger in the process which keeps the REST service up:

enter image description here (the line indicated by arrow is the first line logged by my logger).

I feel some configuration from Spring is erasing my log4j configuration.

Can anyone point me to the right direction to have my logger correctly logging into the file I wish?

Setup

I have a project which has a certain TaskService which contains a static Logger (org.sl4j).

This service can be called two ways:


Relevant part of the three classes:

TaskService.java

public final class TaskService {
    
    private static final Logger LOGGER = LoggerFactory.getLogger(TaskService.class);

}

TaskCommandLineApp.java

public static void main(String[] args) {
    //...
    TaskRequest taskRequest = ... (coming from input);
    TaskService taskService = new TaskService();
    taskService.run(taskRequest);
    //...
}

TaskController.java

@RestController
@RequestMapping("/task")
public final class TaskController {

    @Autowired
    private final TaskService taskService;
    
    @RequestMapping(value = "/tasks", method = RequestMethod.POST)
    public ResponseEntity<?> postTask(@RequestBody TaskRequest taskRequest) {
        //...
        taskRequest.run(taskRequest);
        //...
    }
}

The log4j2.xml configuration file lies in the src/main/resources folder of the module declaring TaskService (the class which uses the logger), and it contains the following:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
        <File name="File" fileName="task.log" immediateFlush="true" append="false">
            <PatternLayout>
                <pattern>%d %p %C{1.} [%t] %m%n</pattern>
            </PatternLayout>
        </File>
    </Appenders>
    <Loggers>
        <!-- additivity=false ensures summary log data only goes to the summary log file -->
        <Root level="info">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="File"/>
        </Root>
    </Loggers>
</Configuration>

For information, this is the dependency I am using:

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.14.1</version>
</dependency>

... and this is the parent pom of my Spring Boot Application:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.4.RELEASE</version>
    <relativePath/>
</parent>

Upvotes: 0

Views: 449

Answers (1)

Chandan
Chandan

Reputation: 740

By default spring will use a different logging mechanism "spring-boot-starter-logging"

If you want to have log4j/log4j2 working then you should exclude default dependency and add log4j related dependency. As you have already have that configured I guess excluding default one will be sufficient. I do this way for my "spring-boot-starter-web" project by adding exclude clause in pom.xml file

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>

Upvotes: 2

Related Questions