Lập trình thay đổi cấp độ nhật ký trong Log4j2


109

Tôi quan tâm đến việc thay đổi cấp độ nhật ký trong Log4j2 theo chương trình. Tôi đã thử xem tài liệu cấu hình của họ nhưng dường như không có gì cả. Tôi cũng đã thử xem trong gói : org.apache.logging.log4j.core.config, nhưng không có gì trong đó trông hữu ích.


2
Nếu bạn không nhận được câu trả lời ở đây, hãy thử danh sách thư, nó thường được các tác giả chính tìm đến một lần trong 2 ngày. Sau đó quay lại và trả lời câu hỏi của riêng bạn :-)
tgkprog

Câu trả lời:


139

CHỈNH SỬA theo câu hỏi thường gặp về log4j2 phiên bản 2.4

Bạn có thể đặt cấp của người ghi nhật ký bằng Trình cấu hình lớp từ Log4j Core. NHƯNG hãy lưu ý rằng lớp Trình cấu hình không phải là một phần của API công khai.

// 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);

Nguồn

CHỈNH SỬA để phản ánh những thay đổi trong API được giới thiệu trong Log4j2 phiên bản 2.0.2

Nếu bạn muốn thay đổi cấp trình ghi gốc, hãy làm như sau:

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.

Đây là javadoc cho LoggerConfig.


3
Ngay và nếu bạn muốn thay đổi chỉ cho một trình ghi cụ thể (của một lớp / gói), hãy lấy ngữ cảnh của trình ghi đó, setLevel và updateLoggers.
tgkprog

34
Một cách phức tạp như vậy chỉ để thiết lập mức ghi nhật ký. Tôi chắc chắn có lý do để làm điều đó với năm dòng mã thay vì một dòng ban đầu trong các phiên bản trước của log4j, nhưng tôi không thấy nó. Trong mọi trường hợp, cảm ơn vì điều này, @slaadvak!
Sturm

1
.updateLoggers () dường như không cần thiết. Có vẻ như những thay đổi được thực hiện với .setLevel () được áp dụng ngay lập tức.
zbyszek

1
Lệnh gọi updateLoggers luôn được yêu cầu, ngay cả khi bạn thêm LoggerConfig mới. UpdateLoggers khiến tất cả các trình ghi nhật ký tự liên kết lại với LoggerConfigs và thay đổi cấp độ nhật ký của họ thành cấp độ của LoggerConfig được liên kết của chúng. Nếu bạn thêm một LoggerConfig mới, bất kỳ Logger nào khớp với mẫu LoggerConfig mới sẽ được chuyển hướng đến nó. Cách "phức tạp" là bắt buộc vì Người ghi nhật ký và cấu hình của chúng đã được tách biệt trong Log4j2.
đi

1
Dưới đây là một câu trả lời mà cung cấp một cập nhật, 1 hoặc giải pháp 2 dòng cho các phiên bản mới hơn của Log4J: stackoverflow.com/a/44678752/1339923
Lambart

37

Câu trả lời được chấp nhận bởi @slaadvak không phù hợp với tôi cho Log4j2 2.8.2 . Sau đây đã làm.

Để thay đổi nhật ký sử dụng Level phổ biến :

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

Để thay đổi nhật ký Levelchỉ cho lớp hiện tại, hãy sử dụng:

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

1
Được sự bình chọn của tôi bởi vì bạn đã lấy tên người ghi nhật ký từ chính người ghi nhật ký thay vì mã hóa khó tên dưới dạng một chuỗi.
DWoldrich

18

Nếu bạn muốn thay đổi một cấp trình ghi cụ thể (không phải trình ghi gốc hoặc trình ghi nhật ký được định cấu hình trong tệp cấu hình), bạn có thể làm như sau:

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
Điều này hoàn toàn không ảnh hưởng đến trình ghi nhật ký của tôi. Tôi đã sử dụng setLevel(logger, Level.ERROR);và các câu lệnh logger.debug vẫn được in. Tệp log4j2.xml của tôi ở pastebin.com/fcbV2mTW
Noumenon.

Tôi đã cập nhật mã. Hãy cho tôi biết nếu có bất kỳ vấn đề nào với nó.
Jörg Friedrich

4
Trong log4j 2.7 LoggerContext không có phương thức getConfiguration (), hãy xem logging.apache.org/log4j/2.x/log4j-api/apidocs/index.html?org/…
maxxyme

log4j-core-2.7.jar có và có thể được sử dụng làm LoggerContext cuối cùng ctx = (LoggerContext) LogManager.getContext (false); cấu hình cuối cùng Cấu hình = ctx.getConfiguration ();
jprism

3
Sau khi nhìn thấy điều này, tôi đang nghĩ .. "Có lẽ họ không muốn chúng tôi thay đổi mức độ trong thời gian chạy?"
Koray Tugay

13

Tôi tìm thấy câu trả lời hay ở đây: https://garygregory.wordpress.com/2016/01/11/changed-log-levels-in-log4j2/

Bạn có thể sử dụng org.apache.logging.log4j.core.config.Configurator để đặt mức cho một trình ghi cụ thể.

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

2
Câu trả lời này chương trình cùng một giải pháp, cũng như làm thế nào để thiết lập nó cho logger gốc - đó là đôi khi hữu ích: stackoverflow.com/a/44678752/1339923
Lambart

4

Phương pháp tiếp cận theo chương trình khá xâm nhập. Có lẽ bạn nên kiểm tra hỗ trợ JMX do Log4J2 cung cấp:

  1. Bật cổng JMX khi khởi động ứng dụng của bạn:

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

  2. Sử dụng bất kỳ ứng dụng khách JMX nào có sẵn (JVM cung cấp một ứng dụng trong JAVA_HOME / bin / jconsole.exe) trong khi thực thi ứng dụng của bạn.

  3. Trong JConsole, hãy tìm bean "org.apache.logging.log4j2.Loggers"

  4. Cuối cùng thay đổi cấp độ của trình ghi nhật ký của bạn

Điều mà tôi thích nhất ở đây là bạn không phải sửa đổi mã hoặc cấu hình của mình để quản lý điều này. Nó là tất cả bên ngoài và minh bạch.

Thông tin thêm: http://logging.apache.org/log4j/2.x/manual/jmx.html


Rất hữu ích, Cảm ơn!
Darren Parker

3

Hầu hết các câu trả lời theo mặc định cho rằng việc ghi nhật ký phải có tính chất phụ gia. Nhưng giả sử rằng một số gói đang tạo ra nhiều nhật ký và bạn chỉ muốn tắt ghi nhật ký cho trình ghi cụ thể đó. Đây là mã mà tôi đã sử dụng để làm cho nó hoạt động

    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();
    }
}

Một trường hợp thử nghiệm cho cùng một

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");
    }
}

Giả sử log4j2.xml sau nằm trong classpath

<?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

Một cách không bình thường mà tôi thường làm là tạo hai tệp riêng biệt với mức độ ghi nhật ký khác nhau.
Ví dụ. log4j2.xml và log4j-debug.xml Bây giờ hãy thay đổi cấu hình từ các tệp này.
Mã mẫu:

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));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.