[java] slf4j에서 런타임시 메시지의 로그 수준 설정

log4j를 사용하는 경우 Logger.log(Priority p, Object message)메서드를 사용할 수 있으며 런타임에 결정된 로그 수준에서 메시지를 기록하는 데 사용할 수 있습니다. 이 사실 과이 팁 을 사용하여 stderr를 특정 로그 수준의 로거로 리디렉션합니다.

slf4j에는 log()내가 찾을 수 있는 일반적인 방법 이 없습니다 . 위를 구현할 방법이 없다는 의미입니까?



답변

으로이 작업을 수행 할 수있는 방법이 없습니다 slf4j.

이 기능이 누락 된 이유 는 파사드 뒤의 가능한 모든 로깅 구현에서 사용되는 (또는 동등한) 유형에 효율적으로 매핑 될 수 있는 Level유형 을 구성하는 것이 거의 불가능하기 때문이라고 생각합니다 . 또는 설계자들은 귀하의 사용 사례가 이를 지원하는 오버 헤드를 정당화 하기에는 너무 이례적 이라고 결정 했습니다.slf4jLevel

에 관한 @ ripper234사용 사례 (단위 테스트), 나는 실용적인 솔루션은 단위 테스트를 실행할 때 로깅 시스템 …을 SLF4J 외관 뒤에 무엇의 하드 와이어 지식 단위 테스트 (들)을 수정할 생각합니다.


답변

Richard Fearn은 올바른 아이디어를 가지고 있으므로 그의 골격 코드를 기반으로 전체 클래스를 작성했습니다. 여기에 게시하기에 충분히 짧기를 바랍니다. 즐거움을 위해 복사 및 붙여 넣기. 마법 주문도 추가해야 할 것 같습니다. “이 코드는 공개 도메인에 공개되었습니다.”

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


답변

Logback으로 전환하고 사용하십시오.

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

나는 이것이 Logback에 대한 유일한 호출이며 나머지 코드는 변경되지 않을 것이라고 믿습니다. Logback은 SLF4J를 사용하며 마이그레이션은 간단하며 xml 구성 파일 만 변경하면됩니다.

완료 한 후에는 로그 수준을 다시 설정해야합니다.


답변

Java 8 람다를 사용하여이를 구현할 수 있습니다.

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


답변

이 작업은 enum및 도우미 메서드를 사용하여 수행 할 수 있습니다 .

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", ...);

logSLF4J의 1- 파라미터 또는 2- 파라미터 warn/ error/ etc 의 일반적인 등가물을 원한다면 의 다른 변형을 추가 할 수 있습니다 . 행동 양식.


답변

이 문제에 대한 완전한 SLF4J 호환 솔루션을 원하는 사람이라면 Lidalia SLF4J Extensions 를 확인하고 싶을 것입니다. Maven Central에 있습니다.


답변

나는 그저 그런 것이 필요했고 다음을 생각 해냈다.

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

용법:

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

Logger는 호출 중에 전달되므로 클래스 정보는 정상이어야하며 @ Slf4j lombok 주석과 잘 작동합니다.