Đặt mức nhật ký của thông báo trong thời gian chạy trong slf4j


100

Khi sử dụng log4j, Logger.log(Priority p, Object message)phương pháp này có sẵn và có thể được sử dụng để ghi thông báo ở cấp nhật ký được xác định trong thời gian chạy. Chúng tôi đang sử dụng thực tế này và mẹo này để chuyển hướng stderr đến trình ghi nhật ký ở cấp nhật ký cụ thể.

slf4j không có log()phương pháp chung mà tôi có thể tìm thấy. Điều đó có nghĩa là không có cách nào để thực hiện những điều trên?


4
Có vẻ như có một số cuộc thảo luận về việc thêm cái này vào slf4j 2.0 trong danh sách gửi thư của nhà phát triển: qos.ch/pipermail/slf4j-dev/2010-March/002865.html
Edward Dale,

1
hãy nhìn vào Marker, đây là dữ liệu tùy chỉnh mà bạn có thể chuyển vào chuỗi nhật ký.
tuxSlayer

1
@tuxSlayer, bạn có thể vui lòng giải thích cách sử dụng Marker trong trường hợp này không?
Biến khốn khổ

Có thể đây không phải là ý tưởng tốt nhất cho "ghi nhật ký" nhưng bạn có thể sử dụng một số điểm đánh dấu cho mục nhập nhật ký "ưu tiên" (cao | thấp | bình thường, thông tin | cảnh báo | nghiêm trọng) và sử dụng tính năng lọc trong logback hoặc appender tùy chỉnh để sử dụng các điểm đánh dấu và ổ đĩa các mục nhật ký vào các kênh riêng biệt (thông tin nhật ký, email nghiêm trọng, v.v.). Tuy nhiên, cách thẳng thắn hơn là có một mặt tiền cho điều này như đã được chỉ ra trong các câu trả lời dưới đây.
tuxSlayer

2
Tính năng này được cho là một phần của slf4j 2.0. jira.qos.ch/browse/SLF4J-124 Xem câu trả lời của tôi để biết chi tiết và để biết slf4j 1.x-cách giải quyết.
slartidan

Câu trả lời:


47

Không có cách nào để làm điều này với slf4j.

Tôi tưởng tượng rằng lý do mà chức năng này bị thiếu là không thể xây dựng một Levelkiểu để slf4jcó thể được ánh xạ hiệu quả đến kiểu Level(hoặc tương đương) được sử dụng trong tất cả các triển khai ghi nhật ký có thể có phía sau mặt tiền. Ngoài ra, các nhà thiết kế quyết định rằng trường hợp sử dụng của bạn quá bất thường để biện minh cho chi phí hỗ trợ nó.

Về @ ripper234 's use-case (kiểm tra đơn vị), tôi nghĩ rằng giải pháp thực dụng là sửa đổi các đơn vị kiểm tra (s) để kiến thức cứng-wire của những gì hệ thống khai thác gỗ là đằng sau mặt tiền slf4j ... khi chạy các bài kiểm tra đơn vị.


9
Không có bản đồ thực sự cần thiết. Có năm cấp độ đã được định nghĩa ngầm bởi các phương thức trong org.slf4j.Logger: gỡ lỗi, lỗi, thông tin, theo dõi, cảnh báo.
Edward Dale

1
Và các vấn đề đã được đóng lại là Không hợp lệ. Theo như tôi hiểu, đây là một sự lựa chọn thiết kế có chủ ý.
ripper234,

9
@ ripper234 - Tôi không nghĩ rằng lỗi của bạn giải quyết vấn đề tương tự như câu hỏi ban đầu của scompt.com. Bạn đã hỏi về cách định cấu hình cấp độ của hệ thống ghi nhật ký cơ bản thông qua API SLF4J. Những gì Scompt.com theo sau là một phương thức 'nhật ký' chung trong API SLF4J, lấy cấp độ ghi nhật ký của thông báo làm tham số.
Richard Fearn

1
+1 @RichardFearn Và người ta không thể hoàn tác nhận xét ủng hộ sau 60 giây, meh . Yêu cầu tính năng vẫn đang hiện hữu trong khi đó: bugzilla.slf4j.org/show_bug.cgi?id=133
Tháng Một

3
Các liên kết RFE không giải quyết được nữa. Các liên kết có liên quan hiện là: jira.qos.ch/browse/SLF4J-124jira.qos.ch/browse/SLF4J-197 ... và cả hai đều đã bị đóng. Đọc các bình luận để biết cơ sở lý luận.
Stephen C

27

Richard Fearn có ý tưởng đúng, vì vậy tôi đã viết ra toàn bộ lớp học dựa trên mã bộ xương của anh ấy. Hy vọng nó đủ ngắn để đăng ở đây. Sao chép và dán để thưởng thức. Tôi có lẽ cũng nên thêm một số câu thần chú ma thuật: "Mã này được phát hành cho miền công cộng"

import org.slf4j.Logger;

public class LogLevel {

    /**
     * Allowed levels, as an enum. Import using "import [package].LogLevel.Level"
     * Every logging implementation has something like this except SLF4J.
     */

    public static enum Level {
        TRACE, DEBUG, INFO, WARN, ERROR
    }

    /**
     * This class cannot be instantiated, why would you want to?
     */

    private LogLevel() {
        // Unreachable
    }

    /**
     * Log at the specified level. If the "logger" is null, nothing is logged.
     * If the "level" is null, nothing is logged. If the "txt" is null,
     * behaviour depends on the SLF4J implementation.
     */

    public static void log(Logger logger, Level level, String txt) {
        if (logger != null && level != null) {
            switch (level) {
            case TRACE:
                logger.trace(txt);
                break;
            case DEBUG:
                logger.debug(txt);
                break;
            case INFO:
                logger.info(txt);
                break;
            case WARN:
                logger.warn(txt);
                break;
            case ERROR:
                logger.error(txt);
                break;
            }
        }
    }

    /**
     * Log at the specified level. If the "logger" is null, nothing is logged.
     * If the "level" is null, nothing is logged. If the "format" or the "argArray"
     * are null, behaviour depends on the SLF4J-backing implementation.
     */

    public static void log(Logger logger, Level level, String format, Object[] argArray) {
        if (logger != null && level != null) {
            switch (level) {
            case TRACE:
                logger.trace(format, argArray);
                break;
            case DEBUG:
                logger.debug(format, argArray);
                break;
            case INFO:
                logger.info(format, argArray);
                break;
            case WARN:
                logger.warn(format, argArray);
                break;
            case ERROR:
                logger.error(format, argArray);
                break;
            }
        }
    }

    /**
     * Log at the specified level, with a Throwable on top. If the "logger" is null,
     * nothing is logged. If the "level" is null, nothing is logged. If the "format" or
     * the "argArray" or the "throwable" are null, behaviour depends on the SLF4J-backing
     * implementation.
     */

    public static void log(Logger logger, Level level, String txt, Throwable throwable) {
        if (logger != null && level != null) {
            switch (level) {
            case TRACE:
                logger.trace(txt, throwable);
                break;
            case DEBUG:
                logger.debug(txt, throwable);
                break;
            case INFO:
                logger.info(txt, throwable);
                break;
            case WARN:
                logger.warn(txt, throwable);
                break;
            case ERROR:
                logger.error(txt, throwable);
                break;
            }
        }
    }

    /**
     * Check whether a SLF4J logger is enabled for a certain loglevel. 
     * If the "logger" or the "level" is null, false is returned.
     */

    public static boolean isEnabledFor(Logger logger, Level level) {
        boolean res = false;
        if (logger != null && level != null) {
            switch (level) {
            case TRACE:
                res = logger.isTraceEnabled();
                break;
            case DEBUG:
                res = logger.isDebugEnabled();
                break;
            case INFO:
                res = logger.isInfoEnabled();
                break;
            case WARN:
                res = logger.isWarnEnabled();
                break;
            case ERROR:
                res = logger.isErrorEnabled();
                break;
            }
        }
        return res;
    }
}

Điều này sẽ dễ sử dụng hơn với tham số args đa dạng (Đối tượng ...).
Anonymoose

"org.slf4j.Logger" có khá nhiều chữ ký của phương thức ghi nhật ký không được xử lý trong lớp trên, do đó, một tiện ích mở rộng có thể được đảm bảo: slf4j.org/api/org/slf4j/Logger.html
David Tonhofer

1
Tôi nghĩ rằng việc triển khai này sẽ thêm một thay đổi không mong muốn. Khi bạn sử dụng call logger.info (...), trình ghi nhật ký có quyền truy cập vào lớp và phương thức của người gọi và nó có thể được thêm tự động vào mục nhật ký. Bây giờ, với việc triển khai này, nhật ký cuộc gọi (logger, level, txt) sẽ tạo ra một mục nhật ký sẽ luôn có cùng một trình gọi: Loglevel.log. Tôi nói đúng chứ?
Domin

@Domin Xin chào, ý bạn là trình ghi nhật ký có thể kiểm tra ngăn xếp cuộc gọi hiện tại, sau đó trích xuất mục nhập cuối cùng để ghi nhật ký tự động, trường hợp này không đúng? Về nguyên tắc là có, nhưng trên thực tế, ngăn xếp sẽ lộn xộn hơn một chút ngay cả sau điều này cho đến khi thông báo thực sự được viết ra (đặc biệt, logback phải được gọi vào một thời điểm nào đó, sau đó là appender thực sự). Tôi nghĩ rằng vai trò của người phụ trách là loại bỏ các dòng ngăn xếp không thú vị, vì vậy bạn có thể điều chỉnh nó để loại bỏ mọi thứ cho đến và bao gồm cả lệnh gọi đến lớp Loglevel này.
David Tonhofer

@David, Vâng, bạn nói đúng :-). Tôi không chắc đó là nhiệm vụ của appender bởi vì trong trường hợp đó, bạn đang xác định sự phụ thuộc khó khăn giữa appender và log ... nhưng ... nó là một giải pháp. Cảm ơn David
Domin

14

Hãy thử chuyển sang Logback và sử dụng

ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger)LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
rootLogger.setLevel(Level.toLevel("info"));

Tôi tin rằng đây sẽ là lệnh gọi duy nhất để Đăng nhập và phần còn lại của mã của bạn sẽ không thay đổi. Logback sử dụng SLF4J và việc di chuyển sẽ không khó khăn gì, chỉ cần thay đổi các tệp cấu hình xml.

Hãy nhớ đặt lại mức nhật ký sau khi bạn hoàn tất.


Tôi đã sử dụng slf4j được Logback hỗ trợ và điều này ngay lập tức cho phép tôi xóa các bài kiểm tra đơn vị của mình. Cảm ơn!
Lambart

2
Đây là -1 đầu tiên của tôi, cảm ơn. Tôi tin rằng bạn đã sai. Logback sử dụng SLF4J, vì vậy câu trả lời là có liên quan.
Αλέκος

3
@AlexandrosGelbessis Bạn nên đọc lại câu hỏi. Nó được yêu cầu cho một phương pháp có thể ghi theo chương trình một thông báo nhật ký ở bất kỳ cấp độ nào. Bạn đang thay đổi cấp của trình ghi gốc cho tất cả các thư, không chỉ cho một thư.
Tháng Một

12

Bạn có thể thực hiện điều này bằng cách sử dụng Java 8 lambdas.

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;

public class LevelLogger {
    private static final Logger LOGGER = LoggerFactory.getLogger(LevelLogger.class);
    private static final Map<Level, LoggingFunction> map;

    static {
        map = new HashMap<>();
        map.put(Level.TRACE, (o) -> LOGGER.trace(o));
        map.put(Level.DEBUG, (o) -> LOGGER.debug(o));
        map.put(Level.INFO, (o) -> LOGGER.info(o));
        map.put(Level.WARN, (o) -> LOGGER.warn(o));
        map.put(Level.ERROR, (o) -> LOGGER.error(o));
    }

    public static void log(Level level, String s) {
        map.get(level).log(s);
    }

    @FunctionalInterface
    private interface LoggingFunction {
        public void log(String arg);
    }
}

Vâng ... nhưng bây giờ bạn cần sửa đổi cơ sở mã của mình để sử dụng API này cũng như hoặc thay vì slf4j. Nếu bạn sử dụng nó thay vì slf4j 1) nó có thể cần phải phong phú hơn, 2) nhiều (ít nhất) nhập khẩu cần được thay đổi và 3) lớp mới này phía trước slf4j thêm một chi phí khai thác bổ sung.
Stephen C

4
Cũng cần biết rằng khi bạn sử dụng giải pháp này, lớp thực hiện việc ghi nhật ký thực sự sẽ không được ghi lại (vì bộ ghi nhật ký được khởi tạo bằng LevelLogger), đây không phải là một điều tốt vì nó nói chung là thông tin rất hữu ích.
Dormouse

6

Điều này có thể được thực hiện với một enumvà một phương thức trợ giúp:

enum LogLevel {
    TRACE,
    DEBUG,
    INFO,
    WARN,
    ERROR,
}

public static void log(Logger logger, LogLevel level, String format, Object[] argArray) {
    switch (level) {
        case TRACE:
            logger.trace(format, argArray);
            break;
        case DEBUG:
            logger.debug(format, argArray);
            break;
        case INFO:
            logger.info(format, argArray);
            break;
        case WARN:
            logger.warn(format, argArray);
            break;
        case ERROR:
            logger.error(format, argArray);
            break;
    }
}

// example usage:
private static final Logger logger = ...
final LogLevel level = ...
log(logger, level, "Something bad happened", ...);

Bạn có thể thêm các biến thể khác của log, giả sử nếu bạn muốn các biến thể tương đương chung của SLF4J 1 tham số hoặc 2 tham số warn/ error/ vv. các phương pháp.


3
Đúng, nhưng mục đích của slf4j không phải viết các trình bao bọc nhật ký.
djjeck

5
Mục đích của SLF4J là cung cấp sự trừu tượng cho các khuôn khổ ghi nhật ký khác nhau. Nếu sự trừu tượng đó không cung cấp chính xác những gì bạn cần, bạn không có lựa chọn nào khác ngoài việc viết một phương thức trợ giúp. Cách thay thế duy nhất khác là đóng góp một phương pháp giống như phương pháp trong câu trả lời của tôi cho dự án SLF4J.
Richard Fearn

Tôi đồng ý, nhưng trong trường hợp này có những lưu ý, như vậy là bạn sẽ không thể cung cấp tệp và số dòng nữa, trừ khi bạn đã triển khai một giải pháp khác cho điều đó. Trong trường hợp này, tôi sẽ mắc kẹt với log4j, cho đến khi khung công tác hỗ trợ tính năng - điều này cuối cùng đã xảy ra thông qua một tiện ích mở rộng, hãy xem câu trả lời gần đây hơn của Robert Elliot.
djjeck


3

Tôi chỉ cần một cái gì đó như thế và nghĩ ra:

@RequiredArgsConstructor //lombok annotation
public enum LogLevel{

    TRACE(l -> l::trace),
    INFO (l -> l::info),
    WARN (l -> l::warn),
    ERROR(l -> l::error);

    private final Function<Logger, Consumer<String>> function;

    public void log(Logger logger, String message) {
        function.apply(logger).accept(message);
    }
}

sử dụng:

    LogLevel level = LogLevel.TRACE;
    level.log(logger, "message");

Trình ghi nhật ký được chuyển trong khi gọi, vì vậy thông tin lớp phải ổn và nó hoạt động tốt với chú thích @ Slf4j lombok.


Cảm ơn bạn rất nhiều vì cách tiếp cận tuyệt vời này - Tôi đã đăng một câu trả lời tương tự, dựa trên ý tưởng của bạn.
slartidan

DEBUGbị thiếu là hằng số.
slartidan

Giải pháp này sẽ luôn ghi nhật ký LogLeveldưới dạng lớp và logdưới dạng phương thức, điều này làm cho các bản ghi ít ý nghĩa hơn.
slartidan

2

Nó là không thể xác định một mức độ đăng nhập sjf4j 1.xra khỏi hộp. Nhưng có hy vọng cho slf4j 2.0để khắc phục sự cố . Trong 2.0, nó có thể trông như thế này:

// POTENTIAL 2.0 SOLUTION
import org.slf4j.helpers.Util;
import static org.slf4j.spi.LocationAwareLogger.*;

// does not work with slf4j 1.x
Util.log(logger, DEBUG_INT, "hello world!");

Trong khi đó, đối với slf4j 1.x, bạn có thể sử dụng cách giải quyết này:

Sao chép lớp này vào classpath của bạn:

import org.slf4j.Logger;
import java.util.function.Function;

public enum LogLevel {

    TRACE(l -> l::trace, Logger::isTraceEnabled),
    DEBUG(l -> l::debug, Logger::isDebugEnabled),
    INFO(l -> l::info, Logger::isInfoEnabled),
    WARN(l -> l::warn, Logger::isWarnEnabled),
    ERROR(l -> l::error, Logger::isErrorEnabled);

    interface LogMethod {
        void log(String format, Object... arguments);
    }

    private final Function<Logger, LogMethod> logMethod;
    private final Function<Logger, Boolean> isEnabledMethod;

    LogLevel(Function<Logger, LogMethod> logMethod, Function<Logger, Boolean> isEnabledMethod) {
        this.logMethod = logMethod;
        this.isEnabledMethod = isEnabledMethod;
    }

    public LogMethod prepare(Logger logger) {
        return logMethod.apply(logger);
    }

    public boolean isEnabled(Logger logger) {
        return isEnabledMethod.apply(logger);
    }
}

Sau đó, bạn có thể sử dụng nó như thế này:

Logger logger = LoggerFactory.getLogger(Application.class);

LogLevel level = LogLevel.ERROR;
level.prepare(logger).log("It works!"); // just message, without parameter
level.prepare(logger).log("Hello {}!", "world"); // with slf4j's parameter replacing

try {
    throw new RuntimeException("Oops");
} catch (Throwable t) {
    level.prepare(logger).log("Exception", t);
}

if (level.isEnabled(logger)) {
    level.prepare(logger).log("logging is enabled");
}

Điều này sẽ xuất ra một bản ghi như sau:

[main] ERROR Application - It works!
[main] ERROR Application - Hello world!
[main] ERROR Application - Exception
java.lang.RuntimeException: Oops
    at Application.main(Application.java:14)
[main] ERROR Application - logging is enabled

Nó có đáng không?

  • ProNó giữ vị trí mã nguồn (tên lớp, tên phương thức, số dòng sẽ trỏ đến mã của bạn )
  • ProBạn có thể dễ dàng xác định các biến , tham số và kiểu trả về nhưLogLevel
  • ProMã doanh nghiệp của bạn luôn ngắn gọn và dễ đọc và không cần thêm phụ thuộc nào .

Mã nguồn như một ví dụ tối thiểu được lưu trữ trên GitHub .


Lưu ý: LogMethodgiao diện cần được công khai để nó hoạt động với các lớp bên ngoài gói của nó. Ngoài ra, nó hoạt động như dự định. Cảm ơn!
andrebrait

1

API slf4j không thể tự động thay đổi cấp độ nhật ký nhưng bạn có thể tự định cấu hình đăng nhập (nếu sử dụng điều này). Trong trường hợp đó, hãy tạo lớp gốc cho bộ ghi nhật ký của bạn và triển khai bộ ghi nhật ký gốc với cấu hình mà bạn cần.

LoggerContext loggerContext = new LoggerContext();
ch.qos.logback.classic.Logger root = loggerContext.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);

// Configure appender
final TTLLLayout layout = new TTLLLayout();
layout.start(); // default layout of logging messages (the form that message displays 
// e.g. 10:26:49.113 [main] INFO com.yourpackage.YourClazz - log message

final LayoutWrappingEncoder<ILoggingEvent> encoder = new LayoutWrappingEncoder<>();
encoder.setCharset(StandardCharsets.UTF_8);
encoder.setLayout(layout);

final ConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<>();
appender.setContext(loggerContext);
appender.setEncoder(encoder);
appender.setName("console");
appender.start();

root.addAppender(appender);

Sau khi bạn định cấu hình bộ ghi nhật ký gốc (chỉ một lần là đủ), bạn có thể ủy quyền nhận bộ ghi nhật ký mới bằng cách

final ch.qos.logback.classic.Logger logger = loggerContext.getLogger(clazz);

Nhớ sử dụng như nhau loggerContext.

Thay đổi cấp độ nhật ký dễ dàng thực hiện với trình ghi nhật ký gốc được cung cấp từ loggerContext.

root.setLevel(Level.DEBUG);

1

Xác nhận câu trả lời Ondrej Skopek

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import org.slf4j.LoggerFactory;

var rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
rootLogger.setLevel(Level.TRACE);

Bạn sẽ nhận được kết quả:

2020-05-14 14: 01: 16,644 TRACE [] [oakcmMetrics] Nhân viên kiểm tra Chỉ số đã đăng ký có tên là MetricName [name = bufferpool-wait-time-total, group = producer-metrics, description = Tổng thời gian người khiếu nại chờ phân bổ không gian ., tags = {client-id = producer-2}]


0

Tôi vừa gặp phải một nhu cầu tương tự. Trong trường hợp của tôi, slf4j được định cấu hình bằng bộ điều hợp ghi nhật ký java (bộ điều hợp jdk14). Sử dụng đoạn mã sau, tôi đã quản lý để thay đổi mức gỡ lỗi trong thời gian chạy:

Logger logger = LoggerFactory.getLogger("testing");
java.util.logging.Logger julLogger = java.util.logging.Logger.getLogger("testing");
julLogger.setLevel(java.util.logging.Level.FINE);
logger.debug("hello world");

1
Giống như các câu trả lời khác, câu trả lời này không giải quyết được câu hỏi ban đầu mà là một vấn đề khác.
E-Riz

0

Dựa trên câu trả lời của massimo virgilio, tôi cũng đã quản lý để làm điều đó với slf4j-log4j bằng cách sử dụng nội quan. HTH.

Logger LOG = LoggerFactory.getLogger(MyOwnClass.class);

org.apache.logging.slf4j.Log4jLogger LOGGER = (org.apache.logging.slf4j.Log4jLogger) LOG;

try {
    Class loggerIntrospected = LOGGER.getClass();
    Field fields[] = loggerIntrospected.getDeclaredFields();
    for (int i = 0; i < fields.length; i++) {
        String fieldName = fields[i].getName();
        if (fieldName.equals("logger")) {
            fields[i].setAccessible(true);
            org.apache.logging.log4j.core.Logger loggerImpl = (org.apache.logging.log4j.core.Logger) fields[i].get(LOGGER);
            loggerImpl.setLevel(Level.DEBUG);
        }
    }
} catch (Exception e) {
    System.out.println("ERROR :" + e.getMessage());
}

0

Đây là một giải pháp lambda không thân thiện với người dùng như @Paul Croarkin theo một cách (cấp được vượt qua hai lần một cách hiệu quả). Nhưng tôi nghĩ (a) người dùng nên chuyển Logger; và (b) AFAIU, câu hỏi ban đầu không phải là yêu cầu một cách thuận tiện cho mọi nơi trong ứng dụng, chỉ một tình huống có ít cách sử dụng trong thư viện.

package test.lambda;
import java.util.function.*;
import org.slf4j.*;

public class LoggerLambda {
    private static final Logger LOG = LoggerFactory.getLogger(LoggerLambda.class);

    private LoggerLambda() {}

    public static void log(BiConsumer<? super String, ? super Object[]> logFunc, Supplier<Boolean> logEnabledPredicate, 
            String format, Object... args) {
        if (logEnabledPredicate.get()) {
            logFunc.accept(format, args);
        }
    }

    public static void main(String[] args) {
        int a = 1, b = 2, c = 3;
        Throwable e = new Exception("something went wrong", new IllegalArgumentException());
        log(LOG::info, LOG::isInfoEnabled, "a = {}, b = {}, c = {}", a, b, c);

        // warn(String, Object...) instead of warn(String, Throwable), but prints stacktrace nevertheless
        log(LOG::warn, LOG::isWarnEnabled, "error doing something: {}", e, e);
    }
}

Vì slf4j cho phép một Throwable (có dấu vết ngăn xếp nên được ghi lại) bên trong tham số varargs , tôi nghĩ không cần quá tải logphương thức trợ giúp cho những người tiêu dùng khác (String, Object[]).


0

Tôi đã có thể thực hiện việc này cho ràng buộc JDK14 bằng cách yêu cầu phiên bản SLF4J Logger đầu tiên và sau đó đặt mức cho ràng buộc - bạn có thể thử điều này cho liên kết Log4J.

private void setLevel(Class loggerClass, java.util.logging.Level level) {
  org.slf4j.LoggerFactory.getLogger(loggerClass);
  java.util.logging.Logger.getLogger(loggerClass.getName()).setLevel(level);
}

0

Phương pháp tôi sử dụng là nhập các mô-đun ch.qos.logback và sau đó nhập kiểu truyền dữ liệu slf4j Logger thành ch.qos.logback.classic.Logger. Phiên bản này bao gồm một phương thức setLevel ().

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;

Logger levelSet = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);

// Now you can set the desired logging-level
levelSet.setLevel( Level.OFF );

Để tìm ra các cấp độ Ghi nhật ký có thể có, bạn có thể phát nổ lớp ch.qos.logback để xem tất cả các giá trị có thể có cho Cấp độ :

prompt$ javap -cp logback-classic-1.2.3.jar ch.qos.logback.classic.Level

Kết quả như sau:

{
   // ...skipping
   public static final ch.qos.logback.classic.Level OFF;
   public static final ch.qos.logback.classic.Level ERROR;
   public static final ch.qos.logback.classic.Level WARN;
   public static final ch.qos.logback.classic.Level INFO;
   public static final ch.qos.logback.classic.Level DEBUG;
   public static final ch.qos.logback.classic.Level TRACE;
   public static final ch.qos.logback.classic.Level ALL;
}

-2

bằng cách sử dụng nội quan java, bạn có thể làm điều đó, ví dụ:

private void changeRootLoggerLevel(int level) {

    if (logger instanceof org.slf4j.impl.Log4jLoggerAdapter) {
        try {
            Class loggerIntrospected = logger.getClass();
            Field fields[] = loggerIntrospected.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                String fieldName = fields[i].getName();
                if (fieldName.equals("logger")) {
                    fields[i].setAccessible(true);
                    org.apache.log4j.Logger loggerImpl = (org.apache.log4j.Logger) fields[i]
                            .get(logger);

                    if (level == DIAGNOSTIC_LEVEL) {
                        loggerImpl.setLevel(Level.DEBUG);
                    } else {
                        loggerImpl.setLevel(org.apache.log4j.Logger.getRootLogger().getLevel());
                    }

                    // fields[i].setAccessible(false);
                }
            }
        } catch (Exception e) {
            org.apache.log4j.Logger.getLogger(LoggerSLF4JImpl.class).error("An error was thrown while changing the Logger level", e);
        }
    }

}

5
Đây rõ ràng đề cập đến log4j và không slf4j quát
Thorbjørn Ravn Andersen

-6

không, nó có một số phương thức, thông tin (), gỡ lỗi (), cảnh báo (), v.v. (điều này thay thế trường ưu tiên)

hãy xem tại http://www.slf4j.org/api/org/slf4j/Logger.html để biết toàn bộ api của Logger.


xin lỗi, tôi thấy những gì bạn đang hỏi bây giờ. không, không có cách chung nào để thay đổi cấp độ nhật ký trong thời gian chạy, nhưng bạn có thể dễ dàng triển khai phương pháp trợ giúp với trạng thái chuyển đổi.
chris

Có, nhưng sau đó bạn phải làm điều đó một lần cho mỗi phiên bản quá tải của phương thức "nhật ký".
Andrew Swan
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.