GitHub user paladox created a discussion: Help with migrating from log4j to log4j2 (we also use a slf4j -> log4j)
Could I have some help to migrate: ``` // Copyright (C) 2014 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.gerrit.sshd.commands; import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterators; import com.google.gerrit.common.data.GlobalCapability; import com.google.gerrit.extensions.annotations.RequiresCapability; import com.google.gerrit.sshd.CommandMetaData; import com.google.gerrit.sshd.SshCommand; import java.net.MalformedURLException; import java.net.URI; import org.apache.log4j.Level; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.helpers.Loader; import org.kohsuke.args4j.Argument; @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER) @CommandMetaData( name = "set-level", description = "Change the level of loggers", runsAt = MASTER_OR_SLAVE) public class SetLoggingLevelCommand extends SshCommand { private static final String LOG_CONFIGURATION = "log4j.properties"; private static final String JAVA_OPTIONS_LOG_CONFIG = "log4j.configuration"; private enum LevelOption { ALL, TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF, RESET, } @Argument(index = 0, required = true, metaVar = "LEVEL", usage = "logging level to set to") private LevelOption level; @Argument(index = 1, required = false, metaVar = "NAME", usage = "used to match loggers") private String name; @Override protected void run() throws MalformedURLException { enableGracefulStop(); if (level == LevelOption.RESET) { reset(); } else { for (Logger logger : getCurrentLoggers()) { if (name == null || logger.getName().contains(name)) { logger.setLevel(Level.toLevel(level.name())); } } } } private static void reset() throws MalformedURLException { for (Logger logger : getCurrentLoggers()) { logger.setLevel(null); } String path = System.getProperty(JAVA_OPTIONS_LOG_CONFIG); if (Strings.isNullOrEmpty(path)) { PropertyConfigurator.configure(Loader.getResource(LOG_CONFIGURATION)); } else { PropertyConfigurator.configure(URI.create(path).toURL()); } } @SuppressWarnings({"unchecked", "JdkObsolete"}) private static ImmutableList<Logger> getCurrentLoggers() { return ImmutableList.copyOf(Iterators.forEnumeration(LogManager.getCurrentLoggers())); } }``` please? I've come up with: ``` package com.google.gerrit.sshd.commands; import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE; import com.google.gerrit.common.data.GlobalCapability; import com.google.gerrit.extensions.annotations.RequiresCapability; import com.google.gerrit.sshd.CommandMetaData; import com.google.gerrit.sshd.SshCommand; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.LoggerConfig; import org.apache.log4j.Logger; // Log4j 1.x import org.kohsuke.args4j.Argument; import org.apache.logging.log4j.core.config.Configurator; @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER) @CommandMetaData( name = "set-level", description = "Change the level of existing loggers", runsAt = MASTER_OR_SLAVE) public class SetLoggingLevelCommand extends SshCommand { public enum LevelOption { ALL, TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF, RESET } private static final Map<String, Level> ORIGINAL_LOG4J2_LEVELS = new HashMap<>(); private static final Map<String, org.apache.log4j.Level> ORIGINAL_LOG4J1_LEVELS = new HashMap<>(); private static Level ORIGINAL_ROOT_LEVEL = null; private static boolean initialized = false; @Argument(index = 0, required = true, metaVar = "LEVEL", usage = "logging level to set to") private LevelOption level; @Argument(index = 1, required = false, metaVar = "NAME", usage = "used to match loggers") private String name; @Override protected void run() { enableGracefulStop(); if (!initialized) { snapshotOriginalLevels(); initialized = true; } if (level == LevelOption.RESET) { resetToSnapshot(); return; } Level newLevel; try { newLevel = Level.valueOf(level.name()); } catch (IllegalArgumentException e) { stderr.println("Unknown logging level: " + level); return; } // --- Log4j2 --- LoggerContext ctx = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false); org.apache.logging.log4j.core.config.Configuration config = ctx.getConfiguration(); config.getLoggers().forEach((loggerName, loggerConfig) -> { if (!loggerName.isEmpty() && (name == null || loggerName.contains(name))) { loggerConfig.setLevel(newLevel); stdout.println("Updated Log4j2 LoggerConfig: " + loggerName + " -> " + newLevel); } }); ctx.updateLoggers(); // --- Log4j1 bridge --- for (Enumeration<?> e = org.apache.log4j.LogManager.getCurrentLoggers(); e.hasMoreElements(); ) { Logger logger1 = (Logger) e.nextElement(); if (name == null || logger1.getName().contains(name)) { org.apache.log4j.Level lvl1 = org.apache.log4j.Level.toLevel(level.name()); logger1.setLevel(lvl1); stdout.println("Updated Log4j1 Logger: " + logger1.getName() + " -> " + lvl1); } } } private static void snapshotOriginalLevels() { LoggerContext ctx = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false); org.apache.logging.log4j.core.config.Configuration config = ctx.getConfiguration(); ORIGINAL_ROOT_LEVEL = config.getRootLogger().getLevel(); config.getLoggers().forEach((loggerName, loggerConfig) -> { ORIGINAL_LOG4J2_LEVELS.put(loggerName, loggerConfig.getLevel()); }); for (Enumeration<?> e = org.apache.log4j.LogManager.getCurrentLoggers(); e.hasMoreElements(); ) { Logger logger1 = (Logger) e.nextElement(); ORIGINAL_LOG4J1_LEVELS.put(logger1.getName(), logger1.getLevel()); } } private static void resetToSnapshot() { LoggerContext ctx = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false); org.apache.logging.log4j.core.config.Configuration config = ctx.getConfiguration(); config.getLoggers().forEach((loggerName, loggerConfig) -> { Level original = ORIGINAL_LOG4J2_LEVELS.get(loggerName); if (original != null) { loggerConfig.setLevel(original); } }); if (ORIGINAL_ROOT_LEVEL != null) { config.getRootLogger().setLevel(ORIGINAL_ROOT_LEVEL); } ctx.updateLoggers(); for (Enumeration<?> e = org.apache.log4j.LogManager.getCurrentLoggers(); e.hasMoreElements(); ) { Logger logger1 = (Logger) e.nextElement(); org.apache.log4j.Level original = ORIGINAL_LOG4J1_LEVELS.get(logger1.getName()); if (original != null) { logger1.setLevel(original); } } } } ``` but it doesn't work properly. I'm not seeing the log level take effect, if the logger was created under slf4j (the logger will also only return under `for (Enumeration<?> e = org.apache.log4j.LogManager.getCurrentLoggers(); e.hasMoreElements(); ) {` for loggers created via slf4j). Although this works with `ctx.getLoggerRegistry().getLoggers()` in listing loggers, but I can't then use it to update the log level if it's created via slf4j. E.g. I'm trying to set `org.eclipse.jetty.` to debug, which works, but it doesn't take effect, I don't see any logging under those channels in debug. It does under log4j if I revert back. I migrated: ``` // Copyright (C) 2014 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.gerrit.sshd.commands; import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterators; import com.google.gerrit.common.data.GlobalCapability; import com.google.gerrit.extensions.annotations.RequiresCapability; import com.google.gerrit.sshd.CommandMetaData; import com.google.gerrit.sshd.SshCommand; import java.util.Map; import java.util.TreeMap; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.kohsuke.args4j.Argument; @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER) @CommandMetaData( name = "ls-level", description = "list the level of loggers", runsAt = MASTER_OR_SLAVE) public class ListLoggingLevelCommand extends SshCommand { @Argument(index = 0, required = false, metaVar = "NAME", usage = "used to match loggers") private String name; @Override protected void run() { enableGracefulStop(); Map<String, String> logs = new TreeMap<>(); for (Logger logger : getCurrentLoggers()) { if (name == null || logger.getName().contains(name)) { logs.put(logger.getName(), logger.getEffectiveLevel().toString()); } } for (Map.Entry<String, String> e : logs.entrySet()) { stdout.println(e.getKey() + ": " + e.getValue()); } } @SuppressWarnings({"unchecked", "JdkObsolete"}) private static ImmutableList<Logger> getCurrentLoggers() { return ImmutableList.copyOf(Iterators.forEnumeration(LogManager.getCurrentLoggers())); } } ``` to ``` // Copyright (C) 2014 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.gerrit.sshd.commands; import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE; import com.google.common.collect.ImmutableList; import com.google.gerrit.common.data.GlobalCapability; import com.google.gerrit.extensions.annotations.RequiresCapability; import com.google.gerrit.sshd.CommandMetaData; import com.google.gerrit.sshd.SshCommand; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.TreeMap; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.LoggerConfig; import org.kohsuke.args4j.Argument; @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER) @CommandMetaData( name = "ls-level", description = "list the level of loggers", runsAt = MASTER_OR_SLAVE) public class ListLoggingLevelCommand extends SshCommand { @Argument(index = 0, required = false, metaVar = "NAME", usage = "used to match loggers") private String name; @Override protected void run() { enableGracefulStop(); Map<String, String> logs = new TreeMap<>(); for (Logger logger : getAllLoggers()) { if (name == null || logger.getName().contains(name)) { logs.put(logger.getName(), getEffectiveLevel(logger)); } } for (Map.Entry<String, String> e : logs.entrySet()) { if (e.getKey() != null && !e.getKey().isEmpty()) { stdout.println(e.getKey() + ": " + e.getValue()); } } } private static ImmutableList<Logger> getAllLoggers() { LoggerContext ctx = (LoggerContext) LogManager.getContext(false); Set<String> seenNames = new HashSet<>(); ImmutableList.Builder<Logger> builder = ImmutableList.builder(); for (LoggerConfig lc : ctx.getConfiguration().getLoggers().values()) { Logger logger = ctx.getLogger(lc.getName()); if (seenNames.add(logger.getName())) { builder.add(logger); } } ctx.getLoggerRegistry() .getLoggers() .forEach( logger -> { if (seenNames.add(logger.getName())) { builder.add(logger); } }); return builder.build(); } private static String getEffectiveLevel(Logger logger) { Level level = logger.getLevel(); if (level != null) { return level.name(); } else { Logger parent = logger.getParent(); return (parent != null && parent.getLevel() != null) ? parent.getLevel().name() : "UNKNOWN"; } } } ``` which lists the loggers similar to log4j. I just can't get SetLoggingLevelCommand to work properly. GitHub link: https://github.com/apache/logging-log4j2/discussions/3914 ---- This is an automatically sent email for [email protected]. To unsubscribe, please send an email to: [email protected]
