How do I inject a logger into a field in the sample spring boot application?

29,259

Solution 1

Although it is not the usual way you can add a logger bean directly in your context reproducing the classic bind:

private final Logger logger = LoggerFactory.getLogger(MainController.class);

simply inserting in the spring context:

<bean id="logger" scope="prototype" class="org.slf4j.LoggerFactory" factory-method="getLogger">
    <constructor-arg name="name" value="youLoggerName" />
</bean>

then you can simply inject your logger:

@Autowired
private Logger logger;

Solution 2

If the objective here is code reduction then try Project Lombok. You then don't even need to declare the logger - just add an annotation and use log instead of logger

So your above code will now look like this:

import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
// import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
public class MainController {

    @RequestMapping("/")
    public String enterSite(HttpServletResponse response) {
        log.info("site entered");
        return "welcome";
    }
}

Solution 3

Solution using @Bean:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.InjectionPoint;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@Configuration
public class LoggerConfiguration {

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public Logger logger(InjectionPoint injectionPoint){
        return LoggerFactory.getLogger(injectionPoint.getMethodParameter().getContainingClass());
    }

}

After that, just inject the Logger using Constructor Injection (field injection will not work):

@Service
class SomeService {

    private Logger logger;

    public SomeService(Logger logger;) {
        this.logger = logger;
    }

    public void someMethod() {
        logger.error("Some log");
    }  
}

Solution 4

You can have Spring autowire a Logger instance, but it would be a very unusual thing to do (you'd need a bean of type Logger to be in your application context). The far more usual approach is to initialise the logger where it's declared, configuring it with the class that will be using it for logging:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MainController {

    private final Logger logger = LoggerFactory.getLogger(MainController.class);

}

Solution 5

This is how I got it working for field injection

LoggingConfiguration.java

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

    @Configuration
    public class LoggingConfiguration {

        @Bean
        public Logger log() {
            var log = LoggerFactory.getLogger("com.bitsmonkey.dummy");
            return log;
        }
    }

Now inside the controller

DummyController.java

@Controller
public class DummyController {

@Autowired
private Logger log;

//......
Share:
29,259
vic
Author by

vic

Updated on July 09, 2022

Comments

  • vic
    vic almost 2 years

    What I want is to make spring autowire a logger. So, in other words, I want to have this working:

    import javax.servlet.http.HttpServletResponse;
    
    import org.slf4j.Logger;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class MainController {
    
        @Autowired
        private Logger logger;
        
        @RequestMapping("/")
        public String enterSite(HttpServletResponse response) {
            logger.info("site entered");
            return "welcome";
        }
    }
    

    Right now it throws an exception at startup: "No qualifying bean of type [org.slf4j.Logger] found for dependency...".

    My pom.xml dependencies:

    <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.2.0.M1</version>
            <relativePath /> <!-- lookup parent from repository -->
        </parent>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-rest</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.apache.tomcat.embed</groupId>
                <artifactId>tomcat-embed-jasper</artifactId>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jstl</artifactId>
            </dependency>
    
            <dependency>
                <groupId>postgresql</groupId>
                <artifactId>postgresql</artifactId>
                <version>9.1-901.jdbc4</version>
            </dependency>
            <!-- <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> 
                </dependency> -->
        </dependencies>
    

    I read this: http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-logging

    It says if you use one of the starter poms (I do) Logback is used - but for internal logging. Can it be autowired in my classes?