本篇文章中涉及到的所有代码都已经上传到gitee中: gitee.com/sss123a/log…
java日志系列全解
# 03.java日志之log4j的基础组件和各种Appender
# 07.java日志之logback内部状态数据Status
# 09.java日志之logback的appender标签及其子标签全解析
logback内部日志status
记重点
- 通过
statusListener标签去自定义StatusListener
<!-- logback内部日志自定义输出,具体实现见下文 -->
<statusListener class="com.matio.logback.statuslistener.CusStatusListener"/>
<!-- logback内部日志输出到标准console中 -->
<!-- 这种方式和<configuration debug="true">等价,具体参考ConfigurationModelHandler -->
<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener"/>
<!-- logback内部日志输出到指定文件中 -->
<statusListener class="ch.qos.logback.core.status.OnFileStatusListener">
<filename>E:/test/logback.log</filename>
</statusListener>
- 系统属性
logback.statusListenerClass去自定义StatusListener,比如:
System.setProperty("logback.statusListenerClass","com.matio.logback.statuslistener.CusStatusListener");
或者
System.setProperty("logback.statusListenerClass","ch.qos.logback.core.status.OnConsoleStatusListener");
- 禁用logback内部日志
System.setProperty("logback.statusListenerClass","ch.qos.logback.core.status.NopStatusListener");
- 通过 Java 代码手动注册
StatusListener
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
StatusManager statusManager = lc.getStatusManager();
OnConsoleStatusListener onConsoleListener = new OnConsoleStatusListener();
statusManager.add(onConsoleListener);
logback内部日志结构
如果在解析配置文件或者打印日志的过程中出现警告或错误,logback会自动在控制台上打印其内部状态数据,也就是今天的主人翁status,它允许方便地访问 logback 的内部状态。
Status
logback每一条内部输出日志都抽象成一个status,根据其紧急程度依次分为InfoStatus、WarnStatus和ErrorStatus,其类图如下:
每一个
status都由以下几个部分组成:
int level; // 紧急程度:info、warn和error
final String message; // 日志内容,就是错误信息
final Object origin; // 由哪个类输出该日志
List<Status> childrenList;
Throwable throwable; // 错误error
long timestamp; // 记录status的时间戳
StatusManager
现在内部日志实体有了,那怎么样才能输出日志呢?
logback提供了一个StatusManager接口专门管理status
StatusManager默认只有一个实现BasicStatusManager
调用其add(Status);就可以输出一个内部日志status
List<Status> statusList = new ArrayList<Status>();
CyclicBuffer<Status> tailBuffer = new CyclicBuffer<Status>(150);
public void add(Status newStatus) {
// 回调StatusListener
fireStatusAddEvent(newStatus);
count++;
if (newStatus.getLevel() > level) {
level = newStatus.getLevel();
}
synchronized (statusListLock) {
if (statusList.size() < 150) {
statusList.add(newStatus);
} else {
tailBuffer.add(newStatus);
}
}
}
// 回调StatusListener
private void fireStatusAddEvent(Status status) {
synchronized (statusListenerListLock) {
for (StatusListener sl : statusListenerList) {
sl.addStatusEvent(status);
}
}
}
// 注册StatusListener
public boolean add(StatusListener listener) {
synchronized (statusListenerListLock) {
if (listener instanceof OnConsoleStatusListener) {
boolean alreadyPresent = checkForPresence(statusListenerList, listener.getClass());
if (alreadyPresent)
return false;
}
statusListenerList.add(listener);
}
return true;
}
主要逻辑见
fireStatusAddEvent(newStatus);
其实statusmanager还维护了一组statuslistener,正是由这些statuslistener来输出日志
List statusListenerList = new ArrayList();
StatusListener
StatusListener接口:
public interface StatusListener {
void addStatusEvent(Status status);
default boolean isResetResistant() {
return false;
}
}
它主要有以下实现:
- OnFileStatusListener:以追加方式输出到一个指定文件中
- OnErrorConsoleStatusListener:以System.err方式输出到console上
- OnConsoleStatusListener:以System.out方式输出到console上
- NopStatusListener:无操作
用户如何在自己的程序中添加logback内部日志呢?
StatusViaSLF4JLoggerFactory
自定义StatusListener
logback配置文件中
<!-- statusListener:StatusListenerAction 解析成 StatusListenerModel 交给 StatusListenerModelHandler
class:非空,反射生成StatusListener子实现,注册到Context.getStatusManager()中,顺便回调其(LifeCycle)start()方法
-->
<statusListener class="com.matio.logback.statuslistener.CusStatusListener"/>
statusListener标签的解析交由StatusListenerModelHandler实现,感兴趣可以去看看
自定义StatusListener实现类如下:
package com.matio.logback.statuslistener;
import ch.qos.logback.core.status.Status;
import ch.qos.logback.core.status.StatusListener;
public class CusStatusListener implements StatusListener {
@Override
public void addStatusEvent(Status status) {
String message = status.getMessage();
Throwable throwable = status.getThrowable();
System.out.println(throwable);
System.out.println(message);
}
}
启动后会发现CusStatusListener成功输出logback内部日志了,如下:
null
Added status listener of type [com.matio.logback.statuslistener.CusStatusListener]
null
End of configuration.
null
Registering current configuration as safe fallback point
null
No appenders present in context [default] for logger [com.matio.logback.statuslistener.StatusListenerTest].
当然也可以通过系统属性logback.statusListenerClass去自定义StatusListener
System.setProperty("logback.statusListenerClass","com.matio.logback.statuslistener.CusStatusListener");
其生效原理可以参考StatusListenerConfigHelper.installIfAsked(Context);,原理很简单
在没有警告或错误的情况下,如果您仍然希望检查 logback 的内部状态,那么您可以通过调用类StatusPrinter.print()来打印logback内部状态数据
// 假设SLF4J在当前环境中绑定了logback
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
// 打印logback的内部状态
StatusPrinter.print(lc);
}
logback关于配置这块可以参考logback官方文档: logback.qos.ch/manual/conf…