I have 2 configuration files for logging,
config1.properties and
config2.properties
When I load the config1.properties and log something, the format is correct, but right after, when I load the second config file, the changes are not reflected. Here is my code:
System.setProperty("java.util.logging.config.file", "config1.properties");
logger = Logger.getLogger(this.getClass().getSimpleName());
logger.info("Message 1");
System.setProperty("java.util.logging.config.file", "config2.properties");
LogManager logManager = LogManager.getLogManager();
logManager.readConfiguration();
logger = Logger.getLogger("NewLogger");
logger.info("Message 2");
I have set the configuration in config2.properties to log messages in 2 lines, however the message is still showing in one line.
Any ideas why the new configuration is not taking effect? I am sure that my config files are correct, because I tried loading config2 before config1, and that showed my logged messages in 2 lines.
Here is the logged result:
[01-13-2014 16:48:56:186] LoggerUnitTest INFO: Message 1
[01-13-2014 16:48:56:195] LoggerUnitTest INFO: Message 2
It should show up as :
[01-13-2014 16:48:56:186] LoggerUnitTest INFO: Message 1
[01-13-2014 16:48:56:195] LoggerUnitTest INFO:
Message 2
Below are the config files I am using:
config1.properties
handlers=java.util.logging.ConsoleHandler
.level= FINE
# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.ConsoleHandler.formatter.format = [%1$tm-%1$td-%1$tY %1$tk:%1$tM:%1$tS:%1$tL] %4$s: %5$s%6$s%n
config2.properties
handlers=java.util.logging.ConsoleHandler
.level= FINE
# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
# Note that this line is different from the line in config1
java.util.logging.ConsoleHandler.formatter.format = [%1$tm-%1$td-%1$tY %1$tk:%1$tM:%1$tS:%1$tL] %n %4$s: %5$s%6$s%n
This works for me:
Test.java
import java.util.logging.LogManager;
import java.util.logging.Logger;
public class Test {
public static void main(String[] args) throws Exception {
System.setProperty("java.util.logging.config.file", "config1.properties");
Logger logger = Logger.getLogger(Test.class.getSimpleName());
logger.info("Message 1");
System.setProperty("java.util.logging.config.file", "config2.properties");
LogManager logManager = LogManager.getLogManager();
logManager.readConfiguration();
logger = Logger.getLogger(Test.class.getSimpleName());
logger.info("Message 2");
}
}
config1.properties
handlers=java.util.logging.ConsoleHandler
.level= FINE
# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
config2.properties
handlers=java.util.logging.ConsoleHandler
.level= FINE
# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.XMLFormatter
javac Test.java
java Test
Jan 13, 2014 8:51:20 PM Test main
INFO: Message 1
<?xml version="1.0" encoding="windows-1252" standalone="no"?>
<!DOCTYPE log SYSTEM "logger.dtd">
<log>
<record>
<date>2014-01-13T20:51:20</date>
<millis>1389664280170</millis>
<sequence>1</sequence>
<logger>Test</logger>
<level>INFO</level>
<class>Test</class>
<method>main</method>
<thread>10</thread>
<message>Message 2</message>
</record>
Look at the Documentation of the Logger.getLogger(String name).documentation
it says
If a new logger is created its log level will be configured based on
the LogManager configuration and it will configured to also send
logging output to its parent's handlers. It will be registered in the
LogManager global namespace.
So Even though set a new configuration properties your logger instance have the old configuration
try getting a new instance by calling following line again
logger = Logger.getLogger("new Name");
may be you might have to change the input parameter name differently. or it will return the old logger object
EDIT
Here the sample code i tried
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
public class LoggingTest {
public static void main(String[] args) {
System.setProperty("java.util.logging.config.file", "config1.properties");
Logger logger = Logger.getLogger(LoggingTest.class.getSimpleName());
logger.info("Message 1");
System.setProperty("java.util.logging.config.file", "config2.properties");
LogManager logManager = LogManager.getLogManager();
try {
logManager.readConfiguration();//logManager.readConfiguration(new FileInputStream(new File("config2.properties")));
} catch (IOException ex) {
Logger.getLogger(LoggingTest.class.getName()).log(Level.SEVERE, null, ex);
} catch (SecurityException ex) {
Logger.getLogger(LoggingTest.class.getName()).log(Level.SEVERE, null, ex);
}
logger = Logger.getLogger("NewLogger");
logger.info("Message 2");
}
}
Related
I am facing an issue with configuring log4j2 logs programmatically.
Please see the below code, I am creating 2 objects of the class App3, and I want to create 2 debug log files(a log file per App3 object), thereafter each object should be able to log to corresponding log file.
But my code is logging all the logs to the second log file after 2nd log is created. Can someone help on this.
Output of the program
file Name: app3_logger1.log_debug.log
2020-06-16 16:19:31,100 DEBUG app3_logger1.log [main] Hello from Log4j 2app3_logger1
file Name: app3_logger2.log_debug.log
2020-06-16 16:19:31,211 DEBUG app3_logger2.log [main] Hello from Log4j 2app3_logger2
2020-06-16 16:19:31,216 DEBUG app3_logger2.log [main] Hello from Log4j 2app3_logger2
2020-06-16 16:19:31,216 DEBUG app3_logger1.log [main] Hello from Log4j 2app3_logger1
2020-06-16 16:19:31,216 DEBUG app3_logger1.log [main] Hello from Log4j 2app3_logger1
2020-06-16 16:19:31,217 DEBUG app3_logger2.log [main] Hello from Log4j 2app3_logger2
Java Class - you just need to add log4j2 dependencies to compile
public class App3 {
public Logger logger;
public static void main(String[] args) {
App3 app1 = new App3();
app1.initializeYourLogger("app3_logger1.log", "%d %p %c [%t] %m%n");
app1.testProg("app3_logger1");
App3 app2 = new App3();
app2.initializeYourLogger("app3_logger2.log", "%d %p %c [%t] %m%n");
app2.testProg("app3_logger2");
app2.testProg("app3_logger2");
app1.testProg("app3_logger1");
app1.testProg("app3_logger1");
app2.testProg("app3_logger2");
}
public void testProg(String s) {
logger.debug("Hello from Log4j 2" + s);
}
public void initializeYourLogger(String fileName, String pattern) {
this.logger = LogManager.getLogger(fileName);
ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
builder.setStatusLevel(Level.DEBUG);
builder.setConfigurationName(fileName);
AppenderComponentBuilder componentBuilder = builder.newAppender("log", "File");
componentBuilder.add(builder.newLayout("PatternLayout").addAttribute("pattern", pattern));
RootLoggerComponentBuilder rootLogger = builder.newRootLogger(Level.DEBUG);
LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout").addAttribute("pattern", pattern);
ComponentBuilder triggeringPolicy = builder.newComponent("Policies")
.addComponent(builder.newComponent("SizeBasedTriggeringPolicy").addAttribute("size", "10MB"));
componentBuilder = builder.newAppender("LogToRollingErrorFile", "RollingFile")
.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.DENY)
.addAttribute("level", Level.ERROR))
.addAttribute("fileName", fileName + "_error.log")
.addAttribute("filePattern", fileName + "-%d{MM-dd-yy-HH-mm-ss}_error.log").add(layoutBuilder)
.addComponent(triggeringPolicy);
builder.add(componentBuilder);
componentBuilder = builder.newAppender("LogToRollingDebugFile", "RollingFile")
.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.DENY)
.addAttribute("level", Level.DEBUG))
.addAttribute("fileName", fileName + "_debug.log")
.addAttribute("filePattern", fileName + "-%d{MM-dd-yy-HH-mm-ss}_debug.log").add(layoutBuilder)
.addComponent(triggeringPolicy);
builder.add(componentBuilder);
AppenderRefComponentBuilder rollingError = rootLogger.getBuilder().newAppenderRef("LogToRollingErrorFile");
AppenderRefComponentBuilder rollingDebug = rootLogger.getBuilder().newAppenderRef("LogToRollingDebugFile");
rootLogger.add(rollingError);
rootLogger.add(rollingDebug);
builder.add(rootLogger);
Configurator.reconfigure(builder.build());
}
}
This is exactly what I want to do in log4j older version, I am still struggling with log4j2,
private void initLogger(String serviceName, String instance) throws IOException {
String loggerName = serviceName+"_"+instance;
this.logger = Logger.getLogger(loggerName);
this.logger.removeAllAppenders();
PatternLayout layout = new PatternLayout();
layout.setConversionPattern("%d: %m%n");
String loggingFolder = this.properties.getLoggingFolder();
String debugFileName = loggingFolder+"/"+loggerName+"_debug.log";
String errorFileName = loggingFolder+"/"+loggerName+"_error.log";
RollingFileAppender debugAppender = new RollingFileAppender(layout, debugFileName, true);
debugAppender.setThreshold(Level.DEBUG);
debugAppender.setMaxFileSize("10000000");
debugAppender.setMaxBackupIndex(49);
logger.addAppender(debugAppender);
RollingFileAppender errorAppender = new RollingFileAppender(layout, errorFileName, true);
errorAppender.setThreshold(Level.ERROR);
errorAppender.setMaxFileSize("10000000");
errorAppender.setMaxBackupIndex(49);
logger.addAppender(debugAppender);
}
Actually, I am quite sure your Logger is being updated correctly. The problem is that both application instances are going to use the same Logging configuration.
If you look at Log4j's architecture you will see that the Loggers and the configuration are anchored in the LoggerContext. By default, Log4j uses the ClassLoaderContextSelector, which means that every ClassLoader can have its own LoggerContext. Your sample application only has a single ClassLoader and so will only have a single LoggerContext and, therefore, only a single Configuration.
So when you reconfigured the second time you simply replaced the prior configuration with the new one. Since the root logger is handling all log events it will route the events from both Loggers you have created to the file created in the second configuration.
If you want logs to end up in two different files then create a configuration with both files and figure out a way to route them to the correct file, either via logger names or filters.
As per observation, your logger is updated with the last initialization so after app2.initializeYourLogger() your object-level logger object updated with App2 configuration.
You need to return the logger object from initializeYourLogger() and also create separate Logger object.
My log4j2 properties file:
status = warn
name= properties_configuration
#Directory path where log files will be stored
property.basePath = ./log/
#File logger
appender.rolling.type = RollingFile
appender.rolling.name = fileLogger
appender.rolling.fileName= ${basePath}app.log
appender.rolling.filePattern= ${basePath}app_%d{yyyyMMdd}.log.gz
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %msg%n
appender.rolling.policies.type = Policies
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling.policies.time.interval = 1
appender.rolling.policies.time.modulate = true
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.delete.type = Delete
appender.rolling.strategy.delete.basePath = ${basePath}
appender.rolling.strategy.delete.maxDepth = 1
appender.rolling.strategy.delete.ifLastModified.type = IfLastModified
appender.rolling.strategy.delete.ifLastModified.age = 30d
#Root logger configuration
rootLogger.level = info
rootLogger.additivity = false
rootLogger.appenderRef.rolling.ref = fileLogger
I'm using Lombok #Log4j2 annotation:
#Log4j2
public class BotApplication {
public static void main(String[] args) {
ApiContextInitializer.init();
TelegramBotsApi telegram = new TelegramBotsApi();
Bot bot = new Bot();
try {
telegram.registerBot(bot);
log.info("Bot successfully connected.");
} catch (TelegramApiRequestException e) {
log.error("Can't start Bot. Error: {}", e.getMessage());
}
}
}
Application writes logs to file correctly, but always when i run my app i got errors in my console:
log4j:WARN No appenders could be found for logger (org.apache.http.client.protocol.RequestAddCookies).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Seems that these errors don't affect to the logger, but I would like to remove them somehow.
Error messages that being with "log4j:WARN" are coming from log4j 1.x. This error means you have the log4j 1.x jar in your classpath but do not have a Log4j 1.x configuration present.
If you do not want to use log4j 1 (and you shouldn't) then add the log4j-1.2-api jar from Log4j 2 to your project.
I have been using Tomcat,JBoss,Glassfish etc for years.
In these containers I have used Log4j, JDK Logging etc. It is very easy.
I am struggling to get any logging from my application in Weblogic 12c.
The logs get written to stderr and not to a log file.
private final static Logger log = Logger.getLogger(TestingService.class.getName());
log.log(Level.SEVERE,"My log " + text);
In the Admin console
Logging implementation: JDK
Severity level: INFO
The behaviour is the same if I configure Log4J by following the log4j Weblogic config process.
You can try some codes like the following to get the Weblogic domain logger and server logger in your application:
import java.util.logging.Logger;
import weblogic.logging.LoggerNotAvailableException;
import weblogic.logging.LoggingHelper;
public class GetLogger {
public static Logger getLogger(){
Logger logger = null ;
try {
logger = LoggingHelper.getDomainLogger() ;
} catch (LoggerNotAvailableException e) {
logger = LoggingHelper.getServerLogger() ;
}
return logger ;
}
}
logger.setLevel() method is not available in log4j2 API. So how to set log level at run time.
I'm not sure if this is the best way, but you set the level on org.apache.logging.log4j.core.config.LoggerConfig which you can get from the LoggerContext via the LogManager.
Once set, you can update the loggers with the new configuration.
As an example:
public static void main(String[] args) {
Logger log = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
log.error("An error");
log.debug("A debug");
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration conf = ctx.getConfiguration();
conf.getLoggerConfig(LogManager.ROOT_LOGGER_NAME).setLevel(Level.DEBUG);
ctx.updateLoggers(conf);
log.error("Another error");
log.debug("Another debug");
}
Yields:
14:03:41.346 [main] ERROR - An error
14:03:41.348 [main] ERROR - Another error
14:03:41.348 [main] DEBUG - Another debug
Credit to amcintosh, I wrapped their answer in a function:
/** Override the logging level of a given logger, return the previous level */
public static Level setLevel(Logger log, Level level) {
LoggerContext ctx = (LoggerContext)LogManager.getContext(false);
Configuration conf = ctx.getConfiguration();
LoggerConfig lconf = conf.getLoggerConfig(log.getName());
Level oldLevel = lconf.getLevel();
lconf.setLevel(level);
ctx.updateLoggers(conf);
return oldLevel;
}
Despite amoe's comment, this seems to be working correctly for me using Log4J 2.5.
Gary Gregory is correct.
Also the answer to this question is right there on the FAQ page in log4j2's site
https://logging.apache.org/log4j/2.x/faq.html#reconfig_level_from_code
Sample Code below:
Configurator.setLevel(logger.getName(), Level.INFO);
On my side, i had to use this code in order to have this working fine (based on previous answers).
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.AbstractConfiguration;
...
public static void changeLoggerLevel(final String module, final Level level) {
String moduleRenamed = module.replaceAll("/", ".");
LoggerContext ctx = (LoggerContext)LogManager.getContext(false);
AbstractConfiguration configuration = (AbstractConfiguration) ctx
.getConfiguration();
if (configuration.getLogger(moduleRenamed) != null) {
LoggerConfig loggerConfig = configuration.getLoggerConfig(moduleRenamed);
loggerConfig.setLevel(level);
} else {
LoggerConfig loggerConfig = new LoggerConfig(moduleRenamed, level, true);
configuration.addLogger(moduleRenamed, loggerConfig);
}
ctx.updateLoggers(configuration);
}
The problem was with the getLoggerConfig() call; if the module you are trying to give a new level is not yet registered, this method returns the root logger (or any intermediate sub path registered), and thus instead of altering the level for com.mycompany you will alter root or com level. That's why you have to add a new LoggerConfig in case the module to alter is not yet registered.
The following APIs in the class org.apache.logging.log4j.core.config.Configurator allow you to change Levels:
setAllLevels(String, Level)
setLevel(Map)
setLevel(String, Level)
setRootLevel(Level)
I want my app to have 4 log files. Three of the log files are the typical log4j Info, Warn and Error logs. The 4th log file is completely unrelated and is used to log some data.
My log4j.properties file looks like this:
log4j.threshold=ALL
log4j.rootLogger=ALL, InfoAppender, WarnAppender, ErrorAppender
log4j.DATA_LOGGER=INFO, DataAppender
log4j.additivity.DATA_LOGGER = false
log4j.appender.DataAppender=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DataAppender.File=/app_logs/data.log
log4j.appender.InfoAppender=org.apache.log4j.DailyRollingFileAppender
log4j.appender.InfoAppender.File=/app_logs/info.log
log4j.appender.WarnAppender=org.apache.log4j.DailyRollingFileAppender
log4j.appender.WarnAppender.File=/app_logs/warn.log
log4j.appender.ErrorAppender=org.apache.log4j.DailyRollingFileAppender
log4j.appender.ErrorAppender.File=/app_logs/error.log
And my Java code looks like this:
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
private static final Log LOG = LogFactory.getLog(SomeClassInMyApp.class);
private static final Log DATA_LOG = LogFactory.getLog("DATA_LOGGER");
private static void foo() {
LOG.info("Hello");
DATA_LOG.info("Some data");
}
When I run this, the "Hello" text is correctly written to the info.log file. But the data.log file is never created or written to.
Why is the DATA_LOG.info("Some data") line not writing to the data.log file, and what code change do I need to make in order for that to happen?
commons should work as well, can you try this
import org.apache.log4j.Logger;
...
...
Logger log = Logger.getLogger("DATA_LOGGER");
...
...
log.info("my data");
instead of this
import org.apache.commons.logging.Log;
Update Just tested this code works:
log4j.properties
log4j.rootLogger = DEBUG, R
log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=E:/testroot.log
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d{DATE} %-5p %c:%L %x - %m%n
##########################################################################
################## Appender for Other Logger ############################
##########################################################################
log4j.logger.TestLog=DEBUG, cache
log4j.additivity.TestLog=false
log4j.appender.cache=org.apache.log4j.DailyRollingFileAppender
log4j.appender.cache.File=E:/testcache.log
log4j.appender.cache.layout=org.apache.log4j.PatternLayout
log4j.appender.cache.layout.ConversionPattern=%d{dd/MM/yyyy HH:mm:ss} %c %m%n
Test Code
private static final Logger DATA_LOG = Logger.getLogger("TestLog");
private static final Logger LOG = Logger.getLogger(Test.class);
public static final void main(String[] args){
LOG.error("MSG1");
DATA_LOG.error("MSG2");
}
Output
testroot.log
09 Feb 2011 12:18:29,671 ERROR in.naishe.so.Test:11 - MSG1
testcache.log
09/02/2011 12:18:29 TestLog MSG2
Are you missing something?