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]

Reply via email to