How to integrate programmatic configuration in log4j?

656 Views Asked by At

I am using Log4j version 2.0.1 version and due to organisation policies, I cannot use any higher version for the time-being.

group:'org.apache.logging.log4j',name:'log4j-core',version:'2.0.1'
group:'org.apache.logging.log4j',name:'log4j-api',version:'2.0.1'

My Requirements for logging

  1. If customDebug=true as environment variable, then enable debug logging
  2. There should be 2 logging files generated -- one primary logging (info/debug based on above logs) and error logging.
  3. Have a size based rolling strategy
  4. The directory of the log files is dynamic.
  5. The format should carry the time in certain styling along with thread id.

I tried implementing programmatic configuration of log4j in the following manner --

CustomConfigFactory.java >>

@Plugin(name = "CustomConfigFactory", category = "JsonConfigurationFactory")
@Order(10)
public class CustomConfigFactory extends JsonConfigurationFactory {

    @Override
    public String[] getSupportedTypes() {
        return new String[] {".json"};
    }

    @Override
    public Configuration getConfiguration(ConfigurationSource cs) {
        try{
            String file = Thread.currentThread().getContextClassLoader().getResource("customRollingConfiguration.json").getFile()
            cs = new ConfigurationSource(new FileInputStream(new File(file ));
        } catch (Exception e){
            System.err.println("ERROR : Exception encountered while initiating configuration source: "+e);
        }
        return new CustomJsonConfiguration(cs);
    }

}

CustomJsonConfiguration.java >>

public class CustomJsonConfiguration extends JsonConfiguration {

    public CustomJsonConfiguration(final ConfigurationSource configSource) {
        super(configSource);
    }

    @Override
    protected void doConfigure(){
        try {
            ConfigurationSource source = this.getConfigurationSource();
            Configuration config = CustomConfigFactory.getInstance().getConfiguration(source);

            final Layout layout = PatternLayout.createLayout("%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%5T] %c{1}:%L - %m%n",
                config,null,Charset.defaultCharset(),true,false,"","");

            SizeBasedTriggeringPolicy policy = SizeBasedTriggeringPolicy.createPolicy("10 MB");
            DefaultRolloverStrategy strategy = DefaultRolloverStrategy.createStrategy("50", "5", "min", "9", config);

            String logDir = System.getenv("log_dir");
            String primaryLogFile = logDir+"/my_main_log";
            String primaryLogFilePattern = primaryLogFile+"-backup-%d{MM-dd-yy-HH-mm-ss}-%i.log.gz";

            String errorLogFile = logDir+"/my_err_log";
            String errorLogFilePattern = errorLogFile+"-backup-%d{MM-dd-yy-HH-mm-ss}-%i.log.gz";

            RollingFileAppender appender1 = RollingFileAppender.createAppender(primaryLogFile,
                primaryLogFilePattern,"true", "debugFile","true", "false","false",
                policy, strategy, layout, null, null, null, null, config);
            appender1.start();;

            RollingFileAppender appender2 = RollingFileAppender.createAppender(errorLogFile,
                errorLogFilePattern,"true","errorFile","true","false","false",
                policy, strategy, layout, null,null,null,null, config);
            appender2.start();;

            config.addAppender(appender1);
            config.addAppender(appender2);

            LoggerConfig primaryLoggerConfig = null;
            if(Boolean.valueOf(System.getenv("customDebug")){
                 primaryLoggerConfig = new LoggerConfig("aa.bb.cc.dd",Level.DEBUG,false);
            } else {
                primaryLoggerConfig = new LoggerConfig("aa.bb.cc.dd",Level.INFO,false);
            }
            LoggerConfig errorLoggerConfig = new LoggerConfig("aa.bb.cc.dd",Level.ERROR,false);

            primaryLoggerConfig.addAppender(appender1,null,null);
            errorLoggerConfig.addAppender(appender2,null,null);
            config.addLogger("aa.bb.cc.dd",primaryLoggerConfig);
            config.addLogger("aa.bb.cc.dd",errorLoggerConfig);

            LoggerContext context = new LoggerContext("default_context");
            context.start(config);
        } catch (Exception e){
            System.err.println("");
        }
    }

where the aa.bb.cc.dd refers to the package name of the MyClass below.

MyClass.java where this logger will be used >>

package aa.bb.cc.dd;

public MyClass {
    static final Logger myCustomLog = LogManager.getLogger(MyClass.class);

    void doSomething(){
        myCustomLog.info("Doing something");
    }
}

Sample Test Method as part of a testng class for testing the above class >>>

@Test
public void testDoingSomething(){
    MyClass m1 = new MyClass();
    m1.doSomething();
}

But the above doesn't seem to work and none of the log files are getting generated i.e. logging is not working. I have primarily referred to this for the implementation - -https://logging.apache.org/log4j/2.x/manual/customconfig.html#Hybrid

I'd appreciate if anybody could help me out with this implementation. All suggestions welcomed !!!

Thanks in advance.

EDIT >>> Following is the configuration json after incorporating @VikasSachdeva's comments. The error file is still empty even thought an ERROR condition is being logged in my_main.log

{
  "configuration": {
     "name": "RollingKitConfig",
    "Appenders": {
  "appender": [
    {
      "type": "RollingFile",
      "name": "debugFile",
      "fileName": "${env:log_dir}/my_main_log",
      "filePattern": "${env:log_dir  }/my_main_backup-%d{MM-dd-yy-HH-mm-ss}-%i.log.gz",
      "PatternLayout": {
        "pattern": "%d{yyyy-MM-dd HH:mm:ss,nnn} [%-5p] [%5t] [%c{3}:%L] - %m%n"
      },
      "Policies": {
        "SizeBasedTriggeringPolicy": {
          "size": "10 MB"
        }
      },
      "DefaultRolloverStrategy": {
        "max": "10"
      },
      "ThresholdFilter": {
        "level": "${env:customDebug:-info}"
      }
    },
    {
      "type": "RollingFile",
      "name": "errorFile",
      "fileName": "${env:log_dir}/errors.log",
      "filePattern": "${env:log_dir}/errors_backup-%d{MM-dd-yy-HH-mm-ss}-%i.log.gz",
      "PatternLayout": {
        "pattern": "%d{yyyy-MM-dd HH:mm:ss,nnn} [%-5p] [%5t] [%c{1}:%L] - %m%n"
      },
      "Policies": {
        "SizeBasedTriggeringPolicy": {
          "size": "10 MB"
        }
      },
      "DefaultRolloverStrategy": {
        "max": "10"
      },
      "ThresholdFilter": {
        "level": "ERROR",
        "onMatch": "ACCEPT",
        "onMisMatch": "DENY"
      }
    }
  ]
},
"Loggers": {
  "logger": [
    {
      "name": "KitLogger",
      "level": "info",
      "additivity": "false",
      "AppenderRef": [
        {
          "ref": "debugFile"
        },
        {
          "ref": "errorFile"
        }
      ]
    }
  ],
  "root": {
    "level": "debug",
    "appender-ref": {
      "ref": "debugFile"
    }
  }
}
  }
}
1

There are 1 best solutions below

7
On BEST ANSWER

If you just want to pick log file location using environment variables, you can do so using configuration file alone as describe in log4j2 documentation

Considering your environment variable is log_dir=D:/logs/. Then you can change your configuration like below -

{
    "configuration": {
        "name": "RollingConfig",
        "ThresholdFilter": { "level": "info" },
        "properties": {
            "property": {
                "name": "basePath",
                "value": "${env:log_dir}"
             }
        },
        "appenders": {
            "RollingFile": {
                "name": "debugFile",
                "fileName": "${basePath}my_main.log",
                "filePattern": "${basePath}my_main_%d{yyyyMMdd}.log.gz",
                "PatternLayout": { "pattern": "%d{yyyy-MM-dd HH:mm:ss} %-5p [%5T] %c{1}:%L - %m%n" },
                "Policies": {
                    "SizeBasedTriggeringPolicy": { "size": "10 MB" }
                },
               "DefaultRolloverStrategy": { "max": "10"  }
            },
            "RollingFile": {
                "name": "errorFile",
                "fileName": "${basePath}my_err.log",,
                "filePattern": "${basePath}my_err_%d{yyyyMMdd}.log.gz",
                "thresholdFilter": {
                    "level": "ERROR",
                    "onMatch": "ACCEPT",
                    "onMisMatch": "DENY"
                },
                "PatternLayout": { "pattern": "%d{yyyy-MM-dd HH:mm:ss} %-5p [%5T] %c{1}:%L - %m%n" },
                "Policies": {
                     "SizeBasedTriggeringPolicy": {  "size": "10 MB" }
                },
                "DefaultRolloverStrategy": {"max": "10"}
            }
        },
        "loggers": {
            "logger": {
                 "name": "mainLogger",
                 "level": "info",
                 "additivity": "false",
                 "appender-ref": [ 
                                 {"ref": "debugFile"}, 
                                 { "ref":"errorFile"}
                                 ]
            },
            "root": {
                "level": "info",
                 "appender-ref": [ 
                                 {"ref": "debugFile" }, 
                                 { "ref":"errorFile" }
                                 ]
             }
          }
       }
}