Ste*_*n C 43
没有办法做到这一点slf4j.
我想,缺少这个功能的原因是,几乎不可能构造一个Level类型slf4j,可以有效地映射到Level外观后面所有可能的日志记录实现中使用的(或等效)类型.或者,设计人员认为您的用例太不寻常,无法证明支持它的开销.
关于@ ripper234的用例(单元测试),我认为实用的解决方案是修改单元测试,以便在运行单元测试时强硬了解slf4j外观背后的日志系统.
Dav*_*fer 25
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;
}
}
Run Code Online (Sandbox Code Playgroud)
Αλέ*_*κος 12
尝试切换到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"));
Run Code Online (Sandbox Code Playgroud)
我相信这将是对Logback的唯一调用,其余代码将保持不变.Logback使用SLF4J,迁移将毫不费力,只需要更改xml配置文件.
记得在完成后重新设置日志级别.
Pau*_*kin 12
您可以使用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);
}
}
Run Code Online (Sandbox Code Playgroud)
无法在 sjf4j 中指定开箱即用的日志级别。1.x但 slf4j 有希望2.0解决这个问题。在 2.0 中,它可能看起来像这样:
// 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!");
Run Code Online (Sandbox Code Playgroud)
同时,对于 slf4j 1.x,您可以使用以下解决方法:
将此类复制到您的类路径中:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以像这样使用它:
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");
}
Run Code Online (Sandbox Code Playgroud)
这将输出如下日志:
// 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!");
Run Code Online (Sandbox Code Playgroud)
这值得么?
LogLevel作为最小示例的源代码托管在 GitHub 上。
这可以使用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", ...);
Run Code Online (Sandbox Code Playgroud)
您可以添加的其他变体log,比方说,如果你想SLF4J的1参数或2个参数的一般等价物warn/ error的/ etc.方法.
SLF4J v2.0 中的 Fluent API 引入了一种新方法,即Logger.atLevel(Level)用于实现期望的结果。
示例代码:
public void logAMessageAtGivenLevel(Level aLevel, String aMessage) {
Logger logger = .. // some slf4j logger of choice
logger.atLevel(aLevel).log(aMessage);
}
Run Code Online (Sandbox Code Playgroud)
NOPLoggingEventBuilder如果给定的记录器被禁用,默认实现将返回单例实例Level。LoggingEventBuilder正如名称 NOP 所示,该接口的这种实现不执行任何操作,而是为禁用的日志消息保留纳秒执行时间。
小智 5
我只是需要类似的东西并想出了:
@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);
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
LogLevel level = LogLevel.TRACE;
level.log(logger, "message");
Run Code Online (Sandbox Code Playgroud)
Logger 在调用期间传递,因此类信息应该没问题,并且它与 @Slf4j lombok 注释配合得很好。
确认答案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);
Run Code Online (Sandbox Code Playgroud)
你会得到结果:
2020-05-14 14:01:16,644 TRACE [] [oakcmMetrics] 测试工作人员注册的指标名为 MetricName [name=bufferpool-wait-time-total, group= Producer-metrics, description=附加程序等待空间分配的总时间., 标签={client-id=生产者-2}]