Configure log4j2 programmatically using ConfigurationFactory - java

I'm trying to configure and set up Log4j2 only through using ConfigurationFactory and this reference. The code I'm using is as follows:
public class LoggingConfiguration {
public static final String PATTERN_LAYOUT = "[%d] [%t] [%-5level] - %msg (%logger{1}:%L) %n%throwable";
public static final String LOG_FILE_NAME = "app.log";
public static final String LOG_FILE_NAME_PATTERN = LOG_FILE_NAME + "-yyyy.MM.dd";
static {
ConfigurationFactory.setConfigurationFactory(new Log4j2ConfigurationFactory());
}
/**
* Just to make JVM visit this class to initialize the static parts.
*/
public static void configure() {
}
#Plugin(category = "ConfigurationFactory", name = "Log4j2ConfigurationFactory")
#Order(0)
public static class Log4j2ConfigurationFactory extends ConfigurationFactory {
#Override
protected String[] getSupportedTypes() {
return null;
}
#Override
public Configuration getConfiguration(ConfigurationSource source) {
return new Log4j2Configuration();
}
#Override
public Configuration getConfiguration(String name, URI configLocation) {
return new Log4j2Configuration();
}
}
private static class Log4j2Configuration extends DefaultConfiguration {
public Log4j2Configuration() {
setName("app-log4j2");
String root = System.getProperty("APP_ROOT", "/tmp");
if (!root.endsWith("/")) {
root += "/";
}
// MARKER
Layout<? extends Serializable> layout = PatternLayout.createLayout(PATTERN_LAYOUT, null, null, null, null);
String oneDay = TimeUnit.DAYS.toMillis(1) + "";
String oneMB = (1024 * 1024) + "";
final TimeBasedTriggeringPolicy timeBasedTriggeringPolicy = TimeBasedTriggeringPolicy.createPolicy(oneDay,
"true");
final SizeBasedTriggeringPolicy sizeBasedTriggeringPolicy = SizeBasedTriggeringPolicy.createPolicy(oneMB);
final CompositeTriggeringPolicy policy = CompositeTriggeringPolicy.createPolicy(timeBasedTriggeringPolicy,
sizeBasedTriggeringPolicy);
final DefaultRolloverStrategy strategy = DefaultRolloverStrategy.createStrategy("7", "1", null,
Deflater.DEFAULT_COMPRESSION + "", this);
Appender appender = RollingFileAppender.createAppender(root + LOG_FILE_NAME, LOG_FILE_NAME_PATTERN, "true",
"app-log-file-appender", "true", "true", policy, strategy, layout, null, null, null, null, null);
addAppender(appender);
getRootLogger().addAppender(appender, Level.INFO, null);
}
}
}
Note that
it extends BaseConfiguration that already configures console by default
it tries to add a rolling file appender to the root logger
I get the following exception:
Exception in thread "main" java.lang.IllegalStateException: Pattern does not contain a date
at org.apache.logging.log4j.core.appender.rolling.PatternProcessor.getNextTime(PatternProcessor.java:91)
at org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy.initialize(TimeBasedTriggeringPolicy.java:49)
at org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy.initialize(CompositeTriggeringPolicy.java:43)
at org.apache.logging.log4j.core.appender.rolling.RollingFileManager.<init>(RollingFileManager.java:58)
at org.apache.logging.log4j.core.appender.rolling.RollingFileManager$RollingFileManagerFactory.createManager(RollingFileManager.java:297)
at org.apache.logging.log4j.core.appender.rolling.RollingFileManager$RollingFileManagerFactory.createManager(RollingFileManager.java:267)
at org.apache.logging.log4j.core.appender.AbstractManager.getManager(AbstractManager.java:71)
at org.apache.logging.log4j.core.appender.OutputStreamManager.getManager(OutputStreamManager.java:65)
at org.apache.logging.log4j.core.appender.rolling.RollingFileManager.getFileManager(RollingFileManager.java:78)
at org.apache.logging.log4j.core.appender.RollingFileAppender.createAppender(RollingFileAppender.java:175)
at com.narmnevis.papyrus.LoggingConfiguration$Log4j2Configuration.<init>(LoggingConfiguration.java:79)
at com.narmnevis.papyrus.LoggingConfiguration$Log4j2ConfigurationFactory.getConfiguration(LoggingConfiguration.java:55)
at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:377)
at org.apache.logging.log4j.core.LoggerContext.start(LoggerContext.java:149)
at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:85)
at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:34)
at org.apache.logging.log4j.LogManager.getContext(LogManager.java:200)
at org.slf4j.helpers.Log4jLoggerFactory$PrivateManager.getContext(Log4jLoggerFactory.java:104)
at org.slf4j.helpers.Log4jLoggerFactory.getContext(Log4jLoggerFactory.java:90)
at org.slf4j.helpers.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:46)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:270)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:281)
at com.narmnevis.papyrus.Main.<init>(Main.java:12)
at com.narmnevis.papyrus.Main.main(Main.java:21)
If I comment out the code after MARKER in above code, it works but it seems that I'm missing something to configure a rolling file appender. What should I do to fix this?

In log4j 2.x you have to specify the date format in this way
public static final String LOG_FILE_NAME_PATTERN = LOG_FILE_NAME + "-%d{dd-MM-yyy}";
% marks the beginning of a format
d means that it is a date format (you can also use date)
within the curly braces {} you define the formatter's options. In this case the date format. You can use everything that a SimpleDateFormat would accept.
In addition you can also use:
%d{ABSOLUTE} -> HH:mm:ss,SSS
%d{COMPACT} -> yyyyMMddHHmmssSSS
%d{DATE} -> dd MMM yyyy HH:mm:ss,SSS
%d{ISO8601_BASIC} -> yyyyMMdd HHmmss,SSS
%d{ISO8601} -> yyyy-MM-dd HH:mm:ss,SSS
Note: This information is based on log4j 2.0-beta9 (the current release). Since it is a beta version it might change slightly.

Related

Initiate Log4j2 RollingFileAppender in Java

I'm using log4j2.
I want to create a RollingFileAppender which rotates the log file on a daily basis.
The name of the logfile is unknown until the application has started (the logfile name is assembled from the application config).
That is why I need to add a RollingFileAppender at runtime.
I have the following code:
public static final ConfigurationBuilder<BuiltConfiguration> BUILDER = ConfigurationBuilderFactory.newConfigurationBuilder
public void initFileLoggerWithFilePattern(final String pattern) {
final LoggerComponentBuilder logger = BUILDER.newLogger("FileLogger", Level.DEBUG);
final AppenderComponentBuilder appender = createFileAppenderWithFilePattern(pattern);
BUILDER.add(appender);
logger.add(BUILDER.newAppenderRef("RollingFileAppender"));
BUILDER.add(logger);
Configurator.initialize(BUILDER.build());
}
public AppenderComponentBuilder createFileAppenderWithFilePattern(final String pattern) {
final AppenderComponentBuilder acb = BUILDER.newAppender("RollingFileAppender", "RollingFile");
acb.addAttribute("fileName", pattern);
acb.addAttribute("filePattern", pattern);
acb.addComponent(createPatternLayout());
acb.addComponent(createTimeBasedTriggeringPolicy());
return acb;
}
public LayoutComponentBuilder createPatternLayout() {
final LayoutComponentBuilder lcb = BUILDER.newLayout("PatternLayout");
lcb.addAttribute("pattern", "%d{yyyy-MM-dd HH:mm:ss.SSS}{GMT}Z %m");
return lcb;
}
public ComponentBuilder createTimeBasedTriggeringPolicy() {
final ComponentBuilder policies = BUILDER.newComponent("Policies");
final ComponentBuilder policy = BUILDER.newComponent("TimeBasedTriggeringPolicy");
policies.addComponent(policy);
return policies;
}
The problem is that this code changes absolutely nothing. No appender as well as no Logger is being added to the configuration. The "FileLogger" that was created programmatically is not available.
I used this code to print the loggers and Appenders after executing the code above.
private void printLog4jConfig() {
final LoggerContext context = (LoggerContext) LogManager.getContext(false);
final Configuration config = context.getConfiguration();
// Print appenders
for(Appender app : config.getAppenders().values()) {
System.out.println(app.getName());
}
// Print Loggers and their Appenders
for(LoggerConfig lc : config.getLoggers().values()) {
System.out.println(lc);
for(Appender app : lc.getAppenders().values()) {
System.out.println(" " + app);
}
}
}
Output:
Appenders
-------------
STDOUT
Loggers
-------------
root
STDOUT
Console
STDOUT
My Question:
What is wrong with my code? Why is my Appender as well as my Logger not added? Respectively why is the configuration not being refreshed / updated ?
How can I add a RollingFileAppender as well as a logger to the log4j2 configuration during runtime?
I found the solution to my problem.
Instead using
Configurator.initialize(BUILDER.build())
I had to use
Configurator.reconfigure(BUILDER.build());
This reloaded the configuration and i was able to see and use my appender and logger.

how to create a log4j custom appender and control the filename

My company uses a software package that reads in log files from our servers, parses them, and spits performance data into a database. We dont have access / permission to modify the source code for the app that reads the files but we do have access to the code that writes the files. I need to change the way the log files are being written and I would like to use log4j (so I can use an AsyncAppender). The program expects a few things:
1). There should be 10 log files that roll and each log file will be one day of logs. The files need to be named 0 through 9 and I need to be able to programatically set the file name and when they roll based on the server time.
2). Essentially when generating the 11th log file it should delete the oldest one and start writing to that one.
3). When a new log file is generated I need to be able to insert a timestamp as the first line of the file (System.currentTimeMillis()).
Is it possible to meet the above requirements with a custom log4j file appender? Ive looked at DailyRollingFileAppender but cant seem to figure out how to control the file names exactly like I need to. Also I cant seem to figure out how to write the first line in the log when it is generated (for example is there some callback function I can register when a new log file gets rolled in)?
I think you can achieve first 2 with
using RollingFileAppender and specifying FixedWindowRollingPolicy for RollingPolicy
as for the #3 you can always write your own handler
For the sake of posterity. I used the below class as my custom rolling policy
import org.apache.log4j.rolling.RollingPolicyBase;
import org.apache.log4j.rolling.RolloverDescription;
import org.apache.log4j.rolling.RolloverDescriptionImpl;
import org.apache.log4j.rolling.TriggeringPolicy;
import org.apache.log4j.Appender;
import org.apache.log4j.spi.LoggingEvent;
public final class CustomRollingPolicy extends RollingPolicyBase
implements TriggeringPolicy
{
private short curFileId = -1;
private String lastFileName = null;
static private final long FILETIMEINTERVAL = 86400000l;
static private final int NUM_FILES = 10;//86400000l;
public String folderName = "";
public String getFolderName() {
return folderName;
}
public void setFolderName(String folderName) {
this.folderName = folderName;
}
private short calculateID(long startTime) {
return (short) ((startTime / FILETIMEINTERVAL) % NUM_FILES);
}
public String getCurrentFileName()
{
StringBuffer buf = new StringBuffer();
buf.append(folderName);
buf.append(calculateID(System.currentTimeMillis()));
return buf.toString();
}
public void activateOptions()
{
super.activateOptions();
this.lastFileName = getCurrentFileName();
}
public RolloverDescription initialize(String currentActiveFile, boolean append)
{
curFileId = this.calculateID(System.currentTimeMillis());
lastFileName = getCurrentFileName();
String fileToUse = activeFileName != null? activeFileName: currentActiveFile != null?currentActiveFile:lastFileName;
return new RolloverDescriptionImpl(fileToUse, append, null, null);
}
public RolloverDescription rollover(String currentActiveFile)
{
curFileId = this.calculateID(System.currentTimeMillis());
String newFileName = getCurrentFileName();
if (newFileName.equals(this.lastFileName))
{
return null;
}
String lastBaseName = this.lastFileName;
String nextActiveFile = newFileName;
if (!currentActiveFile.equals(lastBaseName))
{
nextActiveFile = currentActiveFile;
}
this.lastFileName = newFileName;
return new RolloverDescriptionImpl(nextActiveFile, false, null, null);
}
public boolean isTriggeringEvent(Appender appender, LoggingEvent event, String filename, long fileLength)
{
short fileIdForCurrentServerTime = this.calculateID(System.currentTimeMillis());
return curFileId != fileIdForCurrentServerTime;
}
}
And here is the appender config in my log4j xml file:
<!-- ROLLING FILE APPENDER FOR RUM LOGS -->
<appender name="rumRollingFileAppender" class="org.apache.log4j.rolling.RollingFileAppender">
<rollingPolicy class="com.ntrs.wpa.util.CustomRollingPolicy">
<param name="folderName" value="C:/bea-portal-10.3.2/logs/"/>
<param name="FileNamePattern" value="C:/bea-portal-10.3.2/logs/foo.%d{yyyy-MM}.gz"/>
</rollingPolicy>
<layout class="com.ntrs.els.log4j.AppServerPatternLayout">
<param name="ConversionPattern" value="%m%n" />
</layout>
</appender>

How to change .properties file using apache.commons.configuration

I have an app where I filter messages according to some rules(existing some keywords or regexps). These rules are to be stored in .properties file(as they must be persistent). I've figured out how to read data from this file. here is the part of the code:
public class Config {
private static final Config ourInstance = new Config();
private static final CompositeConfiguration prop = new CompositeConfiguration();
public static Config getInstance() {
return ourInstance;
}
public Config(){
}
public synchronized void load() {
try {
prop.addConfiguration(new SystemConfiguration());
System.out.println("Loading /rules.properties");
final PropertiesConfiguration p = new PropertiesConfiguration();
p.setPath("/home/mikhail/bzrrep/DLP/DLPServer/src/main/resources/rules.properties");
p.load();
prop.addConfiguration(p);
} catch (ConfigurationException e) {
e.printStackTrace();
}
final int processors = prop.getInt("server.processors", 1);
// If you don't see this line - likely config name is wrong
System.out.println("Using processors:" + processors);
}
public void setKeyword(String customerId, String keyword){
}
public void setRegexp(String customerId, String regexp)
{}
}
as you see I'm going to add values to some properties. Here is the .properties file itself:
users = admin, root, guest
users.admin.keywords = admin
users.admin.regexps = test-5, test-7
users.root.keywords = root
users.root.regexps = *
users.guest.keywords = guest
users.guest.regexps =
I have a GUI for user to add keywords and regexps to this config. so, how to implement methods setKeyword and setRegexp?
The easyest way I found is to read the current values of the property to the String[], add there a new value and set property.
props.setProperty(fieldName, values);

configuring log with Spring Application

I have developed a spring application, I want to configure it with apache log4j, have downloaded it and put the jar in project's class path. Below is my log4j.Properties file.
# Root logger option
log4j.rootLogger=INFO, file
# Direct log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=C\:\\loging.log
log4j.appender.file.MaxFileSize=1MB
log4j.appender.file.MaxBackupIndex=1
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
And below is my main spring application class.
import org.apache.log4j.Logger;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;
public class DrawingClass {
public static void main(String args[])
{
//without dependency injection
/*Triangle t1 = new Triangle();
t1.draw();*/
//with dependency injection
BeanFactory factory = new XmlBeanFactory(new FileSystemResource("Spring.xml"));
Triangle t1 =(Triangle) factory.getBean("triangle");
t1.draw();
}
}
Please advise if I want to put the log.info in my above main class what modifications I need to do in my main class and also please advise what modifications I need to done to call log4j in my main class?
come up with this solution and it works ..the edited log4j.properties file is
### direct messages to file or.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=C:/logs/s.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1} - %m%n
log4j.appender.file.append=true
### set log levels - for more verbose logging change 'info' to 'debug' ##
log4j.rootCategory=ALL, file
log4j.logger.Demo=\=debug
log4j.logger.org.eclipse=debug
and the way to callit from main class is
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;
public class DrawingClass {
/* Get actual class name to be printed on */
static final Logger log = Logger.getLogger(DrawingClass.class);
public static void main(String args[])
{PropertyConfigurator.configure("log4j.properties");
//without dependency injection
/*Triangle t1 = new Triangle();
t1.draw();*/
log.info("Before execution");
//with dependency injection
BeanFactory factory = new XmlBeanFactory(new FileSystemResource("Spring.xml"));
Triangle t1 =(Triangle) factory.getBean("triangle");
log.info("Hello this is an info message");
t1.draw();
log.info("after object execution");
}
}
If there is any other better way then please advise .
Can you try adding this line to your class -
public class DrawingClass {
static final Logger log = Logger.getLogger(DrawingClass.class);
public static void main(String args[])
{
//without dependency injection
/*Triangle t1 = new Triangle();
t1.draw();*/
log.info("Before execution");
//with dependency injection
BeanFactory factory = new XmlBeanFactory(new FileSystemResource("Spring.xml"));
Triangle t1 =(Triangle) factory.getBean("triangle");
t1.draw();
}
}
Now let me know if anything gets added to the log.
This link might help you - http://www.dzone.com/tutorials/java/log4j/sample-log4j-properties-file-configuration-1.html
For using logging in my project I made such things:
1) Defined special annotation that should mark fields where logger should be injected:
#Retention(RUNTIME)
#Target(FIELD)
#Documented
public #interface InjectLogger {
}
2) Then created special BeanPostProcessor for injected logger into annotated field:
#Component(value="loggerInjector")
public class LoggerInjector implements BeanPostProcessor {
#Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
#Override
public Object postProcessBeforeInitialization(final Object bean, String beanName)
throws BeansException {
ReflectionUtils.doWithFields(bean.getClass(), new FieldCallback() {
public void doWith(Field field) throws IllegalArgumentException,
IllegalAccessException {
// make the field accessible if defined private
ReflectionUtils.makeAccessible(field);
if (field.getAnnotation(InjectLogger.class) != null) {
Logger log = LoggerFactory.getLogger(bean.getClass());
field.set(bean, log);
}
}
});
return bean;
}
}
3) After this in necessary bean mark property where logger should be injected by #InjectLogger annotation and use this logger in your code.
#InjectLogger
private Logger logger;
public void doSomething(...) {
try{
...
} catch (Exception e) {
logger.error("bla bla bla", e);
}
}
In my project I use slf4j with log4j as concrete implementation. But with log4j it will be similar.
Also you need to know that by default all Spring libs using common-logging. And if you want that Spring libs write their log to your file you should use special additionla lib. You can get them, as I remember, from appache site. For slf4j such lib is named jcl-over-slf4j-1.6.4.jar.
EDIT 2:
Also in spring the good practise is to use AOP for logging. Here is an example of simplified Aspect:
#Component
#Aspect
#Order(value=2)
public class LoggingAspect {
#Around("execution(* com.blablabla.server..*.*(..))")
public Object logMethod(ProceedingJoinPoint joinPoint) throws Throwable{
final Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass().getName());
Object retVal = null;
try {
StringBuffer startMessageStringBuffer = new StringBuffer();
startMessageStringBuffer.append("Start method ");
startMessageStringBuffer.append(joinPoint.getSignature().getName());
startMessageStringBuffer.append("(");
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
startMessageStringBuffer.append(args[i]).append(",");
}
if (args.length > 0) {
startMessageStringBuffer.deleteCharAt(startMessageStringBuffer.length() - 1);
}
startMessageStringBuffer.append(")");
logger.trace(startMessageStringBuffer.toString());
StopWatch stopWatch = new StopWatch();
stopWatch.start();
retVal = joinPoint.proceed();
stopWatch.stop();
StringBuffer endMessageStringBuffer = new StringBuffer();
endMessageStringBuffer.append("Finish method ");
endMessageStringBuffer.append(joinPoint.getSignature().getName());
endMessageStringBuffer.append("(..); execution time: ");
endMessageStringBuffer.append(stopWatch.getTotalTimeMillis());
endMessageStringBuffer.append(" ms;");
logger.trace(endMessageStringBuffer.toString());
} catch (Throwable ex) {
StringBuffer errorMessageStringBuffer = new StringBuffer();
// Create error message
logger.error(errorMessageStringBuffer.toString(), e)
throw ex;
}
return retVal;
}
}
# LOG4J configuration
log4j.rootLogger= DEBUG, INFO, Appender1, Appender2
log4j.appender.Appender1=org.apache.log4j.ConsoleAppender
log4j.appender.Appender1.layout=org.apache.log4j.PatternLayout
log4j.appender.Appender1.layout.ConversionPattern=%-7p %d [%t] %c %x - %m%n
log4j.appender.Appender2=org.apache.log4j.FileAppender
log4j.appender.Appender2.File=D:/Project Log/Demo/demo.log
log4j.appender.Appender2.layout=org.apache.log4j.PatternLayout
log4j.appender.Appender2.layout.ConversionPattern=%-7p %d [%t] %c %x - %m%n
Write this code in log4j.properties which is in Resources folder of src folder.
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
Write this above code in porm.xml file or download jar for this dependency.
<context:property-placeholder location="classpath:log4j.properties" />
write this above code between and in your spring-config.xml
package com.apmc.controller;
import org.apache.log4j.Logger;
import java.text.DateFormat;
import java.util.Date;
import com.apmc.Generic.RandomGenerator;//This my own made class So You need to create //RandomGenerator for use it
#Controller
public class StateController {
private static Logger logger = Logger.getLogger(StateController.class);
DateFormat df = new SimpleDateFormat("ddMMyyHHmmss");
Date dateobj = new Date();
int randNum = RandomGenerator.randInt(1000, 9999);
String successMsg = "", errorMsg = "";
#Autowired
StateService stateService;
List<State> newList = new ArrayList();
#RequestMapping(value = "/Admin/admin/NewState_form")
public ModelAndView stateForm(#ModelAttribute State state) {
try {
logger.info("\n stateForm Started \n errorcode : "+errorcode);
newList = stateService.loadAll();
logger.info("\n stateForm Completed");
errorMsg = "";
} catch (Exception e) {
errorcode = ""+df.format(dateobj)+randNum;
errorMsg = " New State Form Error \n Please contact Admin and errorcode:" +errorcode;
successMsg = "";
logger.error("error code for stateForm in StateController" +df.format(dateobj)+" errorcode: "+errorcode);
}
return new ModelAndView("state").addObject("editState", new State())
.addObject("errorMsg", errorMsg) .addObject("showStateList",newList)
.addObject("successMsg", successMsg);
}
}
Above example for how to use log in Controller or any Java Class
Here I made for error Tracking create error code show for commmunicate with error using RandomGenerator.java write as below given
package com.apmc.Generic;
import java.util.Random;
public class RandomGenerator {
/**
* Returns a pseudo-random number between min and max, inclusive.
* The difference between min and max can be at most
* <code>Integer.MAX_VALUE - 1</code>.
*
* #param min Minimum value
* #param max Maximum value. Must be greater than min.
* #return Integer between min and max, inclusive.
* #see java.util.Random#nextInt(int)
*/
public static int randInt(int min, int max) {
// NOTE: Usually this should be a field rather than a method
// variable so that it is not re-seeded every call.
Random rand = new Random();
// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
}

How to configure Logback with Java code to set log level?

I want to use default SLF4J + Logback configuration except setting org.springframework.data.document.mongodb logging level to DEBUG.
How can I do it with Java code?
I'm not using XML, and this decision made at runtime.
The following works for me but generally this is not a good idea. Your code will depend on Logback (you can't choose another logging framework behind SLF4J).
final org.slf4j.Logger logger =
org.slf4j.LoggerFactory.getLogger("test.package");
if (!(logger instanceof ch.qos.logback.classic.Logger)) {
return;
}
ch.qos.logback.classic.Logger logbackLogger =
(ch.qos.logback.classic.Logger) logger;
logbackLogger.setLevel(ch.qos.logback.classic.Level.TRACE);
logger.trace("some log");
Depending to logback-classic is not a good idea as #palacsint stated. You can achieve what you want using Java's Reflection API. Note that this approach puts some overhead to your program because of use of reflection.
Usage:
LogbackUtils.setLogLevel("com.stackoverflow.sample", "DEBUG")
Code:
public static final String LOGBACK_CLASSIC = "ch.qos.logback.classic";
public static final String LOGBACK_CLASSIC_LOGGER = "ch.qos.logback.classic.Logger";
public static final String LOGBACK_CLASSIC_LEVEL = "ch.qos.logback.classic.Level";
private static final Logger logger = LoggerFactory.getLogger(LogbackUtils.class);
/**
* Dynamically sets the logback log level for the given class to the specified level.
*
* #param loggerName Name of the logger to set its log level. If blank, root logger will be used.
* #param logLevel One of the supported log levels: TRACE, DEBUG, INFO, WARN, ERROR, FATAL,
* OFF. {#code null} value is considered as 'OFF'.
*/
public static boolean setLogLevel(String loggerName, String logLevel)
{
String logLevelUpper = (logLevel == null) ? "OFF" : logLevel.toUpperCase();
try
{
Package logbackPackage = Package.getPackage(LOGBACK_CLASSIC);
if (logbackPackage == null)
{
logger.info("Logback is not in the classpath!");
return false;
}
// Use ROOT logger if given logger name is blank.
if ((loggerName == null) || loggerName.trim().isEmpty())
{
loggerName = (String) getFieldValue(LOGBACK_CLASSIC_LOGGER, "ROOT_LOGGER_NAME");
}
// Obtain logger by the name
Logger loggerObtained = LoggerFactory.getLogger(loggerName);
if (loggerObtained == null)
{
// I don't know if this case occurs
logger.warn("No logger for the name: {}", loggerName);
return false;
}
Object logLevelObj = getFieldValue(LOGBACK_CLASSIC_LEVEL, logLevelUpper);
if (logLevelObj == null)
{
logger.warn("No such log level: {}", logLevelUpper);
return false;
}
Class<?>[] paramTypes = { logLevelObj.getClass() };
Object[] params = { logLevelObj };
Class<?> clz = Class.forName(LOGBACK_CLASSIC_LOGGER);
Method method = clz.getMethod("setLevel", paramTypes);
method.invoke(loggerObtained, params);
logger.debug("Log level set to {} for the logger '{}'", logLevelUpper, loggerName);
return true;
}
catch (Exception e)
{
logger.warn("Couldn't set log level to {} for the logger '{}'", logLevelUpper, loggerName, e);
return false;
}
}
// getFieldValue() method omitted for bravity from here,
// but available at GitHub link below.
Full code including tests: Github Gist.

Categories