Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Configuring Log4j Loggers Programmatically

People also ask

How do you set log file path in log4j properties dynamically?

System. setProperty("{my. log", "C:/logfile. log");

How do I change the log4j configuration at runtime?

Use LogManager. resetConfiguration(); to clear the current config and configure it again. Another approach is to build a new appender and replace the old one with it (most appenders don't support changing their config).


You can add/remove Appender programmatically to Log4j:

  ConsoleAppender console = new ConsoleAppender(); //create appender
  //configure the appender
  String PATTERN = "%d [%p|%c|%C{1}] %m%n";
  console.setLayout(new PatternLayout(PATTERN)); 
  console.setThreshold(Level.FATAL);
  console.activateOptions();
  //add appender to any Logger (here is root)
  Logger.getRootLogger().addAppender(console);

  FileAppender fa = new FileAppender();
  fa.setName("FileLogger");
  fa.setFile("mylog.log");
  fa.setLayout(new PatternLayout("%d %-5p [%c{1}] %m%n"));
  fa.setThreshold(Level.DEBUG);
  fa.setAppend(true);
  fa.activateOptions();

  //add appender to any Logger (here is root)
  Logger.getRootLogger().addAppender(fa);
  //repeat with all other desired appenders

I'd suggest you put it into an init() somewhere, where you are sure, that this will be executed before anything else. You can then remove all existing appenders on the root logger with

 Logger.getRootLogger().getLoggerRepository().resetConfiguration();

and start with adding your own. You need log4j in the classpath of course for this to work.

Remark:
You can take any Logger.getLogger(...) you like to add appenders. I just took the root logger because it is at the bottom of all things and will handle everything that is passed through other appenders in other categories (unless configured otherwise by setting the additivity flag).

If you need to know how logging works and how is decided where logs are written read this manual for more infos about that.
In Short:

  Logger fizz = LoggerFactory.getLogger("com.fizz")

will give you a logger for the category "com.fizz".
For the above example this means that everything logged with it will be referred to the console and file appender on the root logger.
If you add an appender to Logger.getLogger("com.fizz").addAppender(newAppender) then logging from fizz will be handled by alle the appenders from the root logger and the newAppender.
You don't create Loggers with the configuration, you just provide handlers for all possible categories in your system.


It sounds like you're trying to use log4j from "both ends" (the consumer end and the configuration end).

If you want to code against the slf4j api but determine ahead of time (and programmatically) the configuration of the log4j Loggers that the classpath will return, you absolutely have to have some sort of logging adaptation which makes use of lazy construction.

public class YourLoggingWrapper {
    private static boolean loggingIsInitialized = false;

    public YourLoggingWrapper() {
        // ...blah
    }

    public static void debug(String debugMsg) {
        log(LogLevel.Debug, debugMsg);
    }

    // Same for all other log levels your want to handle.
    // You mentioned TRACE and ERROR.

    private static void log(LogLevel level, String logMsg) {
        if(!loggingIsInitialized)
            initLogging();

        org.slf4j.Logger slf4jLogger = org.slf4j.LoggerFactory.getLogger("DebugLogger");

        switch(level) {
        case: Debug:
            logger.debug(logMsg);
            break;
        default:
            // whatever
        }
    }

    // log4j logging is lazily constructed; it gets initialized
    // the first time the invoking app calls a log method
    private static void initLogging() {
        loggingIsInitialized = true;

        org.apache.log4j.Logger debugLogger = org.apache.log4j.LoggerFactory.getLogger("DebugLogger");

        // Now all the same configuration code that @oers suggested applies...
        // configure the logger, configure and add its appenders, etc.
        debugLogger.addAppender(someConfiguredFileAppender);
    }

With this approach, you don't need to worry about where/when your log4j loggers get configured. The first time the classpath asks for them, they get lazily constructed, passed back and made available via slf4j. Hope this helped!


In the case that you have defined an appender in log4j properties and would like to update it programmatically, set the name in the log4j properties and get it by name.

Here's an example log4j.properties entry:

log4j.appender.stdout.Name=console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.Threshold=INFO

To update it, do the following:

((ConsoleAppender) Logger.getRootLogger().getAppender("console")).setThreshold(Level.DEBUG);

If someone comes looking for configuring log4j2 programmatically in Java, then this link could help: (https://www.studytonight.com/post/log4j2-programmatic-configuration-in-java-class)

Here is the basic code for configuring a Console Appender:

ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();

builder.setStatusLevel(Level.DEBUG);
// naming the logger configuration
builder.setConfigurationName("DefaultLogger");

// create a console appender
AppenderComponentBuilder appenderBuilder = builder.newAppender("Console", "CONSOLE")
                .addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
// add a layout like pattern, json etc
appenderBuilder.add(builder.newLayout("PatternLayout")
                .addAttribute("pattern", "%d %p %c [%t] %m%n"));
RootLoggerComponentBuilder rootLogger = builder.newRootLogger(Level.DEBUG);
rootLogger.add(builder.newAppenderRef("Console"));

builder.add(appenderBuilder);
builder.add(rootLogger);
Configurator.reconfigure(builder.build());

This will reconfigure the default rootLogger and will also create a new appender.