-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathlogback.drawio
726 lines (726 loc) · 141 KB
/
logback.drawio
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
<mxfile host="Electron" modified="2024-10-08T10:35:40.546Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/21.6.5 Chrome/114.0.5735.243 Electron/25.3.1 Safari/537.36" etag="mLa9jjj_M31NzUeGRceR" version="21.6.5" type="device">
<diagram name="第 1 页" id="JqhDmuX6L9YFi_Qx25rx">
<mxGraphModel dx="4074" dy="977" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="jevOpthSYDo48ZPv_LFc-1" value="<h1><font style="font-size: 16px;">Logback 工作原理(1.5.6)</font></h1><div style=""><span style="background-color: initial;"><font style="font-size: 12px;">测试代码: SpringBoot-Labs/logging/logback。</font></span></div><div style=""><font style="font-size: 12px;">从源码梳理 Logback 工作原理,理解清楚内部各种组件的工作职责和关系。</font></div>" style="text;html=1;strokeColor=none;fillColor=none;spacing=5;spacingTop=-20;whiteSpace=wrap;overflow=hidden;rounded=0;" parent="1" vertex="1">
<mxGeometry x="40" y="10" width="420" height="90" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-7" value="" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;rounded=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-4" target="jevOpthSYDo48ZPv_LFc-6" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-9" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;rounded=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-4" target="jevOpthSYDo48ZPv_LFc-8" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-4" value="<b>获取 Logger 实例</b>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="40" y="240" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-11" value="" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;rounded=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-5" target="jevOpthSYDo48ZPv_LFc-10" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-4" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="jevOpthSYDo48ZPv_LFc-5" target="xc-GYIRrwOv2HIxgL6Iq-3">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-6" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="jevOpthSYDo48ZPv_LFc-5" target="xc-GYIRrwOv2HIxgL6Iq-5">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-8" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="jevOpthSYDo48ZPv_LFc-5" target="xc-GYIRrwOv2HIxgL6Iq-7">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-5" value="<b>日志输出</b>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="40" y="1000" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-15" value="" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;rounded=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-6" target="jevOpthSYDo48ZPv_LFc-14" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-6" value="通过 LoggerFactory 获取" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="280" y="240" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-8" value="通过 Lombok @Slf4j 注解获取<br><font color="#007fff">TODO</font>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="280" y="360" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-13" value="" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;rounded=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-10" target="jevOpthSYDo48ZPv_LFc-12" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-10" value="log.trace(...);<br>log.debug(...);<br>log.info(...);<br>log.error(...);<br><font color="#007fff">以 info 为例</font>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="280" y="990" width="200" height="80" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-58" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-12" target="jevOpthSYDo48ZPv_LFc-57" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-12" value="<b>filterAndLog_0_Or3Plus</b>(FQCN, null, Level.INFO, msg, null, null);<br><font color="#007fff">FQCN 是 Logback Logger 类的全限定名</font>" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="520" y="1000" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-17" value="" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;rounded=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-14" target="jevOpthSYDo48ZPv_LFc-16" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-14" value="Logger log = LoggerFactory.getLogger(<br>LogbackExample.class);" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="520" y="240" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-20" value="" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;rounded=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-16" target="jevOpthSYDo48ZPv_LFc-19" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-16" value="Logger logger = getLogger(clazz.getName());<br><font color="#007fff">以类名作为Logger名</font>" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="760" y="240" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-18" value="LoggerFactory" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="820" y="210" width="100" height="30" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-22" value="" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;rounded=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-19" target="jevOpthSYDo48ZPv_LFc-21" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-46" value="1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="jevOpthSYDo48ZPv_LFc-22" vertex="1" connectable="0">
<mxGeometry x="0.3929" y="3" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-26" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;rounded=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-19" target="jevOpthSYDo48ZPv_LFc-25" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-47" value="2" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="jevOpthSYDo48ZPv_LFc-26" vertex="1" connectable="0">
<mxGeometry x="0.905" y="2" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-19" value="<div><font color="#007fff">// 1 此测试中返回的是 <b>LoggerContext </b>实例</font></div><div>ILoggerFactory iLoggerFactory = <b>getILoggerFactory</b>();</div><div><font color="#007fff">// 2 name是类的全限定名的话会按每一层创建一个 Logger, 最后返回的以完整限定名为名的 Logger</font></div><div>return iLoggerFactory.<b>getLogger</b>(name);</div><div><font color="#007fff">先获取 LoggerFactory 实例,从后面看首次执行时才会执行初始化</font></div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="1000" y="240" width="440" height="100" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-24" value="" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;rounded=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-21" target="jevOpthSYDo48ZPv_LFc-23" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-45" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;rounded=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-21" target="jevOpthSYDo48ZPv_LFc-44" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-21" value="return <b>getProvider</b>()<br>.<b>getLoggerFactory</b>();" style="rounded=1;whiteSpace=wrap;html=1;align=center;" parent="1" vertex="1">
<mxGeometry x="1480" y="240" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-28" value="" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;rounded=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-23" target="jevOpthSYDo48ZPv_LFc-27" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-29" value="..." style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="jevOpthSYDo48ZPv_LFc-28" vertex="1" connectable="0">
<mxGeometry x="-0.0559" y="-1" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-23" value="<b>performInitialization</b>();<br><font color="#007fff">首次执行会执行LoggerFactory 的初始化</font>" style="rounded=1;whiteSpace=wrap;html=1;align=center;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="1720" y="240" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-52" value="" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;rounded=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-25" target="jevOpthSYDo48ZPv_LFc-51" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-25" value="获取Logger的逻辑是先看是不是 ROOT, 是 ROOT 直接返回根 Logger,<br>否则从 <b>loggerCache</b> 中查,存在则直接返回否则创建一个新的Logger 并缓存到 loggerCache" style="rounded=1;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
<mxGeometry x="1480" y="690" width="200" height="80" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-31" value="" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;rounded=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-27" target="jevOpthSYDo48ZPv_LFc-30" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-32" value="..." style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="jevOpthSYDo48ZPv_LFc-31" vertex="1" connectable="0">
<mxGeometry x="-0.1147" y="-1" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-36" value="1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="jevOpthSYDo48ZPv_LFc-31" vertex="1" connectable="0">
<mxGeometry x="0.7659" y="-4" relative="1" as="geometry">
<mxPoint y="-14" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-38" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;rounded=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-27" target="jevOpthSYDo48ZPv_LFc-37" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-39" value="2" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="jevOpthSYDo48ZPv_LFc-38" vertex="1" connectable="0">
<mxGeometry x="0.9322" y="1" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-27" value="<font color="#007fff"><b>//1 SPI 加载 SLF4JServiceProvider&nbsp;实现, 因为引入的 Logback, 这里实际加载到的是&nbsp;LogbackServiceProvider</b><br></font>List&lt;SLF4JServiceProvider&gt; providersList = <b>findServiceProviders</b>();<br>...<br><font color="#007fff">// provider 如果有多个,使用第一个</font><br><div>PROVIDER = (SLF4JServiceProvider)providersList.get(0);</div><div><font color="#007fff"><b>// 2</b>&nbsp;初始化选中的 Provider&nbsp;</font></div><div>PROVIDER.<b>initialize</b>();</div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;arcSize=4;" parent="1" vertex="1">
<mxGeometry x="1960" y="240" width="440" height="120" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-35" value="" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;rounded=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-30" target="jevOpthSYDo48ZPv_LFc-34" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-30" value="<div><font color="#007fff">//从这部分代码看到可以通过 “slf4j.provider” 手动指定我们要使用</font></div><font color="#007fff">SLF4JServiceProvider 实现,没有指定才会通过 SPI 加载<br></font><div>SLF4JServiceProvider explicitProvider = <b>loadExplicitlySpecified</b>(classLoaderOfLoggerFactory);</div><div>if (explicitProvider != null) {</div><div>&nbsp; &nbsp; providerList.add(explicitProvider);</div><div>&nbsp; &nbsp; return providerList;</div><div>} else {</div><div>&nbsp; &nbsp; ServiceLoader&lt;SLF4JServiceProvider&gt; serviceLoader = <b>getServiceLoader</b>(classLoaderOfLoggerFactory);</div><div>&nbsp; &nbsp; Iterator&lt;SLF4JServiceProvider&gt; iterator = serviceLoader.iterator();</div><div>&nbsp; &nbsp; while(iterator.hasNext()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; safelyInstantiate(providerList, iterator);</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; return providerList;</div><div>}</div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;arcSize=2;" parent="1" vertex="1">
<mxGeometry x="2440" y="240" width="440" height="240" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-34" value="serviceLoader = ServiceLoader.<b>load</b>(<br><b>SLF4JServiceProvider</b>.class, classLoaderOfLoggerFactory);<br><font color="#007fff">SPI 加载 SLF4JServiceProvider 实现,这里是&nbsp;LogbackServiceProvider</font>" style="rounded=1;whiteSpace=wrap;html=1;align=left;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="2920" y="330" width="440" height="60" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-35" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="jevOpthSYDo48ZPv_LFc-37" target="xc-GYIRrwOv2HIxgL6Iq-34">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-36" value="..." style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="xc-GYIRrwOv2HIxgL6Iq-35">
<mxGeometry x="-0.25" y="-5" relative="1" as="geometry">
<mxPoint x="5" y="-5" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-37" value="<div></div><div><div><div>public void initialize() {</div><div><b><font color="#007fff">&nbsp; &nbsp; // 这个就是 Logger 工厂</font></b></div><div>&nbsp; &nbsp; this.<b>defaultLoggerContext</b> = new <b>LoggerContext</b>();</div><div>&nbsp; &nbsp; this.defaultLoggerContext.setName("default");</div><div><font color="#007fff"><b>&nbsp; &nbsp; // 1 这里面做了一些初始化工作,包括解析 xml 配置文件,初始化组件</b></font></div><div>&nbsp; &nbsp; this.<b>initializeLoggerContext</b>();</div><div>&nbsp; &nbsp; this.defaultLoggerContext.start();</div><div>&nbsp; &nbsp; this.<b>markerFactory</b> = new BasicMarkerFactory();</div><div>&nbsp; &nbsp; this.<b>mdcAdapter</b> = new LogbackMDCAdapter();</div><div>&nbsp; &nbsp; this.defaultLoggerContext.setMDCAdapter(this.mdcAdapter);</div><div>}</div></div></div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;arcSize=2;" parent="1" vertex="1">
<mxGeometry x="2440" y="520" width="440" height="160" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-40" value="LogbackServiceProvider" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="2585" y="490" width="150" height="30" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-50" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;endArrow=open;endFill=0;rounded=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-42" target="jevOpthSYDo48ZPv_LFc-49" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-42" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>LogbackServiceProvider</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;">private LoggerContext <b>defaultLoggerContext</b>;</p><p style="margin:0px;margin-left:4px;">private IMarkerFactory <b>markerFactory</b>;</p><p style="margin:0px;margin-left:4px;">private LogbackMDCAdapter <b>mdcAdapter</b>;</p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-440" y="120" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-44" value="return this.<b>defaultLoggerContext</b>;" style="rounded=1;whiteSpace=wrap;html=1;align=center;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="1720" y="400" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-48" value="<font style="font-size: 12px;">从源码中提取出来的重要信息:<br style=""></font><ul style="font-size: 12px;"><li style=""><font style="font-size: 12px;">每个Logger实例都有且仅有一个唯一的名字,根 Logger 的名字是 ROOT</font></li><li style=""><font style="font-size: 12px;">Logger 之间是一种树型关系,树的根是 ROOT Logger</font></li><li style=""><font style="font-size: 12px;">各组件的关系:<br></font><b>Logger</b> 通过 <b>Appender</b> 输出日志;<b>Appender</b> 可以绑定多个 <b>Filter</b> 对日志事件(LoggingEvent)进行过滤(比如按日志级别选择输出);<br>日志如果有参数输出前需要借助 MessageFormatter 格式化,还需要借助 <b>Encoder</b> 进行序列化;<br><b>Encoder</b> 中通过布局 <b>Layout</b> 控制日志序列化的格式 ;<br><b>Layout</b> 则是由一组 <b>Converter</b> 组成,用于将格式中每一个片段替换成具体的值 ( Logback 支持的所有 Pattern 片段及对应的 Converter 可以在 PatternLayout <b>DEFAULT_CONVERTER_MAP</b> 中查看 )。</li></ul>" style="text;html=1;align=left;verticalAlign=top;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="480" y="10" width="1120" height="150" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-49" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>LoggerContext&nbsp;</b><br></p><div style="text-align: center;">extends ContextBase implements <b>ILoggerFactory</b>, LifeCycle</div><hr size="1"><p style="margin:0px;margin-left:4px;"><b><font color="#007fff">Logger 上下文(Logger容器),且是 Logger 工厂</font></b></p><p style="margin:0px;margin-left:4px;"><b><font color="#007fff"><br></font></b></p><p style="margin:0px;margin-left:4px;"><font style="" color="#007fff">// 根 Logger, Logger 之间组成了一颗树,ROOT Logger 是这颗树的根节点</font></p><p style="margin:0px;margin-left:4px;">final Logger <b>root</b> = new Logger("ROOT", (Logger)null, this);</p><p style="margin:0px;margin-left:4px;">private int size;</p><p style="margin:0px;margin-left:4px;">private int noAppenderWarning = 0;</p><p style="margin:0px;margin-left:4px;">private final List&lt;LoggerContextListener&gt; loggerContextListenerList = new ArrayList();</p><p style="margin:0px;margin-left:4px;"><b><font color="#007fff">// Logger Name -&gt; Logger 实例</font></b></p><p style="margin:0px;margin-left:4px;">private Map&lt;String, Logger&gt; <b>loggerCache</b> = new ConcurrentHashMap();</p><p style="margin:0px;margin-left:4px;">private LoggerContextVO loggerContextRemoteView = new LoggerContextVO(this);</p><p style="margin:0px;margin-left:4px;"><font color="#007fff">//</font></p><p style="margin:0px;margin-left:4px;">private final TurboFilterList <b>turboFilterList</b> = new TurboFilterList();</p><p style="margin:0px;margin-left:4px;">private boolean packagingDataEnabled = false;</p><p style="margin:0px;margin-left:4px;">SequenceNumberGenerator sequenceNumberGenerator = null;</p><p style="margin:0px;margin-left:4px;">MDCAdapter mdcAdapter;</p><p style="margin:0px;margin-left:4px;">private int maxCallerDataDepth = 8;</p><p style="margin:0px;margin-left:4px;">int resetCount = 0;</p><p style="margin:0px;margin-left:4px;"></p><p style="margin:0px;margin-left:4px;">private List&lt;String&gt; frameworkPackages;</p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="-1080" y="120" width="600" height="320" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-56" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-51" target="jevOpthSYDo48ZPv_LFc-55" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-51" value="<div><font color="#007fff">Logger 新建的逻辑,这段代码也挺重要,<b>对于理解Logger间的配置继承很重要</b></font></div><div>Logger logger = root;<br></div><div>...</div><div>String childName;</div><div>while (true) {</div><div>&nbsp; &nbsp; int h = LoggerNameUtil.getSeparatorIndexOf(name, i);</div><div>&nbsp; &nbsp; if (h == -1) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; childName = name;</div><div>&nbsp; &nbsp; } else {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; childName = name.substring(0, h);</div><div>&nbsp; &nbsp; }</div><div><span style="background-color: initial;"><br></span></div><div><span style="background-color: initial;">&nbsp; &nbsp; i = h + 1;</span><br></div><div>&nbsp; &nbsp; synchronized (logger) {</div><div><font color="#007fff"><span style="white-space: pre;">	</span>// 这里初始 logger 是 root logger, 这里先查下是否已创建,防止重复创建</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; childLogger = logger.<b>getChildByName</b>(childName);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (childLogger == null) {</div><div><font color="#007fff">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 为 logger 创建一个子 Logger</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; childLogger = logger.<b>createChildByName</b>(childName);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loggerCache.put(childName, childLogger);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; incSize();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; logger = childLogger;</div><div>&nbsp; &nbsp; if (h == -1) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return childLogger;</div><div>&nbsp; &nbsp; }</div><div>}</div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;arcSize=3;" parent="1" vertex="1">
<mxGeometry x="1720" y="520" width="440" height="420" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-53" value="<font color="#007fff"><b>比如这里创建名为&nbsp;top.kwseeker.labs.logging.LogbackExample 的 Logger, 实际上会创建 5个 Logger 实例<br>和 ROOT logger 共同组成一颗树: ROOT -&gt; top -&gt; top.kwseeker -&gt; ...<br></b></font><div style=""><div><font color="#007fff"><b>"top" -&gt; {Logger@2085} "Logger[top]"</b></font></div><div><font color="#007fff"><b>"top.kwseeker" -&gt; {Logger@2113} "Logger[top.kwseeker]"</b></font></div><div><font color="#007fff"><b>"top.kwseeker.labs" -&gt; {Logger@2143} "Logger[top.kwseeker.labs]"</b></font></div><div><font color="#007fff"><b>"top.kwseeker.labs.logging" -&gt; {Logger@2173} "Logger[top.kwseeker.labs.logging]"</b></font></div><div><font color="#007fff"><b>"top.kwseeker.labs.logging.LogbackExample" -&gt; {Logger@2202} "Logger[top.kwseeker.labs.logging.LogbackExample]"</b></font></div><div><br></div></div>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="1000" y="780" width="710" height="130" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-75" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;endArrow=open;endFill=0;" parent="1" source="jevOpthSYDo48ZPv_LFc-54" target="jevOpthSYDo48ZPv_LFc-74" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-54" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>Logger</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>Logger 实现,Logger 之间组成一颗树</b></font></p><p style="margin:0px;margin-left:4px;"><br></p><p style="margin:0px;margin-left:4px;">private String name;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff">// Logger 日志级别</font></p><p style="margin:0px;margin-left:4px;">transient private Level <b>level</b>;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff">// 继承的日志级别</font></p><p style="margin:0px;margin-left:4px;">transient private int <b>effectiveLevelInt</b>;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff">// 指向父节点</font></p><p style="margin:0px;margin-left:4px;">transient private Logger <b>parent</b>;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff">// 指向子节点</font></p><p style="margin:0px;margin-left:4px;">transient private List&lt;Logger&gt; <b>childrenList</b>;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>// 最重要的一个成员,记录与 Logger 绑定的 Appender 信息</b></font></p><p style="margin:0px;margin-left:4px;">transient private AppenderAttachableImpl&lt;ILoggingEvent&gt; <b>aai</b>;<br></p><p style="margin:0px;margin-left:4px;"><font color="#007fff">// 是否将日志输出到父Logger的 Appender</font></p><p style="margin:0px;margin-left:4px;">transient private boolean <b>additive</b> = true;<br></p><p style="margin:0px;margin-left:4px;">final transient LoggerContext <b>loggerContext</b>;<br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="-440" y="480" width="400" height="280" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-55" value="childLogger = new <b>Logger</b>(childName, this, this.loggerContext);<br>childrenList.add(childLogger);" style="rounded=1;whiteSpace=wrap;html=1;align=left;arcSize=17;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="2200" y="700" width="440" height="60" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-60" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-57" target="jevOpthSYDo48ZPv_LFc-59" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-61" value="1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="jevOpthSYDo48ZPv_LFc-60" vertex="1" connectable="0">
<mxGeometry x="0.1853" y="1" relative="1" as="geometry">
<mxPoint x="11" y="-35" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-63" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="jevOpthSYDo48ZPv_LFc-57" target="jevOpthSYDo48ZPv_LFc-62" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-64" value="2" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="jevOpthSYDo48ZPv_LFc-63" vertex="1" connectable="0">
<mxGeometry x="0.7163" y="3" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-57" value="<div><font color="#007fff"><b>// 1 TurboFilter 过滤校验</b></font></div><div>final FilterReply decision = <b>loggerContext</b><br>&nbsp; &nbsp; .<b>getTurboFilterChainDecision_0_3OrMore</b>(<span style="background-color: initial;">marker, this, level, msg,&nbsp;</span><span style="background-color: initial;">params, t);</span></div><div><br></div><div>if (decision == FilterReply.NEUTRAL) {</div><div>&nbsp; &nbsp; if (effectiveLevelInt &gt; level.levelInt) { <font color="#007fff">//经过过滤器后结果中立的话再判断下继承的可输出日志级别</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; return;</div><div>&nbsp; &nbsp; }</div><div>} else if (decision == FilterReply.DENY) {</div><div>&nbsp; &nbsp; return;</div><div>}</div><div><font color="#007fff"><b>// 2 输出日志</b></font></div><div><b>buildLoggingEventAndAppend</b>(localFQCN, marker, level, msg, params, t);</div>" style="rounded=1;whiteSpace=wrap;html=1;arcSize=4;align=left;" parent="1" vertex="1">
<mxGeometry x="760" y="1000" width="440" height="240" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-59" value="<div>if (turboFilterList.size() == 0) {&nbsp;<font color="#007fff">// 如果没有设置过滤器,则过滤结果:中立</font></div><div>&nbsp; &nbsp; return FilterReply.NEUTRAL;&nbsp;</div><div>}</div><div><font color="#007fff">// 查找调用栈,发现只有 LogbackMetrics 有使用,暂略</font></div><div>return <b>turboFilterList</b>.getTurboFilterChainDecision(marker, logger, level, format, params, t);</div>" style="rounded=1;whiteSpace=wrap;html=1;arcSize=8;align=left;" parent="1" vertex="1">
<mxGeometry x="1240" y="1000" width="440" height="100" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-68" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-62" target="jevOpthSYDo48ZPv_LFc-67" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-62" value="<div>LoggingEvent le = new <b>LoggingEvent</b>(localFQCN, this, level, msg, t, params);</div><div>le.addMarker(marker);</div><div><b>callAppenders</b>(le);</div>" style="rounded=1;whiteSpace=wrap;html=1;arcSize=8;align=left;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="1240" y="1180" width="440" height="80" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-65" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>LoggingEvent</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>Logger 事件,就是定义的某次日志输出行为</b></font></p><p style="margin:0px;margin-left:4px;"><br></p><p style="margin:0px;margin-left:4px;"><font color="#007fff">// Logger 实现类的全限定名</font></p><p style="margin:0px;margin-left:4px;">transient String fqnOfLoggerClass;</p><p style="margin:0px;margin-left:4px;">private String threadName;</p><p style="margin:0px;margin-left:4px;">private String <b>loggerName</b>;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff">// Logger 所属的 LoggerContext</font></p><p style="margin:0px;margin-left:4px;">private LoggerContext <b>loggerContext</b>;</p><p style="margin:0px;margin-left:4px;">private LoggerContextVO loggerContextVO;</p><p style="margin:0px;margin-left:4px;"><span style="background-color: initial;"><font color="#007fff">// 日志级别</font></span></p><p style="margin:0px;margin-left:4px;"><span style="background-color: initial;">private transient Level <b>level</b>;</span><br></p><p style="margin:0px;margin-left:4px;"><font color="#007fff">//日志消息体</font></p><p style="margin:0px;margin-left:4px;">private String <b>message</b>;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff">// 格式话之后的消息体,就是最终打印出来的消息体</font></p><p style="margin:0px;margin-left:4px;">transient String formattedMessage;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff">// 消息体后面的参数数组</font></p><p style="margin:0px;margin-left:4px;">private transient Object[] <b>argumentArray</b>;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff">// 用于记录异常信息</font></p><p style="margin:0px;margin-left:4px;">private ThrowableProxy <b>throwableProxy</b>;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff">// 异常调用栈信息</font></p><p style="margin:0px;margin-left:4px;">private StackTraceElement[] <b>callerDataArray</b>;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff">//&nbsp;</font></p><p style="margin:0px;margin-left:4px;">private List&lt;Marker&gt; <b>markerList</b>;</p><p style="margin:0px;margin-left:4px;">private Map&lt;String, String&gt; <b>mdcPropertyMap</b>;</p><p style="margin:0px;margin-left:4px;">List&lt;KeyValuePair&gt; <b>keyValuePairs</b>;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff">// 时间信息 java.time.Instant</font></p><p style="margin:0px;margin-left:4px;">private Instant <b>instant</b>;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff">// 时间戳</font></p><p style="margin:0px;margin-left:4px;">private long <b>timeStamp</b>;</p><p style="margin:0px;margin-left:4px;">private int <b>nanoseconds</b>;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff">// 序列号,需要配置&nbsp;SequenceNumberGenerator</font></p><p style="margin:0px;margin-left:4px;">private long <b>sequenceNumber</b>;</p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-440" y="800" width="400" height="520" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-66" value="Logger" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="590" y="970" width="60" height="30" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-70" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-67" target="jevOpthSYDo48ZPv_LFc-69" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-67" value="<div>int writes = 0;</div><div><font color="#007fff"><b>// 这里可以看到 Logback 先将日志输出到 Logger 对应的Appender, 然后如果设置了 additive == true 还会一级一级遍历父 logger 输出到对应的 Appender</b></font></div><div><b>for (Logger l = this; l != null; l = l.parent) {</b></div><div><b>&nbsp; &nbsp; <font color="#007fff">// 1</font></b></div><div>&nbsp; &nbsp; writes += l.<b>appendLoopOnAppenders</b>(event);</div><div>&nbsp; &nbsp; if (!l.additive) { <font color="#007fff">//对应配置中 logger 标签的 additivity 属性</font></div><div>&nbsp; &nbsp; &nbsp; &nbsp; break;</div><div>&nbsp; &nbsp; }</div><div>}</div><div><font color="#007fff">// 说明没有 Appender 接收日志输出</font></div><div>if (writes == 0) {</div><div>&nbsp; &nbsp; loggerContext.noAppenderDefinedWarning(this);</div><div>}</div>" style="rounded=1;whiteSpace=wrap;html=1;arcSize=5;align=left;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="1720" y="1120" width="440" height="200" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-73" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-69" target="jevOpthSYDo48ZPv_LFc-72" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-69" value="<div><font color="#007fff">//将日志信息打印到当前 Logger 的 Appender, 如果没有 Appender的话当前Logger是不会打印的,而是一级一级往上遍历交给父 Logger 打印</font><br></div><div>if (aai != null) {</div><div>&nbsp; &nbsp; return <b>aai</b>.<b>appendLoopOnAppenders</b>(event);</div><div>} else {</div><div>&nbsp; &nbsp; return 0;</div><div>}</div>" style="rounded=1;whiteSpace=wrap;html=1;arcSize=5;align=left;" parent="1" vertex="1">
<mxGeometry x="2200" y="1160" width="440" height="120" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-71" value="<font color="#007fff"><b>这样实现的好处是可以复用父 Logger 的配置,比如测试中明明没有给名为 top.kwseeker.labs.logging.LogbackExample 的 Logger 配置 Appender, 为何还是可以打印出日志?</b><br><b>就是因为最终是通过 ROOT Logger 将日志打印出来的, Root Logger 的 Appender 信息是一定要配置的</b><br></font>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="1720" y="1080" width="970" height="40" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-93" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="jevOpthSYDo48ZPv_LFc-72" target="jevOpthSYDo48ZPv_LFc-92" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="3140" y="1220" />
<mxPoint x="3140" y="1340" />
<mxPoint x="500" y="1340" />
<mxPoint x="500" y="1690" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-72" value="<div><div>int size = 0;</div><div>Appender&lt;E&gt;[] appenderArray = (Appender[])this.appenderList.asTypedArray();</div><div>int len = appenderArray.length;</div><div><font color="#007fff">// 一个 Logger 可能绑定多个 Appender</font></div><div>for(int i = 0; i &lt; len; ++i) {</div><div><b>&nbsp; &nbsp; appenderArray[i].doAppend(e);</b></div><div>&nbsp; &nbsp; ++size;</div><div>}</div><div>return size;</div></div>" style="rounded=1;whiteSpace=wrap;html=1;arcSize=5;align=left;" parent="1" vertex="1">
<mxGeometry x="2680" y="1150" width="440" height="140" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-77" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;endArrow=open;endFill=0;" parent="1" source="jevOpthSYDo48ZPv_LFc-74" target="jevOpthSYDo48ZPv_LFc-76" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-74" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>AppenderAttachableImpl</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>记录与 Logger 绑定的 Appender 容器</b></font></p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b><br></b></font></p><p style="margin:0px;margin-left:4px;"><font color="#007fff">// COWArrayList 是 Logback 重新封装的一个 COW 列表</font><br></p><p style="margin:0px;margin-left:4px;">private final COWArrayList&lt;Appender&lt;E&gt;&gt; <b>appenderList</b> = new COWArrayList(new Appender[0]);<br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-880" y="560" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-76" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>Appender (I)</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>日志输出目的地,可以理解为是一个 Writer, 有好几种实现</b></font></p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>比如:</b></font></p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>ConsoleAppender、A</b></font><b style="color: rgb(0, 127, 255); background-color: initial;">syncAppender、</b><b style="color: rgb(0, 127, 255); background-color: initial;">CyclicBufferAppender、OutputStreamAppender、FileAppender、RollingFileAppender、SMTPAppender、SyslogAppender 等等</b></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="-1320" y="560" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-80" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-78" target="jevOpthSYDo48ZPv_LFc-79" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-78" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>ConsoleAppender</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>将日志输出到终端的Appender</b></font></p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b><br></b></font></p><p style="margin:0px;margin-left:4px;">protected ConsoleTarget target;</p><p style="margin:0px;margin-left:4px;">protected boolean withJansi;</p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-880" y="1240" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-82" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-79" target="jevOpthSYDo48ZPv_LFc-81" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-50" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;endArrow=open;endFill=0;" parent="1" source="jevOpthSYDo48ZPv_LFc-79" target="I5ocxiANe00BZeKkWwZh-31" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="-1340" y="1120" />
<mxPoint x="-1340" y="1740" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-79" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>OutputStreamAppender</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>// LoggingEvent 编码器,用于将&nbsp;</b></font><font color="#007fff"><b>&nbsp;LoggingEvent 序列化</b></font></p><p style="margin:0px;margin-left:4px;">protected Encoder&lt;E&gt; <b>encoder</b>;</p><p style="margin:0px;margin-left:4px;">protected final ReentrantLock lock = new ReentrantLock(false);</p><p style="margin:0px;margin-left:4px;">private OutputStream outputStream;</p><p style="margin:0px;margin-left:4px;">boolean immediateFlush = true;</p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-1320" y="1040" width="400" height="160" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-83" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;dashed=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-81" target="jevOpthSYDo48ZPv_LFc-76" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-3" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.005;exitY=0.579;exitDx=0;exitDy=0;exitPerimeter=0;endArrow=open;endFill=0;" parent="1" source="jevOpthSYDo48ZPv_LFc-81" target="I5ocxiANe00BZeKkWwZh-2" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-81" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>UnsynchronizedAppenderBase&nbsp;</b><br></p><div style="text-align: center;">extends ContextAwareBase implements Appender&lt;E&gt;&nbsp;</div><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b><br></b></font></p><p style="margin:0px;margin-left:4px;">protected boolean started = false;</p><p style="margin:0px;margin-left:4px;">private ThreadLocal&lt;Boolean&gt; guard = new ThreadLocal();</p><p style="margin:0px;margin-left:4px;">protected String name;</p><p style="margin:0px;margin-left:4px;"><b><font color="#007fff">// 与 Appender 绑定的过滤器列表</font></b></p><p style="margin:0px;margin-left:4px;">private <b>FilterAttachableImpl</b>&lt;E&gt; <b>fai</b> = new FilterAttachableImpl();</p><p style="margin:0px;margin-left:4px;">private int statusRepeatCount = 0;</p><p style="margin:0px;margin-left:4px;">private int exceptionCount = 0;</p><p style="margin:0px;margin-left:4px;">static final int ALLOWED_REPEATS = 3;</p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-1320" y="760" width="400" height="240" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-86" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-84" target="jevOpthSYDo48ZPv_LFc-79" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-84" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>FileAppender</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>将日志输出到文件的Appender</b></font></p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b><br></b></font></p><p style="margin:0px;margin-left:4px;">public static final long DEFAULT_BUFFER_SIZE = 8192L;</p><p style="margin:0px;margin-left:4px;">protected static String COLLISION_WITH_EARLIER_APPENDER_URL = "http://logback.qos.ch/codes.html#earlier_fa_collision";</p><p style="margin:0px;margin-left:4px;">protected boolean append = true;</p><p style="margin:0px;margin-left:4px;">protected String fileName = null;</p><p style="margin:0px;margin-left:4px;">private boolean prudent = false;</p><p style="margin:0px;margin-left:4px;">private FileSize bufferSize = new FileSize(8192L);</p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-1320" y="1240" width="400" height="200" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-89" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-85" target="jevOpthSYDo48ZPv_LFc-87" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-85" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>AsyncAppender</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>异步输出日志的Appender</b></font></p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b><br></b></font></p><p style="margin:0px;margin-left:4px;">boolean includeCallerData = false;<br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-1760" y="1360" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-88" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-87" target="jevOpthSYDo48ZPv_LFc-81" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-87" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>AsyncAppenderBase</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>// 可以封装其他的 Appender 将它们改造成异步的, 比如 RollingFileAppender</b></font></p><p style="margin:0px;margin-left:4px;"><b>AppenderAttachableImpl</b>&lt;E&gt; <b>aai</b> = new AppenderAttachableImpl();</p><p style="margin:0px;margin-left:4px;">BlockingQueue&lt;E&gt; blockingQueue;</p><p style="margin:0px;margin-left:4px;">public static final int DEFAULT_QUEUE_SIZE = 256;</p><p style="margin:0px;margin-left:4px;">int queueSize = 256;</p><p style="margin:0px;margin-left:4px;">int appenderCount = 0;</p><p style="margin:0px;margin-left:4px;">static final int UNDEFINED = -1;</p><p style="margin:0px;margin-left:4px;">int discardingThreshold = -1;</p><p style="margin:0px;margin-left:4px;">boolean neverBlock = false;</p><p style="margin:0px;margin-left:4px;">AsyncAppenderBase&lt;E&gt;.Worker worker = new Worker();</p><p style="margin:0px;margin-left:4px;">public static final int DEFAULT_MAX_FLUSH_TIME = 1000;</p><p style="margin:0px;margin-left:4px;">int maxFlushTime = 1000;</p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-1760" y="1040" width="400" height="280" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-91" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-90" target="jevOpthSYDo48ZPv_LFc-84" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-90" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>RollingFileAppender</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>日志文件可以滚动压缩删除的FileAppender</b></font></p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b><br></b></font></p><p style="margin:0px;margin-left:4px;">File currentlyActiveFile;</p><p style="margin:0px;margin-left:4px;">TriggeringPolicy&lt;E&gt; triggeringPolicy;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff">// 滚动策略</font></p><p style="margin:0px;margin-left:4px;">RollingPolicy <b>rollingPolicy</b>;</p><p style="margin:0px;margin-left:4px;">Lock triggeringPolicyLock = new ReentrantLock();</p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-1320" y="1480" width="400" height="160" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-95" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-92" target="jevOpthSYDo48ZPv_LFc-94" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="740" y="1690" />
<mxPoint x="740" y="1510" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-98" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="jevOpthSYDo48ZPv_LFc-92" target="jevOpthSYDo48ZPv_LFc-96" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-99" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="jevOpthSYDo48ZPv_LFc-92" target="jevOpthSYDo48ZPv_LFc-97" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-101" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="jevOpthSYDo48ZPv_LFc-92" target="jevOpthSYDo48ZPv_LFc-100" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-92" value="<b>这里列举4种最常用的 Appender 实现的 doAppend() 方法实现</b>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="520" y="1660" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-103" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="jevOpthSYDo48ZPv_LFc-94" target="jevOpthSYDo48ZPv_LFc-102" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-94" value="<b>ConsoleAppender#doAppend(...)</b>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="760" y="1480" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-96" value="<b>FileAppender#doAppend(...)</b><br><font color="#007fff">TODO</font>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="760" y="1660" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-97" value="<b>RollingFileAppender#doAppend(...)</b><br><font style="" color="#007fff">TODO</font>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="760" y="1740" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-100" value="<b>AsyncAppender#doAppend(...)</b><br><font color="#007fff">TODO</font>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="760" y="1820" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-10" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=0.996;exitY=0.319;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="jevOpthSYDo48ZPv_LFc-102" target="I5ocxiANe00BZeKkWwZh-11" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="1480" y="1510" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-19" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="jevOpthSYDo48ZPv_LFc-102" target="I5ocxiANe00BZeKkWwZh-18" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-20" value="..." style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="I5ocxiANe00BZeKkWwZh-19" vertex="1" connectable="0">
<mxGeometry x="0.2229" y="-2" relative="1" as="geometry">
<mxPoint x="2" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="jevOpthSYDo48ZPv_LFc-102" value="<div style="font-size: 11px;">if (!Boolean.TRUE.equals(this.guard.get())) {</div><div style="font-size: 11px;">&nbsp; &nbsp; try {</div><div style="font-size: 11px;">&nbsp; &nbsp; &nbsp; &nbsp; this.guard.set(Boolean.TRUE);</div><div style="font-size: 11px;">&nbsp; &nbsp; &nbsp; &nbsp; ...</div><div style="font-size: 11px;"><font color="#007fff" style="font-size: 11px;"><b style="font-size: 11px;">&nbsp; &nbsp; &nbsp; &nbsp; // 1 遍历 fai (FilterAttachableImpl) 中的 Filter 列表依次执行各个过滤器的过滤检查</b></font></div><div style="font-size: 11px;">&nbsp; &nbsp; &nbsp; &nbsp; if (this.<b>getFilterChainDecision</b>(eventObject) == FilterReply.DENY) {</div><div style="font-size: 11px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return;</div><div style="font-size: 11px;">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="font-size: 11px;"><font color="#007fff" style="font-size: 11px;"><b>&nbsp; &nbsp; &nbsp; &nbsp; // 2 没有被拒绝就调用 Appender 的 append() 方法输出日志</b></font></div><div style="font-size: 11px;">&nbsp; &nbsp; &nbsp; &nbsp; this.<b>append</b>(eventObject);</div><div style="font-size: 11px;">&nbsp; &nbsp; } catch (Exception var6) {</div><div style="font-size: 11px;">&nbsp; &nbsp; &nbsp; &nbsp; if (this.exceptionCount++ &lt; 3) {</div><div style="font-size: 11px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.addError("Appender [" + this.name + "] failed to append.", var6);</div><div style="font-size: 11px;">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="font-size: 11px;">&nbsp; &nbsp; } finally {</div><div style="font-size: 11px;">&nbsp; &nbsp; &nbsp; &nbsp; this.guard.set(Boolean.FALSE);</div><div style="font-size: 11px;">&nbsp; &nbsp; }</div><div style="font-size: 11px;">}</div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;arcSize=3;fontSize=11;" parent="1" vertex="1">
<mxGeometry x="1000" y="1380" width="440" height="260" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-1" value="UnsynchronizedAppenderBase" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="1125" y="1350" width="190" height="30" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-5" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;endArrow=open;endFill=0;" parent="1" source="I5ocxiANe00BZeKkWwZh-2" target="I5ocxiANe00BZeKkWwZh-6" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="-1800" y="820" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-2" value="<div style="text-align: center;"><b>FilterAttachableImpl</b><span style="background-color: initial;">&nbsp;</span></div><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b><br></b></font></p><p style="margin:0px;margin-left:4px;">COWArrayList&lt;Filter&lt;E&gt;&gt; <b>filterList</b> = new COWArrayList(new Filter[0]);<br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-1760" y="760" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-6" value="<div style="text-align: center;"><b>Filter (A)</b><span style="background-color: initial;">&nbsp;</span></div><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p><p style="margin:0px;margin-left:4px;">private String name;</p><p style="margin:0px;margin-left:4px;">boolean start = false;</p><hr size="1"><p style="margin:0px;margin-left:4px;"><font color="#007fff">// 过滤逻辑的实现方法</font></p><p style="margin:0px;margin-left:4px;">public abstract FilterReply <b>decide</b>(E var1);<br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="-2200" y="760" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-8" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-7" target="I5ocxiANe00BZeKkWwZh-6" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-7" value="<div style="text-align: center;"><b>ThresholdFilter</b><b style="background-color: initial;">&nbsp;(A)</b><span style="background-color: initial;">&nbsp;</span></div><hr size="1"><p style="margin:0px;margin-left:4px;"><b><font color="#007fff">根据日志级别进行过滤</font></b></p><p style="margin:0px;margin-left:4px;"><br></p><p style="margin:0px;margin-left:4px;">Level level;<br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><font color="#007fff">// 过滤逻辑的实现方法</font></p><p style="margin:0px;margin-left:4px;">public abstract FilterReply <b>decide</b>(E var1);<br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-2200" y="920" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-13" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="I5ocxiANe00BZeKkWwZh-11" target="I5ocxiANe00BZeKkWwZh-12" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-11" value="<div>Filter&lt;E&gt;[] filterArrray = (Filter[])this.filterList.asTypedArray();</div><div>int len = filterArrray.length;</div><div>for(int i = 0; i &lt; len; ++i) {</div><div>&nbsp; &nbsp; FilterReply r = filterArrray[i].<b>decide</b>(event);</div><div>&nbsp; &nbsp; if (r == FilterReply.DENY || r == FilterReply.ACCEPT) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return r;</div><div>&nbsp; &nbsp; }</div><div>}</div><div>return FilterReply.NEUTRAL;</div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;arcSize=6;" parent="1" vertex="1">
<mxGeometry x="1480" y="1380" width="440" height="140" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-15" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-12" target="I5ocxiANe00BZeKkWwZh-14" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-12" value="<b>一个 Appender 可能通过 FilterAttachableImpl 绑定多个 Filter,&nbsp;这里列举种最常用的 Filter 实现的 decide() 方法</b>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="1960" y="1420" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-17" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-14" target="I5ocxiANe00BZeKkWwZh-16" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-14" value="<b>ThresholdFilter#decide(...)</b>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="2200" y="1420" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-16" value="<div style="font-size: 11px;">if (!isStarted()) {</div><div style="font-size: 11px;">&nbsp; &nbsp; return FilterReply.NEUTRAL;</div><div style="font-size: 11px;">}</div><div style="font-size: 11px;"><font color="#007fff" style="font-size: 11px;">// 仅仅是比较一下过滤器的日志级别和日志的级别</font></div><div style="font-size: 11px;">if (event.getLevel().<b style="font-size: 11px;">isGreaterOrEqual</b>(level)) {</div><div style="font-size: 11px;">&nbsp; &nbsp; return FilterReply.NEUTRAL;</div><div style="font-size: 11px;">} else {</div><div style="font-size: 11px;">&nbsp; &nbsp; return FilterReply.DENY;</div><div style="font-size: 11px;">}</div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;fontSize=11;arcSize=6;" parent="1" vertex="1">
<mxGeometry x="2440" y="1390" width="440" height="120" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-22" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1.002;exitY=0.593;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="I5ocxiANe00BZeKkWwZh-18" target="I5ocxiANe00BZeKkWwZh-21" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-25" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1.003;exitY=0.919;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="I5ocxiANe00BZeKkWwZh-18" target="I5ocxiANe00BZeKkWwZh-24" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-18" value="<div>if (event instanceof <b>DeferredProcessingAware</b>) {</div><div><font color="#007fff"><b>&nbsp; &nbsp; // 执行 LoggingEvent 的延迟处理(前面可以看到 LoggingEvent 到这里还是不完整的,有些字段为空),包括格式化日志消息、获取当前线程名、获取 MDC属性Map</b></font></div><div>&nbsp; &nbsp; ((DeferredProcessingAware)event).<b>prepareForDeferredProcessing</b>();</div><div>}</div><div><br></div><div>this.<b>writeOut</b>(event);</div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;arcSize=6;" parent="1" vertex="1">
<mxGeometry x="1480" y="1560" width="440" height="120" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-21" value="<div>this.getFormattedMessage();</div><div>this.getThreadName();</div><div><span style="background-color: initial;">this.getMDCPropertyMap();</span><br></div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;arcSize=10;" parent="1" vertex="1">
<mxGeometry x="1960" y="1560" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-23" value="LoggingEvent" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="2010" y="1530" width="100" height="30" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-27" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-24" target="I5ocxiANe00BZeKkWwZh-26" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-24" value="<div><font color="#007fff">// LoggingEvent 序列化</font></div><div>byte[] byteArray = this.<b>encoder</b>.<b>encode</b>(event);<br></div><div>this.<b>writeBytes</b>(byteArray);<br></div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;arcSize=10;" parent="1" vertex="1">
<mxGeometry x="1960" y="1640" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-29" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-26" target="I5ocxiANe00BZeKkWwZh-28" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-26" value="<div>一个 Appender 最多只有一个 Encoder, Encoder 有多种实现,这里列举种最常用的实现<br></div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;arcSize=10;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="2200" y="1640" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-41" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-28" target="I5ocxiANe00BZeKkWwZh-40" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-28" value="<div><b>PatternLayoutEncoder</b>#encode(...)<br></div>" style="rounded=1;whiteSpace=wrap;html=1;align=center;arcSize=10;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="2440" y="1640" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-31" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>Encoder (I)</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>用于将日志序列化的编码器</b></font></p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b><br></b></font></p><p style="margin:0px;margin-left:4px;">byte[] headerBytes();</p><p style="margin:0px;margin-left:4px;">byte[] encode(E var1);</p><p style="margin:0px;margin-left:4px;"></p><p style="margin:0px;margin-left:4px;">byte[] footerBytes();</p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="-1320" y="1680" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-36" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;dashed=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-32" target="I5ocxiANe00BZeKkWwZh-31" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-32" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>EncoderBase</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p><p style="margin:0px;margin-left:4px;">protected boolean started;<br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-1320" y="1840" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-37" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-33" target="I5ocxiANe00BZeKkWwZh-32" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-43" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.002;exitY=0.418;exitDx=0;exitDy=0;endArrow=open;endFill=0;exitPerimeter=0;" parent="1" source="I5ocxiANe00BZeKkWwZh-33" target="I5ocxiANe00BZeKkWwZh-42" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="-1319" y="2070" />
<mxPoint x="-1380" y="2070" />
<mxPoint x="-1380" y="1740" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-33" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>LayoutWrappingEncoder</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>借助 Layout 控制日志输出布局的 Encoder</b></font></p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b><br></b></font></p><p style="margin:0px;margin-left:4px;">protected Layout&lt;E&gt; <b>layout</b>;</p><p style="margin:0px;margin-left:4px;">private Charset charset;</p><p style="margin:0px;margin-left:4px;">ContextAware parent;</p><p style="margin:0px;margin-left:4px;">Boolean immediateFlush = null;</p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-1320" y="2000" width="400" height="160" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-38" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-34" target="I5ocxiANe00BZeKkWwZh-33" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-34" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>PatternLayoutEncoderBase</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>按特征值进行序列化编码的编码器</b></font></p><p style="margin:0px;margin-left:4px;"><br></p><p style="margin:0px;margin-left:4px;">String <b>pattern</b>;</p><p style="margin:0px;margin-left:4px;">protected boolean outputPatternAsHeader = false;</p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-1320" y="2200" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-39" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-35" target="I5ocxiANe00BZeKkWwZh-34" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-35" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>PatternLayoutEncoder</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-1320" y="2360" width="400" height="80" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-53" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-40" target="I5ocxiANe00BZeKkWwZh-52" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-40" value="<div style="font-size: 10px;"><font color="#007fff" style="font-size: 10px;"><b style="font-size: 10px;">// 遍历执行 Converter 链表中的 Converter 按照 Pattern 格式生成</b></font><font color="#007fff" style="font-size: 10px;"><b style="font-size: 10px;">日志消息</b></font></div><div style="font-size: 10px;">String txt = this.<b style="font-size: 10px;">layout</b>.<b style="font-size: 10px;">doLayout</b>(event);<br style="font-size: 10px;"></div><div style="font-size: 10px;"><font color="#007fff" style="font-size: 10px;">// 字符串转成字节数组</font></div><div style="font-size: 10px;">return this.<b style="font-size: 10px;">convertToBytes</b>(txt);<br style="font-size: 10px;"></div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;arcSize=10;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="2680" y="1630" width="200" height="80" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-42" value="<div style="text-align: center;"><b>Layout</b><b style="background-color: initial;">&nbsp;(I)</b></div><hr size="1"><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>布局, 用于控制日志输出的组成</b></font></p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b><br></b></font></p><p style="margin:0px;margin-left:4px;">String doLayout(E var1);</p><p style="margin:0px;margin-left:4px;">String getFileHeader();</p><p style="margin:0px;margin-left:4px;">String getPresentationHeader();</p><p style="margin:0px;margin-left:4px;">String getPresentationFooter();</p><p style="margin:0px;margin-left:4px;">String getFileFooter();</p><p style="margin:0px;margin-left:4px;">String getContentType();</p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="-1800" y="1680" width="400" height="160" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-45" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;dashed=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-44" target="I5ocxiANe00BZeKkWwZh-42" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-44" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>LayoutBase</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><span style="background-color: initial;">protected boolean started;</span><br></p><p style="margin:0px;margin-left:4px;">String fileHeader;</p><p style="margin:0px;margin-left:4px;">String fileFooter;</p><p style="margin:0px;margin-left:4px;">String presentationHeader;</p><p style="margin:0px;margin-left:4px;">String presentationFooter;</p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-1800" y="1880" width="400" height="160" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-47" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-46" target="I5ocxiANe00BZeKkWwZh-44" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-61" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.006;exitY=0.41;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;endArrow=open;endFill=0;exitPerimeter=0;" parent="1" source="I5ocxiANe00BZeKkWwZh-46" target="I5ocxiANe00BZeKkWwZh-59" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-46" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>PatternLayoutBase</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p><p style="margin:0px;margin-left:4px;">static final int INTIAL_STRING_BUILDER_SIZE = 256;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff">// 里面包含了一组 Converter, 以链表的方式保存</font></p><p style="margin:0px;margin-left:4px;">Converter&lt;E&gt; <b>head</b>;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>// 日志输出模板</b></font></p><p style="margin:0px;margin-left:4px;">String <b>pattern</b>;</p><p style="margin:0px;margin-left:4px;">protected PostCompileProcessor&lt;E&gt; postCompileProcessor;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>// Converter Map</b></font></p><p style="margin:0px;margin-left:4px;">Map&lt;String, String&gt; <b>instanceConverterMap</b> = new HashMap();</p><p style="margin:0px;margin-left:4px;">protected boolean outputPatternAsHeader = false;</p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-1800" y="2080" width="400" height="200" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-49" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-48" target="I5ocxiANe00BZeKkWwZh-46" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-48" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>PatternLayout</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><b><font color="#007fff">保存了所有Logback 支持的 Pattern 片段以及对应的 Converter</font></b></p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b><br></b></font></p><p style="margin:0px;margin-left:4px;">public static final Map&lt;String, String&gt; DEFAULT_CONVERTER_MAP = new HashMap&lt;String, String&gt;();</p><p style="margin:0px;margin-left:4px;">public static final Map&lt;String, String&gt; CONVERTER_CLASS_TO_KEY_MAP = new HashMap&lt;String, String&gt;();</p><p style="margin:0px;margin-left:4px;">public static final Map&lt;String, String&gt; <b>defaultConverterMap</b> = DEFAULT_CONVERTER_MAP;<br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-1800" y="2320" width="400" height="200" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-51" value="LayoutWrappingEncoder" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="2700" y="1600" width="160" height="30" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-56" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-52" target="I5ocxiANe00BZeKkWwZh-55" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-52" value="<div style="font-size: 10px;"><div style="font-size: 10px;">if (!isStarted()) {</div><div style="font-size: 10px;">&nbsp; &nbsp; return CoreConstants.EMPTY_STRING;</div><div style="font-size: 10px;">}</div><div style="font-size: 10px;">return <b>writeLoopOnConverters</b>(event);</div></div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;arcSize=10;fontSize=10;" parent="1" vertex="1">
<mxGeometry x="2920" y="1640" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-54" value="PatternLayout" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="2970" y="1610" width="100" height="30" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-1" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="I5ocxiANe00BZeKkWwZh-55" target="I5ocxiANe00BZeKkWwZh-73">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-55" value="<div style="font-size: 10px;"><div style="font-size: 10px;"><div>StringBuilder strBuilder = new StringBuilder(256);</div><div><font color="#007fff"><b>// PatternLayout 中包含了一组 Converter, head 指向 Converter链表中第一个 Converter</b></font></div><div>for(Converter&lt;E&gt; c = this.<b>head</b>; c != null; c = c.getNext()) {</div><div>&nbsp; &nbsp; c.<b>write</b>(strBuilder, event); <font color="#007fff">//转换Pattern中每一部分值附加到StringBuilder</font></div><div>}</div><div>return strBuilder.toString();</div></div></div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;arcSize=10;fontSize=10;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="3160" y="1620" width="280" height="100" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-57" value="PatternLayoutBase" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="3235" y="1590" width="130" height="30" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-59" value="<div style="text-align: center;"><b>Converter (A)</b><span style="background-color: initial;">&nbsp;</span></div><hr size="1"><p style="margin:0px;margin-left:4px;"><b><font color="#007fff">转换器,用于将布局中%开头的字段替换为具体的值,有几十种实现</font></b></p><p style="margin:0px;margin-left:4px;"><br></p><p style="margin:0px;margin-left:4px;"><font color="#007fff">// 单向链表的形式</font></p><p style="margin:0px;margin-left:4px;">Converter&lt;E&gt; next;<br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><font color="#007fff">// 过滤逻辑的实现方法</font></p><p style="margin:0px;margin-left:4px;">public abstract FilterReply <b>decide</b>(E var1);<br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="-2240" y="1680" width="400" height="160" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-70" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-63" target="I5ocxiANe00BZeKkWwZh-59" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-63" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>FormattingConverter</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><font color="#007fff">格式化转换器,比如&nbsp;%-16t 表示线程名最小宽度16</font><font color="#007fff">左对齐</font></p><p style="margin:0px;margin-left:4px;"><br></p><p style="margin:0px;margin-left:4px;"><span style="background-color: initial;">static final int INITIAL_BUF_SIZE = 256;</span><br></p><p style="margin:0px;margin-left:4px;">static final int MAX_CAPACITY = 1024;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>// 记录从配置中解析的格式信息</b></font></p><p style="margin:0px;margin-left:4px;"><b>FormatInfo</b> <b>formattingInfo</b>;</p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-2240" y="1880" width="400" height="160" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-69" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-64" target="I5ocxiANe00BZeKkWwZh-63" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-64" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>DynamicConverter</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;">ContextAwareBase cab = new ContextAwareBase(this);</p><p style="margin:0px;margin-left:4px;">private List&lt;String&gt; optionList;</p><p style="margin:0px;margin-left:4px;">protected boolean started = false;</p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-2240" y="2080" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-68" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;endArrow=block;endFill=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-65" target="I5ocxiANe00BZeKkWwZh-64" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-65" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>ClassicConverter</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><font color="#007fff">空类型</font></p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;" parent="1" vertex="1">
<mxGeometry x="-2240" y="2240" width="400" height="80" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-67" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=block;endFill=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-66" target="I5ocxiANe00BZeKkWwZh-65" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-66" value="<p style="margin: 4px 0px 0px; text-align: center;"><b>DateConverter</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p><p style="margin:0px;margin-left:4px;"><br></p><p style="margin:0px;margin-left:4px;">long lastTimestamp = -1;</p><p style="margin:0px;margin-left:4px;">String timestampStrCache = null;</p><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>// 内部封装的 DateTimeFormatter</b></font>&nbsp;</p><p style="margin:0px;margin-left:4px;">CachingDateFormatter cachingDateFormatter = null;</p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="-2240" y="2360" width="400" height="160" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-71" value="<font color="#007fff"><b>比如&nbsp;&lt;pattern&gt;%d{yy-MM-dd.HH:mm:ss.SSS} [%-16t] %-5p %-22c{0}%X{ServiceId} -%X{trace-id} %m%n&lt;/pattern&gt; 配置会被解析为一组 Converter 链表<br>链表从头到尾依次是:<br>DateConverter -&gt; LiteralConverter -&gt; ThreadConverter -&gt; LiteralConverter -&gt; LevelConverter -&gt; LiteralConverter -&gt; LoggerConverter -&gt; MDCConverter -&gt;&nbsp;<br>LiteralConverter -&gt;&nbsp;MDCConverter -&gt;&nbsp;LiteralConverter -&gt; MessageConverter -&gt; LineSeparatorConverter -&gt; ThrowableProxyConverter</b></font>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="3470" y="1620" width="890" height="70" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-72" value="<font color="#007fff"><b>比如&nbsp;&lt;pattern&gt;%d{yy-MM-dd.HH:mm:ss.SSS} [%-16t] %-5p %-22c{0}%X{ServiceId} -%X{trace-id} %m%n&lt;/pattern&gt; 配置会被解析为一组 Converter 链表<br>链表从头到尾依次是:<br>DateConverter -&gt; LiteralConverter -&gt; ThreadConverter -&gt; LiteralConverter -&gt; LevelConverter -&gt; LiteralConverter -&gt; LoggerConverter -&gt; MDCConverter -&gt;&nbsp;<br>LiteralConverter -&gt;&nbsp;MDCConverter -&gt;&nbsp;LiteralConverter -&gt; MessageConverter -&gt; LineSeparatorConverter -&gt; ThrowableProxyConverter</b></font>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="-2240" y="1595" width="890" height="70" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-75" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-73" target="I5ocxiANe00BZeKkWwZh-74" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-77" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="I5ocxiANe00BZeKkWwZh-73" target="I5ocxiANe00BZeKkWwZh-76" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-79" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="I5ocxiANe00BZeKkWwZh-73" target="I5ocxiANe00BZeKkWwZh-78" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-84" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="I5ocxiANe00BZeKkWwZh-73" target="I5ocxiANe00BZeKkWwZh-80" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-85" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="I5ocxiANe00BZeKkWwZh-73" target="I5ocxiANe00BZeKkWwZh-81" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-86" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="I5ocxiANe00BZeKkWwZh-73" target="I5ocxiANe00BZeKkWwZh-82" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-87" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="I5ocxiANe00BZeKkWwZh-73" target="I5ocxiANe00BZeKkWwZh-83" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-73" value="<div>一个 Layout Pattern 被解析为 Converter 链表后,通常会包含多种Converter 实现,这里展示几种较为重要的实现</div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;arcSize=10;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="2200" y="1760" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-89" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="I5ocxiANe00BZeKkWwZh-74" target="I5ocxiANe00BZeKkWwZh-88" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-74" value="<div><b>DateConverter</b>#write(...)</div>" style="rounded=1;whiteSpace=wrap;html=1;align=center;arcSize=10;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="2440" y="1760" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-76" value="<b>ThreadConverter</b><span style="background-color: initial;">#write(...)</span><b><br></b>" style="rounded=1;whiteSpace=wrap;html=1;align=center;arcSize=10;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="2440" y="1840" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-78" value="<span style="background-color: initial;"><b>LevelConverter</b>#write(...)</span><b><br></b>" style="rounded=1;whiteSpace=wrap;html=1;align=center;arcSize=10;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="2440" y="1920" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-80" value="<span style="background-color: initial;"><b>LoggerConverter</b>#write(...)<br></span><b><font color="#007fff">用于打印FQN(Logger类全限定名)中<br>的类名</font><br></b>" style="rounded=1;whiteSpace=wrap;html=1;align=center;arcSize=10;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="2440" y="2000" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-81" value="<span style="background-color: initial;"><b>MDCConverter</b>#write(...)<br></span><b><font color="#007fff">转换MDC属性占位符</font><br></b>" style="rounded=1;whiteSpace=wrap;html=1;align=center;arcSize=10;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="2440" y="2080" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-82" value="<span style="background-color: initial;"><b>MessageConverter</b>#write(...)</span><b><br></b>" style="rounded=1;whiteSpace=wrap;html=1;align=center;arcSize=10;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="2440" y="2160" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-83" value="<span style="background-color: initial;"><b>ThrowableProxyConverter</b>#write(...)<br></span><b><font color="#007fff">处理异常信息,递归遍历异常栈转成String, 然后格式化追加到 StringBuilder</font><br></b>" style="rounded=1;whiteSpace=wrap;html=1;align=center;arcSize=10;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="2440" y="2238" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-88" value="long timestamp = le.<b>getTimeStamp</b>();<br>return cachingDateFormatter<br>.format(timestamp);" style="rounded=1;whiteSpace=wrap;html=1;align=center;arcSize=10;" parent="1" vertex="1">
<mxGeometry x="2680" y="1760" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-90" value="<font color="#007fff">用于转换 %d, 比如测试中的 %d{yy-MM-dd.HH:mm:ss.SSS},<br>从 LoggingEvent 获取日志时间戳使用 CachingDateFormatter 转换成&nbsp;yy-MM-dd.HH:mm:ss.SSS 格式</font>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="2890" y="1770" width="560" height="40" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-91" value="<font color="#007fff">用于转换 %t, 比如测试中的 %-16t,<br>从 LoggingEvent 获取线程名,然后经过最小宽度16左对齐处理后,追加到 StringBuilder<br>比如线程名 “main” 格式化处理后是 “main&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ”, 后边12位填充空格<br></font>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="2650" y="1840" width="490" height="60" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-92" value="<div><font color="#007fff">关于格式信息,比如 %-16t&nbsp;</font></div><div><font color="#007fff">this.formattingInfo = {FormatInfo@2284}</font></div><div><font color="#007fff">&nbsp;min = 16 //最小宽度</font></div><div><font color="#007fff">&nbsp;max = 2147483647 //最大宽度</font></div><div><font color="#007fff">&nbsp;leftPad = false<span style="white-space: pre;">	</span>//是否左边填充空格</font></div><div><font color="#007fff">&nbsp;leftTruncate = true&nbsp; //是否删除左边溢出的字符</font></div>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="-2480" y="1945" width="270" height="100" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-93" value="<font color="#007fff">用于转换 %p, 比如测试中的 %-5p,<br>从 LoggingEvent 获取日志级别名,然后经过最小宽度5左对齐处理后,追加到 StringBuilder<br>比如日志事件级别 “INFO” 格式化处理后是 “INFO ”<br></font>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="2650" y="1920" width="510" height="60" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-94" value="<font color="#007fff">用于转换 %c, 比如测试中的 %-22c{0},<br>从 LoggingEvent 获取Logger 名,截取类名,然后经过最小宽度22左对齐处理后,追加到 StringBuilder<br></font>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="2650" y="2010" width="570" height="40" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-95" value="<font color="#007fff">用于转换 %X, 比如测试中的 %X{ServiceId} %X{trace-id},<br>从 LoggingEvent 获取mdcPropertyMap,根据占位符key读取值替换占位符,关键是看 mdcPropertyMap 中的值是怎么写进去的,TODO<br></font>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="2650" y="2090" width="740" height="40" as="geometry" />
</mxCell>
<mxCell id="I5ocxiANe00BZeKkWwZh-96" value="<font color="#007fff">用于转换 %m,&nbsp;<br>从 LoggingEvent 获取 formattedMessage (这个值是前面prepareForDeferredProcessing中转换完成的),追加到 StringBuilder<br></font>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="2650" y="2170" width="680" height="40" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-2" value="<font style="" color="#007fff">用于转换异常信息,&nbsp;</font><span style="border-color: var(--border-color); text-align: center;"><font style="border-color: var(--border-color);" color="#007fff">,<br>异常并不会被 MessageConverter 处理直接加入 formattedMessage, 而是由此转换器递归遍历异常栈生成异常信息(String)</font></span><font color="#007fff">,然后格式化追加到 StringBuilder<br></font>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
<mxGeometry x="2650" y="2248" width="840" height="40" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-3" value="log.error(..., e);<br><font color="#007fff"><b>带有异常的日志输出流程</b>,异常会被保存到 LoggingEvent 最终由&nbsp;<b>ThrowableProxyConverter </b>处理</font>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="280" y="1100" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-5" value="log.info("info message: {}", "hello");<br style="font-size: 11px;"><font color="#007fff" style=""><b>带有参数的日志输出流程</b>,参数同样保存到 LoggingEvent, 最终在&nbsp;<b>DeferredProcessingAware</b>#<br><b>prepareForDeferredProcessing</b>() 处理</font>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="280" y="1180" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-10" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="xc-GYIRrwOv2HIxgL6Iq-7" target="xc-GYIRrwOv2HIxgL6Iq-9">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-16" value="1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="xc-GYIRrwOv2HIxgL6Iq-10">
<mxGeometry x="0.0706" relative="1" as="geometry">
<mxPoint x="9" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-7" value="<font color="#007fff">// 1</font><br>MDC.put("trace-id", "10001");<br>log.info("info message with mdc ...");<br><b style="color: rgb(0, 127, 255);">带有MDC参数的日志输出流程</b>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;fillColor=#dae8fc;strokeColor=#6c8ebf;align=left;" vertex="1" parent="1">
<mxGeometry x="280" y="1920" width="200" height="80" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-13" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="xc-GYIRrwOv2HIxgL6Iq-9" target="xc-GYIRrwOv2HIxgL6Iq-12">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-9" value="mdcAdapter.put(key, val);<br><font color="#007fff">从后面可以看到本质就是<b>通过 ThreadLocal 传参</b></font>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;" vertex="1" parent="1">
<mxGeometry x="520" y="1930" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-15" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;endArrow=open;endFill=0;" edge="1" parent="1" source="xc-GYIRrwOv2HIxgL6Iq-11" target="xc-GYIRrwOv2HIxgL6Iq-14">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-11" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>MDC</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"></p><font color="#007fff"><b>&nbsp;MDC (Mapped Diagnostic Context) 用来添加额外的上下文信息到日志</b></font><p style="margin:0px;margin-left:4px;"><br></p><p style="margin:0px;margin-left:4px;">static MDCAdapter <b>mdcAdapter</b>;<br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="-440" y="1480" width="400" height="120" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-12" value="<div>Map&lt;String, String&gt; current = <b>readWriteThreadLocalMap</b>.get();</div><div>if (current == null) {</div><div>&nbsp; &nbsp; current = new HashMap&lt;String, String&gt;();</div><div>&nbsp; &nbsp; readWriteThreadLocalMap.set(current);</div><div>}</div><div>current.<b>put</b>(key, val);</div><div>nullifyReadOnlyThreadLocalMap();</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;align=left;arcSize=6;" vertex="1" parent="1">
<mxGeometry x="760" y="1920" width="440" height="110" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-14" value="<p style="margin:0px;margin-top:4px;text-align:center;"><b>LogbackMDCAdapter</b><br></p><hr size="1"><p style="margin:0px;margin-left:4px;"><font color="#007fff"><b>MDCAdapter 的 Logback 实现,从下面可以看到,本质就是通过 ThreadLocal 传参</b></font></p><p style="margin:0px;margin-left:4px;"><span style="color: rgb(0, 127, 255); background-color: initial;">&nbsp;</span><br></p><p style="margin:0px;margin-left:4px;">final <b>ThreadLocal</b>&lt;Map&lt;String, String&gt;&gt; readWriteThreadLocalMap = new ThreadLocal&lt;Map&lt;String, String&gt;&gt;();</p><p style="margin:0px;margin-left:4px;">final <b>ThreadLocal</b>&lt;Map&lt;String, String&gt;&gt; readOnlyThreadLocalMap = new ThreadLocal&lt;Map&lt;String, String&gt;&gt;();</p><p style="margin:0px;margin-left:4px;">private final <b>ThreadLocalMapOfStacks</b> threadLocalMapOfDeques = new ThreadLocalMapOfStacks();</p><hr size="1"><p style="margin:0px;margin-left:4px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;whiteSpace=wrap;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="-880" y="1480" width="400" height="200" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-17" value="<font color="#007fff"><b>Logback 实现 MDC 的原理很简单:<br>就是通过 ThreadLocal 传递自定义信息,<br>后面进行序列化编码时由 MDCConverter 从&nbsp; ThreadLocal 将值取出来<br>追加到 StringBuilder 后面</b><br></font>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
<mxGeometry x="280" y="2005" width="400" height="70" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-20" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="xc-GYIRrwOv2HIxgL6Iq-18" target="xc-GYIRrwOv2HIxgL6Iq-19">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-18" value="<b>Skywalking TraceId Layout 实现</b><br><b>TraceIdPatternLogbackLayout</b>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;" vertex="1" parent="1">
<mxGeometry x="40" y="2160" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-22" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;" edge="1" parent="1" source="xc-GYIRrwOv2HIxgL6Iq-19" target="xc-GYIRrwOv2HIxgL6Iq-21">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-19" value="<div><div>public class TraceIdPatternLogbackLayout extends PatternLayout {</div><div>&nbsp; &nbsp; static {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; defaultConverterMap.put("tid", LogbackPatternConverter.class.getName());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; defaultConverterMap.put("sw_ctx", LogbackSkyWalkingContextPatternConverter.class.getName());</div><div>&nbsp; &nbsp; }</div><div>}</div></div><div><font color="#007fff">实现挺简单仅仅是在 Logback PatternLayout 基础上额外添加了两个Converter, 这里只关注 LogbackPatternConverter,用于转换 %tid 占位符</font></div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;arcSize=4;" vertex="1" parent="1">
<mxGeometry x="280" y="2120" width="440" height="140" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-28" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="xc-GYIRrwOv2HIxgL6Iq-21" target="xc-GYIRrwOv2HIxgL6Iq-27">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="980" y="2190" />
<mxPoint x="980" y="2360" />
<mxPoint x="740" y="2360" />
<mxPoint x="740" y="2400" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-21" value="<b>LogbackPatternConverter</b>#write(...)<br><font color="#007fff">LogbackPatternConverter继承 ClassicConverter, 仅仅重写了 convert() 方法</font>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1">
<mxGeometry x="760" y="2160" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-23" value="<font color="#007fff">通过这个类在日志中插入 Skywalking <br>TraceId类位于 skywalking-java&nbsp;<br></font>" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
<mxGeometry x="40" y="2220" width="220" height="40" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-26" value="<font color="#007fff"><b>但是 convert() 方法实现只是返回 "TID: N/A" ?</b><b>那么实际使用时替换占位符 %tid 的值哪里来的?</b><br><b>推测业务实际使用时可能 Skywalking JavaAgent 将这个 LogbackPatternConverter 类增强了,</b><b>修改了 convert() 方法的实现</b><br>从 Skywalking JavaAgent 原理可知是通过加载 plugins 中的 XxxInstrumentation 实现修改服务中的类的,<br>如果上面猜想不错,应该也有一个对应的 Instrumentation 类修改 LogbackPatternConverter, 搜索源码找到了 <b>LogbackPatternConverterActivation</b> (虽然不是 Imstrumentation 结尾的,但确实是这个)<br>包路径是 apm-sniffer/apm-toolkit-activation/apm-toolkit-logback-1.x-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/log/logback/v1/x/LogbackPatternConverterActivation.java<br><b>看了下实现和猜想一致<br></b><div>&nbsp; &nbsp; public static final String <b>INTERCEPT_CLASS</b> = "org.apache.skywalking.apm.toolkit.activation.log.logback.v1.x.<b>PrintTraceIdInterceptor</b>"; <b>//增强逻辑所在的类</b></div><div>&nbsp; &nbsp; public static final String <b>ENHANCE_CLASS</b> = "org.apache.skywalking.apm.toolkit.log.logback.v1.x.<b>LogbackPatternConverter</b>";</div><div>&nbsp; &nbsp; public static final String <b>ENHANCE_METHOD</b> = "<b>convert</b>";</div><div><br></div></font>" style="text;html=1;align=left;verticalAlign=top;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
<mxGeometry x="990" y="2160" width="1090" height="160" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-32" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="xc-GYIRrwOv2HIxgL6Iq-27" target="xc-GYIRrwOv2HIxgL6Iq-31">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-27" value="<b>PrintTraceIdInterceptor#afterMethod()</b><br><font color="#007fff">实际引入 JavaAgent 后 convert() 被重写,调用此拦截器</font>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=11;" vertex="1" parent="1">
<mxGeometry x="760" y="2370" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-31" value="<div>if (!ContextManager.isActive()) {</div><div>&nbsp; &nbsp; if (allArguments[0] instanceof EnhancedInstance) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; SkyWalkingContext skyWalkingContext = (SkyWalkingContext) ((EnhancedInstance) allArguments[0]).getSkyWalkingDynamicField();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if (skyWalkingContext != null) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return "TID:" + skyWalkingContext.getTraceId();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; }</div><div>}</div><div><b><font color="#007fff">// ContextManager 中存储的是链路追踪上下文,也包括TraceId</font></b></div><div>return "TID:" + <b>ContextManager</b>.<b>getGlobalTraceId</b>();</div>" style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;align=left;arcSize=5;" vertex="1" parent="1">
<mxGeometry x="1000" y="2320" width="440" height="160" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-34" value="<div style="font-size: 12px;"></div><div style="font-size: 12px;"><font color="#007fff" style="font-size: 12px;">// xml配置初始化默认是通过 DefaultJoranConfigurator 实现</font></div><div style="font-size: 12px;"><b style="font-size: 12px;">DefaultJoranConfigurator</b></div><div style="font-size: 12px;">#configure(...)<br style="font-size: 12px;"></div>" style="rounded=1;whiteSpace=wrap;html=1;align=left;arcSize=10;fontSize=12;fillColor=#ffe6cc;strokeColor=#d79b00;" vertex="1" parent="1">
<mxGeometry x="2920" y="570" width="200" height="60" as="geometry" />
</mxCell>
<mxCell id="xc-GYIRrwOv2HIxgL6Iq-39" value="<font color="#007fff"><b>XML 配置解析为LoggerContext中的组件在这里面完成<br>这里面的代码还是有点复杂的,也比较杂<br><div style=""><b style="background-color: initial;">但是不妨碍理解 Logback 工作原理,暂略</b></div></b></font>" style="text;html=1;align=left;verticalAlign=top;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
<mxGeometry x="2920" y="640" width="320" height="60" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>