Shutting up log4j for good - java

Im using a 3rd party jar that uses log4j and spams really way too much (makes eclipse crash), is there a way to wipe all logging as if log4j never existed in the first place? programmatically or by project setup anything is fine as long as it stfu.
i tried
List<Logger> loggers = Collections.<Logger>list(LogManager.getCurrentLoggers());
loggers.add(LogManager.getRootLogger());
for ( Logger logger : loggers ) {
logger.setLevel(Level.OFF);
}
But doesnt compile in my setup:
LogManager.getCurrentLoggers() and
LogManager.getRootLogger() do not exist.

Log4j2 uses multiple contexts. Adapting the above code:
LoggerContext ctx = (LoggerContext) LogManager.getContext();
Configuration config = ctx.getConfiguration();
Collection<LoggerConfig> loggers = config.getLoggers().values();
for(LoggerConfig cfg: loggers) {
cfg.setLevel(Level.OFF);
}

Related

Migration from log4j to log4j2 - FileAppender set new file name & acitvateOptions

We are migrating to log4j2. I can't find anywhere how to rewrite a part of code.
LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);
Configuration config = context.getConfiguration();
RollingFileAppender fileAppender = config.getAppender("file");
(...)
fileAppender.setFile(newFileName); //this part
fileAppender.activateOptions(); //and this part
Does anyone know how it should be written correctly? Any help would be greatly appreciated and I am sorry if it is a dumb question.
EDIT:
I also have a problem with my class which (with log4j v.1) implements LoggerFactory. I found here: log4j migration to log4j2 that I should use "other mechanism". I am not sure if I should use LoggerContextFactory here or something else:
class MyNameLoggerFactory implements LoggerFactory {
(...)
void init() {
//sets quiet mode
//init DOMConfigutator
//configure using log4j config xml
}
Appender getFileAppender(File file) {
//returns a FileAppender
}
#Override
public MyNameLoggerFactory makeNewLoggerInstance(String name) {
return new MyNameLoggerFactory (name);
}
}
The XML configuration loaded here has appenders like an EmailSender, ConsoleAppender and RollingFileAppender (I will need to convert the xml too, I think).
If I understood this How to specify Log4J 2.x config location? correctly, instead of DOMConfigurator I will use here (in my init method) an initialize method with null ClassLoader?
This is really an old project, written by many different people during the years, and it is a mess. Thank you for any help.
You can try this way.
Layout<? extends Serializable> old_layout = fileAppender.getLayout();
fileAppender.stop();
//delete old appender
((org.apache.logging.log4j.core.Logger)logger).removeAppender(fileAppender);
RollingFileAppender appender = RollingFileAppender.newBuilder().withFileName(newFileName).withAppend(true).withLocking(false)
.setName(fileAppender.getName()).setIgnoreExceptions(true).withFilePattern(newFileName.concat(".%d")).withPolicy(fileAppender.getTriggeringPolicy())
.withStrategy(DefaultRolloverStrategy.newBuilder().withMax(String.valueOf(5)).build())
.setLayout(old_layout).setConfiguration(config).build();
appender.start();
((org.apache.logging.log4j.core.Logger)logger).addAppender(appender);

Equivalent programmatic logger initialization for log4j to log4j2 migration

I am trying to understand the programmatic side of log4j2, as I am migrating a lot of log4j 1.2 code. The following seems to be very different and more complicated to accomplish:
org.apache.log4j.Logger.getRootLogger().setLevel(Level.FATAL);
org.apache.log4j.Logger.getRootLogger().addAppender(new ConsoleAppender(new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN), "System.err"));
Can someone with plenty of log4j2 experience explain to me what the simple way to migrate the 2 above lines is?
EDIT: This is what I have so far:
LoggerContext context = (LoggerContext) LogManager.getContext(false);
Configuration config = context.getConfiguration();
config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME).setLevel(Level.FATAL);
PatternLayout patternLayout = PatternLayout.createLayout(PatternLayout.TTCC_CONVERSION_PATTERN, config, null, null, true, true, null, null);
Layout<? extends Serializable> layout = patternLayout;
ConsoleAppender consoleAppender = ConsoleAppender.createAppender(layout , null, "SYSTEM_ERR", "System.err", null, null);
consoleAppender.start();
config.addAppender(consoleAppender);
context.updateLoggers();
There is no way it is that complicated, right?
Unfortunately creating programmatic configuration wasn't the main concern of Log4j2. You may check on their AbstractConfiguration class sources line 580 to see how default configuration is set programmatically internally.
Log4j2 library have good support for different types of configuration files (xml, json, properties, yaml) or you can build composite configuration out of several sources. Also it tracks configuration files and is capable of dynamic reloading.
I would remmend you evaluating features mentioned above to update configuration from code. E.g.
final URL log4j = Resources.getResource("log4j2-test.xml");
ConfigurationSource configurationSource = new ConfigurationSource(
Resources.asByteSource(log4j).openStream(), log4j);
LoggerContext context = LoggerContext.getContext(false);
XmlConfiguration xmlConfiguration = new XmlConfiguration(context, configurationSource);
context.start(xmlConfiguration);
Seem easier to manage than programmatic way with larger configurations.

How to allow user to make permanent changes to log levels?

I have a Spring Boot application that uses log4j2 for logging. I have a need to adjust the logging level at run time and I have done that with a simple RESTful interface that accepts a logger name and the level it needs to be set at. I also need to be able to make permanent changes to the logging level (on just certain loggers).
a) Is there a way to persist my changes back to the log4j config file so that the next time the application is brought up, the log levels are where they had been left at, on the previous run?
b) Is there a way to read the list of loggers listed in the config file?
Thank you
a) If you have a config file, every time the server starts it will be used to configure log4j2. You could create a new config file (outside the container) and use it to configure log4j2 when the server starts:
File file = new File("/config/new/log4j2.xml");
final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
ctx.setConfigLocation(file.toURI());
Or just store the new info and modify log4j programatically
b) Try this:
public Collection<Logger> getLoggers()
https://logging.apache.org/log4j/2.0/log4j-core/apidocs/org/apache/logging/log4j/core/LoggerContext.html#getLoggers()
Here's a code example (executed at the application startup):
File file = new File(log4jConfigFilePath);
final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
ctx.setConfigLocation(file.toURI());
Collection<org.apache.logging.log4j.core.Logger> collection = ctx.getLoggers();
System.out.println(collection.size()); // returns 0 (No loggers instantiated)
Logger logger = LoggerFactory.getLogger("myLogger");
collection = ctx.getLoggers();
System.out.println(collection.size()); // returns 1 (myLogger instantiated)

What is an equivalent of LoggerRepository in log4j2

I want to migrate from Log4j 1.x to log4j2 so I read this article:
http://logging.apache.org/log4j/2.x/manual/migration.html
In our application we are using LoggerRepository:
Logger.getRootLogger().getLoggerRepository().getCurrentLoggers();
what is the equivalent of this piece of code in log4j2. Because in article they said we can't access to this method but they don't mention how should I replace it
If I understand your need correctly, you can go via LogManager to get the LoggerContext's configuration and retrieve the Loggers from that:
LoggerContext ctx = LogManager.getContext();
Configuration cfg = ctx.getConfiguration();
Map<String, LoggerConfig> loggers = cfg.getLoggers();

What is getCurrentLoggers's analog in log4j2

How can i get all loggers used used in log4j2? In log4j i could use getCurrentLoggers like described here: Number of loggers used
get all loggers used in log4j2:
LoggerContext logContext = (LoggerContext) LogManager
.getContext(false);
Map<String, LoggerConfig> map = logContext.getConfiguration()
.getLoggers();
Attention:
use org.apache.logging.log4j.core.LoggerContext
not org.apache.logging.log4j.spi.LoggerContext
looks like i've found the way:
File configFile = new File("c:\\my_path\\log4j2.xml");
LoggerContext loggerContext = Configurator.initialize("my_config", null, configFile.toURI());
Configuration configuration = loggerContext.getConfiguration();
Collection<LoggerConfig> loggerConfigs = configuration.getLoggers().values();
YuriR's answer is incomplete in that it does not point that LoggerConfig objects are returned, not Logger. This is the fundamental difference between Log4j1 and Log4j2 - Loggers cannot be dirrectly manipulated in Log4j2. See Log4j2 Architecture for details.
If you are running in a web app, you may have multiple LoggerContexts.
Please take a look at how LoggerConfigs are exposed via JMX in the org.apache.logging.log4j.core.jmx.Server class.
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Collection<? extends Logger> loggers = ctx.getLoggers();
It's important to note that LoggerConfig objects are being returned by getLoggers() and NOT the loggers themselves. As vacant78 pointed out, this is only good for setting the configuration for loggers that have yet to be instantiated. If you already have a bunch of loggers already instantiated, changing the configuration using this method does no good.
For example, to change the level of logging at runtime, refer to this link, which utilizes an undocumented API within Apache (no surprise there) that will change all your currently instantiated logger levels: Programmatically change log level in Log4j2

Categories