Log4j2'de günlük düzeyini programlı olarak değiştirin


109

Log4j2'deki günlük düzeyini programlı olarak değiştirmekle ilgileniyorum. Yapılandırma belgelerine bakmayı denedim ama bunda hiçbir şey yok gibi görünüyor. Ayrıca pakete bakmayı da denedim: org.apache.logging.log4j.core.configama içindeki hiçbir şey de yardımcı olmadı.


2
Burada bir cevap alamazsanız, posta listesini deneyin, genellikle ana yazarlar tarafından 2 günde bir aranır. Sonra geri dönüp kendi sorunuzu cevaplayın :-)
tgkprog

Yanıtlar:


139

Log4j2 sürüm 2.4'e göre DÜZENLENDİ SSS

Log4j Core'dan Class Configurator ile bir kaydedicinin seviyesini ayarlayabilirsiniz. AMA Configurator sınıfının genel API'nin bir parçası olmadığını unutmayın.

// org.apache.logging.log4j.core.config.Configurator;
Configurator.setLevel("com.example.Foo", Level.DEBUG);

// You can also set the root logger:
Configurator.setRootLevel(Level.DEBUG);

Kaynak

Log4j2 sürüm 2.0.2'de sunulan API'deki değişiklikleri yansıtacak şekilde DÜZENLENDİ

Kök kaydedici düzeyini değiştirmek isterseniz, aşağıdaki gibi bir şey yapın:

LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration config = ctx.getConfiguration();
LoggerConfig loggerConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME); 
loggerConfig.setLevel(level);
ctx.updateLoggers();  // This causes all Loggers to refetch information from their LoggerConfig.

İşte LoggerConfig için javadoc.


3
Doğru ve sadece belirli bir günlükçüyü (bir sınıfın / paketin) değiştirmek istiyorsanız bu günlükçünün, setLevel ve updateLoggers bağlamını alın.
tgkprog

34
Sadece kayıt seviyesini ayarlamak için böyle karmaşık bir yol. Eminim bunu log4j'nin önceki sürümlerindeki orijinal tek satır yerine beş satırlık kodla yapmanın bir nedeni vardır, ama ben görmüyorum. Her durumda, bunun için teşekkürler @slaadvak!
Sturm

1
.updateLoggers () gerekli görünmüyor. .SetLevel () ile yapılan değişikliklerin hemen uygulandığı görülüyor.
zbyszek

1
Yeni bir LoggerConfig ekleseniz bile updateLoggers çağrısı her zaman gereklidir. UpdateLoggers, tüm kaydedicilerin LoggerConfigs ile yeniden ilişki kurmalarına ve günlük düzeylerini ilişkili LoggerConfig ile değiştirmelerine neden olur. Yeni bir LoggerConfig eklerseniz, yeni LoggerConfig modeliyle eşleşen herhangi bir Logger ona yeniden yönlendirilecektir. Logger'lar ve yapılandırmaları Log4j2'de ayrıldığından "kıvrımlı" yol gereklidir.
rgoers


37

@Slaadvak tarafından kabul edilen cevap Log4j2 2.8.2 için benim için işe yaramadı . Aşağıdakiler yaptı.

Günlüğü Level evrensel olarak değiştirmek için şunu kullanın:

Configurator.setAllLevels(LogManager.getRootLogger().getName(), level);

Günlüğü Levelyalnızca geçerli sınıf için değiştirmek için şunu kullanın:

Configurator.setLevel(LogManager.getLogger(CallingClass.class).getName(), level);

1
Oyumu aldım çünkü kaydedici adlarını, adı bir dizge olarak kodlamak yerine kaydedicilerin kendisinden aldınız.
DWoldrich

18

Tek bir belirli günlük kaydı düzeyini değiştirmek istiyorsanız (yapılandırma dosyasında yapılandırılan kök kaydediciyi veya kaydediciyi değil), bunu yapabilirsiniz:

public static void setLevel(Logger logger, Level level) {
    final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
    final Configuration config = ctx.getConfiguration();

    LoggerConfig loggerConfig = config.getLoggerConfig(logger.getName());
    LoggerConfig specificConfig = loggerConfig;

    // We need a specific configuration for this logger,
    // otherwise we would change the level of all other loggers
    // having the original configuration as parent as well

    if (!loggerConfig.getName().equals(logger.getName())) {
        specificConfig = new LoggerConfig(logger.getName(), level, true);
        specificConfig.setParent(loggerConfig);
        config.addLogger(logger.getName(), specificConfig);
    }
    specificConfig.setLevel(level);
    ctx.updateLoggers();
}

3
Bu, kaydedicimi hiç etkilemedi. Kullandım setLevel(logger, Level.ERROR);ve logger.debug ifadeleri hala yazdırılıyor. Benim log4j2.xml dosyası olan pastebin.com/fcbV2mTW
Numen

Kodu güncelledim. Bununla ilgili herhangi bir sorun olursa bana bildirin.
Jörg Friedrich

4
Log4j 2.7 olarak LoggerContext değil getConfiguration () yöntemi, bkz etti logging.apache.org/log4j/2.x/log4j-api/apidocs/index.html?org/...
maxxyme

log4j-core-2.7.jar, son LoggerContext olarak kullanılabilir ve kullanılabilir ctx = (LoggerContext) LogManager.getContext (false); final Yapılandırma yapılandırması = ctx.getConfiguration ();
jprism

3
Bunu gördükten sonra düşünüyorum .. "Belki de çalışma zamanında seviyeyi değiştirmemizi istemiyorlar?"
Koray Tugay

13

Burada iyi bir cevap buldum: https://garygregory.wordpress.com/2016/01/11/changing-log-levels-in-log4j2/

Belirli bir kaydedicinin düzeyini ayarlamak için org.apache.logging.log4j.core.config.Configurator'ı kullanabilirsiniz.

Logger logger = LogManager.getLogger(Test.class);
Configurator.setLevel(logger.getName(), Level.DEBUG);

2
Bu cevap aynı çözümü ve bunun kök kaydedici için nasıl ayarlanacağını gösterir - bu bazen yararlıdır: stackoverflow.com/a/44678752/1339923
Lambart

4

Programlı yaklaşım oldukça müdahaleci. Belki de Log4J2 tarafından verilen JMX desteğini kontrol etmelisiniz:

  1. Uygulamanızın başlangıcında JMX bağlantı noktasını etkinleştirin:

    -Dcom.sun.management.jmxremote.port = [port_num]

  2. Uygulamanızı çalıştırırken mevcut JMX istemcilerinden herhangi birini kullanın (JVM, JAVA_HOME / bin / jconsole.exe içinde bir tane sağlar).

  3. JConsole'da "org.apache.logging.log4j2.Loggers" fasulyesini arayın

  4. Sonunda kaydedicinizin seviyesini değiştirin

En çok sevdiğim şey, bunu yönetmek için kodunuzu veya yapılandırmanızı değiştirmek zorunda kalmamanızdır. Tamamen harici ve şeffaf.

Daha fazla bilgi: http://logging.apache.org/log4j/2.x/manual/jmx.html


Çok yardımcı oldu, teşekkürler!
Darren Parker

3

Yanıtların çoğu, varsayılan olarak, günlüğe kaydetmenin ek olması gerektiğini varsayar. Ancak bazı paketlerin çok sayıda günlük oluşturduğunu ve yalnızca söz konusu günlük kaydı için günlük kaydını kapatmak istediğinizi söyleyin. İşte onu çalıştırmak için kullandığım kod

    public class LogConfigManager {

    public void setLogLevel(String loggerName, String level) {
        Level newLevel = Level.valueOf(level);
        LoggerContext logContext = (LoggerContext) LogManager.getContext(false);
        Configuration configuration = logContext.getConfiguration();
        LoggerConfig loggerConfig = configuration.getLoggerConfig(loggerName);
        // getLoggerConfig("a.b.c") could return logger for "a.b" if there is no logger for "a.b.c"
        if (loggerConfig.getName().equalsIgnoreCase(loggerName)) {
            loggerConfig.setLevel(newLevel);
            log.info("Changed logger level for {} to {} ", loggerName, newLevel);
        } else {
            // create a new config.
            loggerConfig = new LoggerConfig(loggerName, newLevel, false);
            log.info("Adding config for: {} with level: {}", loggerConfig, newLevel);
            configuration.addLogger(loggerName, loggerConfig);


            LoggerConfig parentConfig = loggerConfig.getParent();
            do {
                for (Map.Entry<String, Appender> entry : parentConfig.getAppenders().entrySet()) {
                    loggerConfig.addAppender(entry.getValue(), null, null);
                }
                parentConfig = parentConfig.getParent();
            } while (null != parentConfig && parentConfig.isAdditive());
        }
        logContext.updateLoggers();
    }
}

Aynı şey için bir test durumu

public class LogConfigManagerTest {
    @Test
    public void testLogChange() throws IOException {
        LogConfigManager logConfigManager = new LogConfigManager();
        File file = new File("logs/server.log");
        Files.write(file.toPath(), new byte[0], StandardOpenOption.TRUNCATE_EXISTING);
        Logger logger = LoggerFactory.getLogger("a.b.c");
        logger.debug("Marvel-1");
        logConfigManager.setLogLevel("a.b.c", "debug");
        logger.debug("DC-1");
        // Parent logger level should remain same
        LoggerFactory.getLogger("a.b").debug("Marvel-2");
        logConfigManager.setLogLevel("a.b.c", "info");
        logger.debug("Marvel-3");
        // Flush everything
        LogManager.shutdown();

        String content = Files.readAllLines(file.toPath()).stream().reduce((s1, s2) -> s1 + "\t" + s2).orElse(null);
        Assert.assertEquals(content, "DC-1");
    }
}

Aşağıdaki log4j2.xml'nin sınıf yolunda olduğunu varsayarsak

<?xml version="1.0" encoding="UTF-8"?>
<Configuration xmlns="http://logging.apache.org/log4j/2.0/config">

    <Appenders>
        <File name="FILE" fileName="logs/server.log" append="true">
            <PatternLayout pattern="%m%n"/>
        </File>
        <Console name="STDOUT" target="SYSTEM_OUT">
            <PatternLayout pattern="%m%n"/>
        </Console>
    </Appenders>

    <Loggers>
        <AsyncLogger name="a.b" level="info">
            <AppenderRef ref="STDOUT"/>
            <AppenderRef ref="FILE"/>
        </AsyncLogger>

        <AsyncRoot level="info">
            <AppenderRef ref="STDOUT"/>
        </AsyncRoot>
    </Loggers>

</Configuration>

2

Yaptığım alışılmadık bir yol, farklı günlük kaydı düzeyine sahip iki ayrı dosya oluşturmaktır.
Örneğin. log4j2.xml ve log4j-debug.xml Şimdi yapılandırmayı bu dosyalardan değiştirin.
Basit kod:

ConfigurationFactory configFactory = XmlConfigurationFactory.getInstance();
            ConfigurationFactory.setConfigurationFactory(configFactory);
            LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
            ClassLoader classloader = Thread.currentThread().getContextClassLoader();
            InputStream inputStream = classloader.getResourceAsStream(logFileName);
            ConfigurationSource configurationSource = new ConfigurationSource(inputStream);

            ctx.start(configFactory.getConfiguration(ctx, configurationSource));
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.