Logback的LoggerContext

Logback的LoggerContext

image-20231016151727985

从图中可以看到,LoggerContext类除了ILoggerFactory接口之外,还实现了LifeCycle接口,并继承自ContextBase类。同时拥有LoggerContextListener和根Logger两个比较重要的成员变量。

大致介绍一下LoggerContext的字段和方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
*
* LoggerContext继承ContextBase并实现ILoggerFactory和LifeCycle
* LoggerContext将许多logback经典组件粘在一起。
* 原则上,每个logback经典组件实例都直接或间接地附加到LoggerContext实例。
* 同样重要的是,LoggerContext实现了{@link ILoggerFactory}作为{@link Logger}实例的制造源。
* @author Ceki Gulcu
*/
public class LoggerContext extends ContextBase implements ILoggerFactory, LifeCycle {

/** Default setting of packaging data in stack traces */
public static final boolean DEFAULT_PACKAGING_DATA = false;

/** 根Logger */
final Logger root;
/** size用来表示LoggerContext一共创建了几个Logger*/
private int size;

/**
* 没有Appender警告计数器 原则上只警告一次
*/
private int noAppenderWarning = 0;
/**
* 观察者模式 被观察者(主题):LoggerContext 观察者:多个LoggerContextListener
* LoggerContext监听器
*/
final private List<LoggerContextListener> loggerContextListenerList = new ArrayList<LoggerContextListener>();

/** loggerCache 缓存 所有LoggerContext创建的logger都放在这里*/
private Map<String, Logger> loggerCache;
/**loggerContextRemoteView是一个LoggerContext的VO对象,保存了LoggerContext的一些值 */
private LoggerContextVO loggerContextRemoteView;
/**
* 快速过滤器链
* 通过封装一个TurboFilterList对象(继承一个集合对象),可以将 获取过滤器链结果 方法封装到该对面里面 方法复用
*
* 我认为TurboFilterList实例不应放在LoggerContext作为一个成员变量
* 目前看来 TurboFilterList用来Logger对象的过滤 且LoggerContext没有用到TurboFilterList
* 反而后续 Logger对象需要维持一个LoggerContext的成员变量的引用(为了用TurboFilterList组件)
* 我认为应该在Logger类中拥有一个静态的TurboFilterList实例对象
*/
private final TurboFilterList turboFilterList = new TurboFilterList();
private boolean packagingDataEnabled = DEFAULT_PACKAGING_DATA;

private int maxCallerDataDepth = ClassicConstants.DEFAULT_MAX_CALLEDER_DATA_DEPTH;
/** resetCount是用来统计该LoggerContext调用过几次reset()方法*/
int resetCount = 0;
private List<String> frameworkPackages;

构造方法:这个方法基本上是只会调用一次的,在StaticLoggerBinder

1
2
3
4
5
6
7
8
9
10
11
12
public LoggerContext() {
super();
this.loggerCache = new ConcurrentHashMap<String, Logger>();

this.loggerContextRemoteView = new LoggerContextVO(this);
this.root = new Logger(Logger.ROOT_LOGGER_NAME, null, this);
this.root.setLevel(Level.DEBUG);
loggerCache.put(Logger.ROOT_LOGGER_NAME, root);
initEvaluatorMap();
size = 1;
this.frameworkPackages = new ArrayList<String>();
}

方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
private void incSize() {
size++;
}

int size() {
return size;
}
/**
*/
public Logger exists(String name) {
return (Logger) loggerCache.get(name);

final void noAppenderDefinedWarning(final Logger logger) {
if (noAppenderWarning++ == 0) {
getStatusManager().add(new WarnStatus("No appenders present in context [" + getName() + "] for logger [" + logger.getName() + "].", logger));
}
}

/**
* 获取所有创建的Loggers
* @return
*/
public List<Logger> getLoggerList() {
Collection<Logger> collection = loggerCache.values();
List<Logger> loggerList = new ArrayList<Logger>(collection);
Collections.sort(loggerList, new LoggerComparator());
return loggerList;
}


/**
* 重置LoggerContxet
*/
@Override
public void reset() {
resetCount++;
super.reset();
initEvaluatorMap();
initCollisionMaps();
root.recursiveReset();
resetTurboFilterList();
cancelScheduledTasks();
fireOnReset();
resetListenersExceptResetResistant();
resetStatusListeners();
}


/**
* 一层薄封装 我觉得没必要
* @param newFilter
*/
public void addTurboFilter(TurboFilter newFilter) {
turboFilterList.add(newFilter);
}

/**
* First processPriorToRemoval all registered turbo filters and then clear the registration
* list.
* 重置快速过滤器链表
* 我认为这个方法应该 封装在TurboFilterList类中
*/
public void resetTurboFilterList() {
for (TurboFilter tf : turboFilterList) {
tf.stop();
}
turboFilterList.clear();
}

/**
* getTurboFilterChainDecision_0_3OrMore
* getTurboFilterChainDecision_1
* getTurboFilterChainDecision_2
* 这一系列奇怪的方法是对TurboFilterList中getTurboFilterChainDecision()的薄封装
* 至于目的 据作者自己说是为了提高性能
* @param marker
* @param logger
* @param level
* @param format
* @param params
* @param t
* @return
*/
final FilterReply getTurboFilterChainDecision_0_3OrMore(final Marker marker, final Logger logger, final Level level, final String format,
final Object[] params, final Throwable t) {
if (turboFilterList.size() == 0) {
return FilterReply.NEUTRAL;
}
return turboFilterList.getTurboFilterChainDecision(marker, logger, level, format, params, t);
}

final FilterReply getTurboFilterChainDecision_1(final Marker marker, final Logger logger, final Level level, final String format, final Object param,
final Throwable t) {
if (turboFilterList.size() == 0) {
return FilterReply.NEUTRAL;
}
return turboFilterList.getTurboFilterChainDecision(marker, logger, level, format, new Object[] { param }, t);
}

final FilterReply getTurboFilterChainDecision_2(final Marker marker, final Logger logger, final Level level, final String format, final Object param1,
final Object param2, final Throwable t) {
if (turboFilterList.size() == 0) {
return FilterReply.NEUTRAL;
}
return turboFilterList.getTurboFilterChainDecision(marker, logger, level, format, new Object[] { param1, param2 }, t);
}

// === start listeners ==============================================

/**
* 观察者模式
* 添加一个监听者
* @param listener
*/
public void addListener(LoggerContextListener listener) {
loggerContextListenerList.add(listener);
}

/**
* 移除一个监听者
* @param listener
*/
public void removeListener(LoggerContextListener listener) {
loggerContextListenerList.remove(listener);
}


/**
* 清空所有的监听者
*/
private void resetAllListeners() {
loggerContextListenerList.clear();
}


void fireOnLevelChange(Logger logger, Level level) {
for (LoggerContextListener listener : loggerContextListenerList) {
listener.onLevelChange(logger, level);
}
}

/**
* 当上下文重置时 通知上下文监听者们
* 采用“拉”的方式 将自己的引用传递过去
*/
private void fireOnReset() {
for (LoggerContextListener listener : loggerContextListenerList) {
listener.onReset(this);
}
}

/**
* 当启动上下文时 通知上下文监听者们
*/
private void fireOnStart() {
for (LoggerContextListener listener : loggerContextListenerList) {
listener.onStart(this);
}
}

/**
* 当停止上下文时 通知上下文监听者们
*/
private void fireOnStop() {
for (LoggerContextListener listener : loggerContextListenerList) {
listener.onStop(this);
}
}

// === end listeners ==============================================

/**
* 启动LoggerContxet
*/
public void start() {
super.start();
fireOnStart();
}

/**
* 停止LoggerContxet
*/
public void stop() {
reset();
fireOnStop();
resetAllListeners();
super.stop();
}

接下来我们重点介绍一个核心方法getLogger(String name)LoggerContext如何创建Logger

  1. 如果namenull,抛出异常。
  2. 如果请求的是ROOT Logger,那么就直接返回root
  3. 然后检查一下请求的Logger是否已经创建过了,如果已经创建过,就直接从loggerCache中返回
  4. 如果还没创建过,那就开始逐层创建,比如请求的Loggernamecom.company.package.ClassName,那么一共会创建4个Logger,分别是Logger[com]Logger[com.company]Logger[com.company.package]Logger[com.company.package.ClassName]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public final Logger getLogger(final Class<?> clazz) {
return getLogger(clazz.getName());
}

@Override
public final Logger getLogger(final String name) {

if (name == null) {
throw new IllegalArgumentException("name argument cannot be null");
}

// if we are asking for the root logger, then let us return it without
// wasting time
//若是获取根logger直接返回
if (Logger.ROOT_LOGGER_NAME.equalsIgnoreCase(name)) {
return root;
}

int i = 0;
Logger logger = root;

// check if the desired logger exists, if it does, return it
// without further ado.
//查看loggerCache容器里面是否存在期望的logger,有则直接返回
Logger childLogger = (Logger) loggerCache.get(name);
// if we have the child, then let us return it without wasting time
if (childLogger != null) {
return childLogger;
}

// if the desired logger does not exist, them create all the loggers
// in between as well (if they don't already exist)
//如果期望的logger不存在,则创建中间所有的loggers
String childName;
while (true) {
int h = LoggerNameUtil.getSeparatorIndexOf(name, i);
if (h == -1) {
childName = name;
} else {
childName = name.substring(0, h);
}
// move i left of the last point
i = h + 1;
synchronized (logger) {
childLogger = logger.getChildByName(childName);
if (childLogger == null) {
childLogger = logger.createChildByName(childName);
loggerCache.put(childName, childLogger);
incSize();
}
}
logger = childLogger;
if (h == -1) {
return childLogger;
}
}
}

上面代码比较清晰,就是根据”.”来解析name,然后创建Logger,每创建一个Logger,都放到loggerCache中,并且把size++

创建Child Logger是有点讲究的,除了创建Logger实例之外,还有维护父子关系,并且处理Level继承的问题,这个是在Logger类的createChildByName(String childName)方法里实现的。我们来先来看看这些方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* The default size of child list arrays. The JDK 1.5 default is 10. We use a
* smaller value to save a little space.
* 根据名称创建子logger
*/

Logger createChildByName(final String childName) {
// 检查childName的合法性 是不是该logger的child
int i_index = LoggerNameUtil.getSeparatorIndexOf(childName, this.name.length() + 1);
if (i_index != -1) {
throw new IllegalArgumentException("For logger [" + this.name + "] child name [" + childName
+ " passed as parameter, may not include '.' after index" + (this.name.length() + 1));
}

if (childrenList == null) {
childrenList = new CopyOnWriteArrayList<Logger>();
}
Logger childLogger;
childLogger = new Logger(childName, this, this.loggerContext);
childrenList.add(childLogger);
childLogger.effectiveLevelInt = this.effectiveLevelInt;
return childLogger;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 根据名称查询子logger
* @param childName
* @return
*/
Logger getChildByName(final String childName) {
if (childrenList == null) {
return null;
} else {
int len = this.childrenList.size();
for (int i = 0; i < len; i++) {
final Logger childLogger_i = (Logger) childrenList.get(i);
final String childName_i = childLogger_i.getName();

if (childName.equals(childName_i)) {
return childLogger_i;
}
}
// no child found
return null;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/**
* 为该logger设置等级level
* @param newLevel
*/
public synchronized void setLevel(Level newLevel) {
//赋值level和当前level相等,因为level是固定的几个常量所以用==比较即可,则什么也不做并结束
if (level == newLevel) {
// nothing to do;
return;
}
//当该looger为root时,该level不能为null
if (newLevel == null && isRootLogger()) {
throw new IllegalArgumentException("The level of the root logger cannot be set to null");
}

//赋新值
level = newLevel;
if (newLevel == null) {//若newLevel为null,则继承父logger的effectiveLevelInt
effectiveLevelInt = parent.effectiveLevelInt;
newLevel = parent.getEffectiveLevel();
} else {//否则,effectiveLevelInt = newLevel.levelInt
effectiveLevelInt = newLevel.levelInt;
}

if (childrenList != null) {//若子loggers不为空,则为每一个子logger处理他们的effectiveLevelInt的值
int len = childrenList.size();
for (int i = 0; i < len; i++) {
Logger child = (Logger) childrenList.get(i);
// tell child to handle parent levelInt change
child.handleParentLevelChange(effectiveLevelInt);
}
}
// inform listeners
//通知
loggerContext.fireOnLevelChange(this, newLevel);
}

/**
* This method is invoked by parent logger to let this logger know that the
* prent's levelInt changed.
*
* 递归处理父logger的level变化,该loggere的effectiveLevelInt值处理
* @param newParentLevelInt
*/
private synchronized void handleParentLevelChange(int newParentLevelInt) {
// changes in the parent levelInt affect children only if their levelInt is
// null
//当该logger的level为空时,父logger的level变化才会影响子logger的effectiveLevelInt
//因为当该logger的level不为空时,effectiveLevelInt=level.levelInt,否则effectiveLevelInt继承父logger的effectiveLevelInt
if (level == null) {
effectiveLevelInt = newParentLevelInt;

// propagate the parent levelInt change to this logger's children
if (childrenList != null) {
int len = childrenList.size();
for (int i = 0; i < len; i++) {
Logger child = (Logger) childrenList.get(i);
child.handleParentLevelChange(newParentLevelInt);
}
}
}

/**
* 我写该递归函数的方式
* 先写该递归函数的终止条件
* if (level != null){
* return;
* }
* level为null时处理
* effectiveLevelInt = newParentLevelInt;
* if (childrenList != null) {
* int len = childrenList.size();
* for (int i = 0; i < len; i++) {
* Logger child = (Logger) childrenList.get(i);
* child.handleParentLevelChange(newParentLevelInt);
* }
* }
*/

}

构造方法:this.parent = parent里,设置了父Logger

1
2
3
4
5
Logger(String name, Logger parent, LoggerContext loggerContext) {
this.name = name;
this.parent = parent;
this.loggerContext = loggerContext;
}

总结一下创建Logger的完整流程

  1. 如果请求ROOT logger,则直接返回root
  2. 如果请求的Logger已经存在,则直接返回
  3. 如果请求的Logger尚未创建,则从ROOT开始,级联创建所有Logger
  4. 每创建一个Logger,都要设置父子关系,继承生效级别
  5. 每创建一个Logger,都将其放入loggerCache,并将size++