1 各種元素對應的解析器
protected void addInstanceRules(RuleStore rs) { // is "configuration/variable" referenced in the docs? rs.addRule(new ElementSelector("configuration/variable"), new PropertyAction()); rs.addRule(new ElementSelector("configuration/property"), new PropertyAction()); rs.addRule(new ElementSelector("configuration/substitutionProperty"), new PropertyAction()); rs.addRule(new ElementSelector("configuration/timestamp"), new TimestampAction()); rs.addRule(new ElementSelector("configuration/shutdownHook"), new ShutdownHookAction()); rs.addRule(new ElementSelector("configuration/define"), new DefinePropertyAction()); // the contextProperty pattern is deprecated. It is undocumented // and will be dropped in future versions of logback rs.addRule(new ElementSelector("configuration/contextProperty"), new ContextPropertyAction()); rs.addRule(new ElementSelector("configuration/conversionRule"), new ConversionRuleAction()); rs.addRule(new ElementSelector("configuration/statusListener"), new StatusListenerAction()); rs.addRule(new ElementSelector("configuration/appender"), new AppenderAction<E>()); rs.addRule(new ElementSelector("configuration/appender/appender-ref"), new AppenderRefAction<E>()); rs.addRule(new ElementSelector("configuration/newRule"), new NewRuleAction()); rs.addRule(new ElementSelector("*/param"), new ParamAction(getBeanDescriptionCache())); } @Override public void addInstanceRules(RuleStore rs) { // parent rules already added super.addInstanceRules(rs); rs.addRule(new ElementSelector("configuration"), new ConfigurationAction()); rs.addRule(new ElementSelector("configuration/contextName"), new ContextNameAction()); rs.addRule(new ElementSelector("configuration/contextListener"), new LoggerContextListenerAction()); rs.addRule(new ElementSelector("configuration/insertFromJNDI"), new InsertFromJNDIAction()); rs.addRule(new ElementSelector("configuration/evaluator"), new EvaluatorAction()); rs.addRule(new ElementSelector("configuration/appender/sift"), new SiftAction()); rs.addRule(new ElementSelector("configuration/appender/sift/*"), new NOPAction()); rs.addRule(new ElementSelector("configuration/logger"), new LoggerAction()); rs.addRule(new ElementSelector("configuration/logger/level"), new LevelAction()); rs.addRule(new ElementSelector("configuration/root"), new RootLoggerAction()); rs.addRule(new ElementSelector("configuration/root/level"), new LevelAction()); rs.addRule(new ElementSelector("configuration/logger/appender-ref"), new AppenderRefAction<ILoggingEvent>()); rs.addRule(new ElementSelector("configuration/root/appender-ref"), new AppenderRefAction<ILoggingEvent>()); // add if-then-else support rs.addRule(new ElementSelector("*/if"), new IfAction()); rs.addRule(new ElementSelector("*/if/then"), new ThenAction()); rs.addRule(new ElementSelector("*/if/then/*"), new NOPAction()); rs.addRule(new ElementSelector("*/if/else"), new ElseAction()); rs.addRule(new ElementSelector("*/if/else/*"), new NOPAction()); // add jmxConfigurator only if we have JMX available. // If running under JDK 1.4 (retrotranslateed logback) then we // might not have JMX. if (PlatformInfo.hasJMXObjectName()) { rs.addRule(new ElementSelector("configuration/jmxConfigurator"), new JMXConfiguratorAction()); } rs.addRule(new ElementSelector("configuration/include"), new IncludeAction()); rs.addRule(new ElementSelector("configuration/consolePlugin"), new ConsolePluginAction()); rs.addRule(new ElementSelector("configuration/receiver"), new ReceiverAction()); }
2 一些默認的解析器
static public void addDefaultNestedComponentRegistryRules(DefaultNestedComponentRegistry registry) { registry.add(AppenderBase.class, "layout", PatternLayout.class); registry.add(UnsynchronizedAppenderBase.class, "layout", PatternLayout.class); registry.add(AppenderBase.class, "encoder", PatternLayoutEncoder.class); registry.add(UnsynchronizedAppenderBase.class, "encoder", PatternLayoutEncoder.class); registry.add(EvaluatorFilter.class, "evaluator", JaninoEventEvaluator.class); SSLNestedComponentRegistryRules.addDefaultNestedComponentRegistryRules(registry); }
3 variable元素
<variable name="aaa" value="aaa" />
設置了一個屬性變量,後面可以引用這個屬性變量!
4 property元素
<property name="bbb" value="bbb" />
設置了一個屬性變量,後面可以引用這個屬性變量!
5 timestamp元素
<timestamp key="logbackStartTime" datePattern="yyyy-MM-dd_HH:mm:ss" timeReference="contextBirth"/>
設置了一個屬性變量,後面可以引用這個屬性變量!
這裏引用的是系統啓動時間,可以格式化!
6 shutdownHook元素
<!--關閉鉤子--> <!--在沒有class屬性的情況下 假設 ch.qos.logback.core.hook.DelayingShutdownHook --> <!--Runtime.getRuntime().addShutdownHook(hookThread);--> <!--10 milliseconds--> <shutdownHook class="ch.qos.logback.core.hook.DelayingShutdownHook"> <delay>10</delay> </shutdownHook>
7 define元素
<!--define--> <!--classs 屬性用來引用實現了 PropertyDefiner 接口的類。PropertyDefiner 實例的 getPropertyValue() 的返回值就是變量的值--> <define name="rootFileExists" class="ch.qos.logback.core.property.FileExistsPropertyDefiner"> <path>/root</path> </define>
8 conversionRule
<!--自定義轉換符,只是把轉換規則註冊到context中而已,用的時候再拿出來使用--> <!--就是類似%thread %msg 由誰負責解析--> <conversionRule conversionWord="ip" converterClass="com.cj.log.IpConvert" />
9 一些關鍵字段對應的解析類
就是pattern裏的那些字段由誰負責解析!
static { defaultConverterMap.putAll(Parser.DEFAULT_COMPOSITE_CONVERTER_MAP); defaultConverterMap.put("d", DateConverter.class.getName()); defaultConverterMap.put("date", DateConverter.class.getName()); defaultConverterMap.put("r", RelativeTimeConverter.class.getName()); defaultConverterMap.put("relative", RelativeTimeConverter.class.getName()); defaultConverterMap.put("level", LevelConverter.class.getName()); defaultConverterMap.put("le", LevelConverter.class.getName()); defaultConverterMap.put("p", LevelConverter.class.getName()); defaultConverterMap.put("t", ThreadConverter.class.getName()); defaultConverterMap.put("thread", ThreadConverter.class.getName()); defaultConverterMap.put("lo", LoggerConverter.class.getName()); defaultConverterMap.put("logger", LoggerConverter.class.getName()); defaultConverterMap.put("c", LoggerConverter.class.getName()); defaultConverterMap.put("m", MessageConverter.class.getName()); defaultConverterMap.put("msg", MessageConverter.class.getName()); defaultConverterMap.put("message", MessageConverter.class.getName()); defaultConverterMap.put("C", ClassOfCallerConverter.class.getName()); defaultConverterMap.put("class", ClassOfCallerConverter.class.getName()); defaultConverterMap.put("M", MethodOfCallerConverter.class.getName()); defaultConverterMap.put("method", MethodOfCallerConverter.class.getName()); defaultConverterMap.put("L", LineOfCallerConverter.class.getName()); defaultConverterMap.put("line", LineOfCallerConverter.class.getName()); defaultConverterMap.put("F", FileOfCallerConverter.class.getName()); defaultConverterMap.put("file", FileOfCallerConverter.class.getName()); defaultConverterMap.put("X", MDCConverter.class.getName()); defaultConverterMap.put("mdc", MDCConverter.class.getName()); defaultConverterMap.put("ex", ThrowableProxyConverter.class.getName()); defaultConverterMap.put("exception", ThrowableProxyConverter.class.getName()); defaultConverterMap.put("rEx", RootCauseFirstThrowableProxyConverter.class.getName()); defaultConverterMap.put("rootException", RootCauseFirstThrowableProxyConverter.class.getName()); defaultConverterMap.put("throwable", ThrowableProxyConverter.class.getName()); defaultConverterMap.put("xEx", ExtendedThrowableProxyConverter.class.getName()); defaultConverterMap.put("xException", ExtendedThrowableProxyConverter.class.getName()); defaultConverterMap.put("xThrowable", ExtendedThrowableProxyConverter.class.getName()); defaultConverterMap.put("nopex", NopThrowableInformationConverter.class.getName()); defaultConverterMap.put("nopexception", NopThrowableInformationConverter.class.getName()); defaultConverterMap.put("cn", ContextNameConverter.class.getName()); defaultConverterMap.put("contextName", ContextNameConverter.class.getName()); defaultConverterMap.put("caller", CallerDataConverter.class.getName()); defaultConverterMap.put("marker", MarkerConverter.class.getName()); defaultConverterMap.put("property", PropertyConverter.class.getName()); defaultConverterMap.put("n", LineSeparatorConverter.class.getName()); defaultConverterMap.put("black", BlackCompositeConverter.class.getName()); defaultConverterMap.put("red", RedCompositeConverter.class.getName()); defaultConverterMap.put("green", GreenCompositeConverter.class.getName()); defaultConverterMap.put("yellow", YellowCompositeConverter.class.getName()); defaultConverterMap.put("blue", BlueCompositeConverter.class.getName()); defaultConverterMap.put("magenta", MagentaCompositeConverter.class.getName()); defaultConverterMap.put("cyan", CyanCompositeConverter.class.getName()); defaultConverterMap.put("white", WhiteCompositeConverter.class.getName()); defaultConverterMap.put("gray", GrayCompositeConverter.class.getName()); defaultConverterMap.put("boldRed", BoldRedCompositeConverter.class.getName()); defaultConverterMap.put("boldGreen", BoldGreenCompositeConverter.class.getName()); defaultConverterMap.put("boldYellow", BoldYellowCompositeConverter.class.getName()); defaultConverterMap.put("boldBlue", BoldBlueCompositeConverter.class.getName()); defaultConverterMap.put("boldMagenta", BoldMagentaCompositeConverter.class.getName()); defaultConverterMap.put("boldCyan", BoldCyanCompositeConverter.class.getName()); defaultConverterMap.put("boldWhite", BoldWhiteCompositeConverter.class.getName()); defaultConverterMap.put("highlight", HighlightingCompositeConverter.class.getName()); defaultConverterMap.put("lsn", LocalSequenceNumberConverter.class.getName()); }
10 ConsoleAppender
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <!-- encoder 默認使用 ch.qos.logback.classic.encoder.PatternLayoutEncoder --> <!--系統有個默認的表,不寫class則取默認的類--> <encoder> <pattern>%-4relative %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> <!--默認就是true--> <!-- <immediateFlush>true</immediateFlush> --> <charset>UTF-8</charset> </encoder> </appender>
11 RollingFileAppender
11.1 Appender
<appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> ... </appender>
11.2 消息過濾
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter>
11.3 消息格式化
<!-- 構造消息內容 --> <!-- encoder 默認使用 ch.qos.logback.classic.encoder.PatternLayoutEncoder --> <encoder> <pattern>%X{first} %X{last} %-4relative %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n </pattern> <charset>UTF-8</charset> </encoder>
11.4 寫入的方式:append vs truncate
<!-- 默認爲true,以追加的方式啓動而不是truncate 實際上代碼強制爲true --> <append>true</append>
11.5 目標文件
<!-- 寫到的文件裏 --> <file>mylog.txt</file>
11.6 滾動策略
11.6.1 policy
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> ... </rollingPolicy>
11.6.2 時間策略
<fileNamePattern>logback-${logbackStartTime}/mylog-%d{yyyy-MM-dd_HH}.%i.txt</fileNamePattern>
11.6.3 文件大小策略
<maxFileSize>64KB</maxFileSize>
11.6.4 清除策略
<!-- 先按照maxHistory刪除一部分文件,然後再按照totalSizeCap刪除一部分文件 全部設置爲0則不刪除文件,建議讓flume採集器來採集!!! --> <maxHistory>0</maxHistory> <totalSizeCap>0</totalSizeCap>
其實還有一個清除配置就是是否在系統啓動時先預先執行一遍清除任務(根據當前時間點來執行相應的操作)
/** * Should archive removal be attempted on application start up? Default is false. * @since 1.0.1 * @param cleanHistoryOnStart */ public void setCleanHistoryOnStart(boolean cleanHistoryOnStart) { this.cleanHistoryOnStart = cleanHistoryOnStart; }
12 Logger與appender的綁定
12.1 手動綁定
<!-- 指定具體的某個類日誌文件打印 --> <!--這裏會提前通過getLogger(...)創建一個logger--> <!--additive=false表示執行到自己就不會往parent執行,執行中止--> <logger name="restful.logTest" level="INFO" additivity="false"> <appender-ref ref="ROLLING"/> </logger>
12.2 全局默認綁定
<!--全局配置,rootLogger一開始就存在--> <root level="debug"> <!-- <appender-ref ref="STDOUT" /> --> <appender-ref ref="ROLLING" /> </root>
13 留給讀者的問題
13.1 啓動後滾動新生成的文件如何不覆蓋老文件?
13.2 文件大小滾動策略中,如果文件大小設置爲10字節真的一定會生效嗎?如果不生效如何讓它生效?
上面2個問題,筆者都有解決方案,歡迎探討!