1. logger.debug(" Entry: " + i + " is " + String.valueOf(Entry[i]));
2. logger.debug(" Entry: {} is {}", i, Entry[i]);
3. if (logger.isDebugEnabled()) {
logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
}
logger.isDebugEnabled()
,另一次是
logger.debug()
方法内部也会做的判断。这样会带来一点点效率问题,所以综上所述,第二种是目前最优的写法,
提供占位符,以参数化的方式打印日志,既省了一次日志级别判断,又避免了字符串拼接。
(2) logback-core-${version}.jar
(3)logback-classic-${version}.jar
(4)logback.xml 或 logback-test.xml
public static ContextSelectorStaticBinder getSingleton() {
return singleton;
}
static ContextSelectorStaticBinder singleton = new ContextSelectorStaticBinder();
private final ContextSelectorStaticBinder contextSelectorBinder = ContextSelectorStaticBinder.getSingleton();
public ILoggerFactory getLoggerFactory() {
if (!initialized) {
return defaultLoggerContext;
}
if (contextSelectorBinder.getContextSelector() == null) {
throw new IllegalStateException("contextSelector cannot be null. See also " + NULL_CS_URL);
}
return contextSelectorBinder.getContextSelector().getLoggerContext();
}
1.当一个spring boot工程中存在多个日志框架时,加载顺序是怎样的?
static {
Map systems = new LinkedHashMap();
systems.put("ch.qos.logback.core.Appender",
"org.springframework.boot.logging.logback.LogbackLoggingSystem");
systems.put("org.apache.logging.log4j.core.impl.Log4jContextFactory",
"org.springframework.boot.logging.log4j2.Log4J2LoggingSystem");
systems.put("java.util.logging.LogManager",
"org.springframework.boot.logging.java.JavaLoggingSystem");
SYSTEMS = Collections.unmodifiableMap(systems);
}
public static LoggingSystem get(ClassLoader classLoader) {
String loggingSystem = System.getProperty(SYSTEM_PROPERTY);
if (StringUtils.hasLength(loggingSystem)) {
if (NONE.equals(loggingSystem)) {
return new NoOpLoggingSystem();
}
return get(classLoader, loggingSystem);
}
for (Map.Entry entry : SYSTEMS.entrySet()) {
if (ClassUtils.isPresent(entry.getKey(), classLoader)) {
return get(classLoader, entry.getValue());
}
}
throw new IllegalStateException("No suitable logging system located");
}
会按照logback->log4j2->java logging这样的顺序去查找,一旦找到某个日志框架的LoggingSystem存在,那么便会停止查找,然后以找到的这个配置为准
2.怎样控制logback当中同样的日志只打印一份
public final class Logger implements org.slf4j.Logger, LocationAwareLogger, AppenderAttachable, Serializable {
transient private boolean additive = true;
public void callAppenders(ILoggingEvent event) {
int writes = 0;
for (Logger l = this; l != null; l = l.parent) {
writes += l.appendLoopOnAppenders(event);
if (!l.additive) {
break;
}
}
// No appenders in hierarchy
if (writes == 0) {
loggerContext.noAppenderDefinedWarning(this);
}
}
从源码可以看出additive这个选项默认设置是true,所以需要在logback-spring.xml中手动设置additivity为false,这样就不会去找当前日志的父类,只打印当前日志
public abstract class AbstractLoggingSystem extends LoggingSystem {
protected String[] getSpringConfigLocations() {
String[] locations = getStandardConfigLocations();
for (int i = 0; i < locations.length; i++) {
String extension = StringUtils.getFilenameExtension(locations[i]);
locations[i] = locations[i].substring(0,
locations[i].length() - extension.length() - 1) + "-spring."
+ extension;
}
return locations;
}
protected abstract String[] getStandardConfigLocations();
@Override
protected String[] getStandardConfigLocations() {
return new String[] { "logback-test.groovy", "logback-test.xml", "logback.groovy",
"logback.xml" };
}
<appender name=
"async"
class
=
"ch.qos.logback.classic.AsyncAppender"
>
<queueSize>
500
</queueSize>
<discardingThreshold>
0
</discardingThreshold>
<appender-ref ref=
"FILE"
/>
</appender>
<appender name="FILE_PRUDENT" >
<file>logs/test.log</file>
<prudent>true</prudent>
</appender>
<appender name=
"SIFT"
class
=
"ch.qos.logback.classic.sift.SiftingAppender"
>
<discriminator>
<key>logid</key>
<defaultValue>unknown</defaultValue>
</discriminator>
<sift>
<appender name=
"FILE-${logid}"
class
=
"ch.qos.logback.core.FileAppender"
>
<file>logs/sift-${logid}.log</file>
<append>
false
</append>
</appender>
</sift>
</appender>
<appender name="ROOT_LOG_FILE_APPENDER" >
<!-- 文件路径 -->
<layout >
<pattern>%X{requestURI}</pattern>
</layout>
</appender>
public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)
return false;
else {
insert(e);
return true;
}
} finally {
lock.unlock();
}
}