有什么方法可以只记录异常的简单名称而不从代码中显式检索它?
例如,通过调用
log.error(exception);
使用日志模式
%d{yyyy-MM-dd}|%-5level|%m%n
而不仅仅是记录异常堆栈跟踪
2018-01-01|ERROR|
mainPackage.foo.bar.RocketExplosionException: Houston we have a problem
at mainPackage.foo.bar.TestThrower.fire(TestThrower.java:22)
at mainPackage.foo.bar.TestThrower.readyToLaunch(TestThrower.java:17)
at mainPackage.ExceptionLauncher.main(ExceptionLauncher.java:38)
应记录具有异常简单名称的单独列
2018-01-01|ERROR|RocketExplosionException|
mainPackage.foo.bar.RocketExplosionException: Houston we have a problem
at mainPackage.foo.bar.TestThrower.fire(TestThrower.java:22)
at mainPackage.foo.bar.TestThrower.readyToLaunch(TestThrower.java:17)
at mainPackage.ExceptionLauncher.main(ExceptionLauncher.java:38)
您可以编写自己的自定义转化说明符。
为此,您需要在logback.xml
中为符号%exname
声明一个转换规则,如下所示:
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<conversionRule conversionWord="exname" converterClass="com.foo.ExceptionNameConverter" />
...
</configuration>
然后像这样声明ExceptionNameConverter
:
import ch.qos.logback.classic.pattern.ThrowableProxyConverter;
import ch.qos.logback.classic.spi.IThrowableProxy;
public class ExceptionNameConverter extends ThrowableProxyConverter {
@Override
protected String throwableProxyToString(IThrowableProxy tp) {
return tp.getClassName();
}
}
现在,使用此模式:
%d{yyyy-MM-dd}|%-5level|%exname|%m%n
以下日志语句:
logger.error("Boom!", new RuntimeException("ouch"));
将发出:
2018-09-26|ERROR|java.lang.RuntimeException|Boom!
正如 Andreas 所建议的那样,支持异常名称日志记录的一种方法是使用自定义Layout
而不是PatternLayout
示例布局:
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.classic.spi.ThrowableProxyUtil;
import ch.qos.logback.core.CoreConstants;
import ch.qos.logback.core.LayoutBase;
public class ErrorLoggingLayout extends LayoutBase<ILoggingEvent> {
private static final char SEP = '|';
@Override
public String doLayout(final ILoggingEvent event) {
StringBuilder sb = new StringBuilder(128);
sb.append(event.getTimeStamp() - event.getLoggerContextVO().getBirthTime());
sb.append(SEP);
sb.append(event.getLevel());
sb.append(SEP);
sb.append(event.getThreadName());
sb.append(SEP);
StackTraceElement frame = event.getCallerData()[0];
sb.append(extractSimpleName(frame.getClassName())).append('.').append(frame.getMethodName()).append(':').append(frame.getLineNumber());
sb.append(SEP);
IThrowableProxy throwableProxy = event.getThrowableProxy();
if (throwableProxy != null) {
String simpleName = extractSimpleName(throwableProxy.getClassName());
sb.append(simpleName);
}
sb.append(SEP);
sb.append(event.getFormattedMessage());
sb.append(CoreConstants.LINE_SEPARATOR);
if (throwableProxy != null) {
sb.append(ThrowableProxyUtil.asString(throwableProxy));
}
return sb.toString();
}
@NotNull
private String extractSimpleName(final String cName) {
int index = cName.lastIndexOf('.');
return cName.substring(index + 1);
}
}
这个结果是这样的
7645|ERROR|Thread-Name-0|RocketConsole.report:22|RocketExplosionException|custom msg
mainPackage.foo.bar.RocketExplosionException: Houston we have a problem
at mainPackage.foo.bar.TestThrower.fire(TestThrower.java:22)
at mainPackage.foo.bar.TestThrower.readyToLaunch(TestThrower.java:17)
at mainPackage.ExceptionLauncher.main(ExceptionLauncher.java:38)
但是,这种方法的一个缺点是输出格式可能与原始模式略有不同,并且格式化字段需要额外的努力。