Injectable Logger with CDI

In my Java EE projects I don’t like logger configuration in every classes such as below:

private Logger logger = Logger.getLogger(this.getClass().getName());

I want to use with @Inject annotation. Fortunately there is @Produces annotation for it (see CDI – JSR 299: Context and Dependency Injection). I’m writing a producer class then I can @Inject logger  everywhere as below:

package com.devsniper.demoapp.util;

import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;

import org.apache.log4j.Logger;

/**
 * Logging producer for injectable log4j logger
 *
 * @author cem ikta
 */
public class LoggerProducer {
   /**
    * @param injectionPoint
    * @return logger
    */
    @Produces
    public Logger produceLogger(InjectionPoint injectionPoint) {
		return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
    }
}

in classes:

@Inject
private transient Logger logger;

I am using log4j in producer class but this works well for java logger too. Transient keyword is important, without transient keyword you get the following error in GlassFish:

WELD-000054 Producers cannot produce non-serializable instances for injection into non-transient fields of passivating beans\\n\\nProducer\: Producer Method [Logger] with qualifiers [@Any @Default] declared as [[method] @Produces public  com.devsniper.demoapp.util.LoggerProducer.produceLogger(InjectionPoint)]\\nInjection Point\: [field] @Inject private com.desniper.demoapp.controller.UserController.logger

16 Comments

  1. Emre Simtay
    Sep 19, 2012 @ 21:51:57

    Thanks for sharing it.

    Reply

  2. Prashanth Kumar
    Apr 16, 2013 @ 17:19:14

    Cool , really nice. Thanks for the tip

    Reply

  3. Benjamin Murauer
    Jul 25, 2013 @ 16:55:16

    Nice..

    very tiny enhancement: you could remove the .getName()

    Reply

  4. Sudheer Gollapudi
    Aug 14, 2013 @ 22:24:07

    Very nice example.Could you please tell how to configure the logger to roll the file to a specific file like apache log4j

    Reply

    • Cem Ikta
      Aug 15, 2013 @ 16:27:08

      Hi,

      Hier is a small log4j.properties example.

      Reply

      • Sudheer Gollapudi
        Aug 15, 2013 @ 20:08:51

        Hello Cem,Thanks for your response but I was wondering instead of using any jars,would there be any way just by using CDI and Java util logging,can we write the applications logs to a file including the roller

        Reply

  5. Sudheer Gollapudi
    Aug 21, 2013 @ 21:35:34

    Cem,I was able to configure the logger to write to a separate file.Please see the code below inside my producerLogger method.

    //Configure the File Handler
    FileHandler handler= new FileHandler(“/APPLOGS/demoApp/demoApp.log”);
    // This block configure the logger with handler and formatter
    handler.setFormatter(new LogFormatter());
    logger.addHandler(handler);
    //To disable logs from console
    logger.setUseParentHandlers(false);

    But I had another question,the produceLogger method is being called everytime I send a request to the class which is Injecting the logger.I tried @RequestScoped and @SessionScoped but none of them are working

    Thanks
    Sudheer

    Reply

    • Cem Ikta
      Aug 22, 2013 @ 12:35:18

      Simple steps:
      1 – You should have a logging.properties file in resources folder of your project.
      2 – You should have a LoggerProducer.java as seen in this toturial.
      3 – Look at your application/web server log settings.

      Sample logging.properties file:

      ############################################################
      # Default Logging Configuration File
      #
      # You can use a different file by specifying a filename
      # with the java.util.logging.config.file system property.
      # For example java -Djava.util.logging.config.file=myfile
      ############################################################

      ############################################################
      # Global properties
      ############################################################

      # "handlers" specifies a comma separated list of log Handler
      # classes. These handlers will be installed during VM startup.
      # Note that these classes must be on the system classpath.
      # By default we only configure a ConsoleHandler, which will only
      # show messages at the INFO and above levels.
      handlers= java.util.logging.ConsoleHandler, java.util.logging.FileHandler

      # To also add the FileHandler, use the following line instead.
      #handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler

      # Default global logging level.
      # This specifies which kinds of events are logged across
      # all loggers. For any given facility this global level
      # can be overriden by a facility specific level
      # Note that the ConsoleHandler also has a separate level
      # setting to limit messages printed to the console.
      .level= FINEST

      ############################################################
      # Handler specific properties.
      # Describes specific configuration info for Handlers.
      ############################################################

      # default file output is in home directory.
      java.util.logging.FileHandler.pattern = %h/java%u.log
      java.util.logging.FileHandler.level = FINEST
      java.util.logging.FileHandler.limit = 50000
      java.util.logging.FileHandler.count = 1
      java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter

      # Limit the message that are printed on the console to INFO and above.
      java.util.logging.ConsoleHandler.level = FINEST
      java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

      ############################################################
      # Facility specific properties.
      # Provides extra control for each logger.
      ############################################################

      # For example, set the com.xyz.foo logger to only log SEVERE
      # messages:
      org.demo.yourproject.level = FINEST

      Reply

  6. Rinkesh Dusane
    Jun 20, 2014 @ 15:15:03

    Hi,

    In my case, it creates the multiple log files. e.g. java0.log, java1.log, java2.log…and files created with 2KB…3KB size even in property size mentioned java.util.logging.FileHandler.limit = 50000.
    So is that any solution for this issue.

    Reply

  7. Sergey
    Jul 29, 2014 @ 18:40:51

    Will this logger inject in Servlet 3.0.

    public class WelcomeServlet extends HttpServlet {
    @Inject
    private transient Logger logger;

    In Jboss 7, logger is null.

    Reply

    • Cem Ikta
      Jul 29, 2014 @ 23:34:44

      Hi Sergey,

      Have you beans.xml in your project? In Java EE 7 (CDI 1.1) you don’t have to put beans.xml but then you should use @Dependent annotation on your LoggerProducer class. I used only in Glassfish and it works!

      Reply

      • Sergey
        Aug 06, 2014 @ 17:05:24

        Hi Cem Ikta,
        Thank you for reply.
        I verified in WildFly and GlassFish and @Inject in WildFly into Servlet doesn’t work but it works well in GlassFish.

        Reply

  8. ledo
    Sep 23, 2016 @ 16:50:06

    Is it important what is method name (produceLogger) or it can be what so ever ?

    Reply

    • Cem Ikta
      Sep 23, 2016 @ 17:13:46

      Method name does not matter but I use this for GlassFish application server.

      Reply

  9. Rafael Nascimento
    May 24, 2017 @ 23:03:14

    Hi, excellent post! I tried to implement your sample exactly as it is, but I’m getting the following error:

    Severe: Exception during lifecycle processing
    org.glassfish.deployment.common.DeploymentException: CDI deployment failure:WELD-001408: Unsatisfied dependencies for type Logger with qualifiers @Default
    at injection point [BackedAnnotatedField] @Inject private transient controller.LoginAdminBean.logger
    at controller.LoginAdminBean.logger(LoginAdminBean.java:0)

    I don’t know what is wrong!

    Reply

Leave a Reply