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个问题,笔者都有解决方案,欢迎探讨!