<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>星游第二领地</title>
	<atom:link href="https://watchzerg.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://watchzerg.wordpress.com</link>
	<description>如果说不经历专制就无法体会自由的珍贵，如果说不经历孤独就无法体会爱情的滋味，那么：我都TMD经历和24年的专制和孤独了，老天啥时候开眼？</description>
	<lastBuildDate>Sat, 19 Jul 2014 03:07:15 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='watchzerg.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>https://s0.wp.com/i/buttonw-com.png</url>
		<title>星游第二领地</title>
		<link>https://watchzerg.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="https://watchzerg.wordpress.com/osd.xml" title="星游第二领地" />
	<atom:link rel='hub' href='https://watchzerg.wordpress.com/?pushpress=hub'/>
	<item>
		<title>logback_config_demo</title>
		<link>https://watchzerg.wordpress.com/2014/07/13/logback_config_demo/</link>
					<comments>https://watchzerg.wordpress.com/2014/07/13/logback_config_demo/#comments</comments>
		
		<dc:creator><![CDATA[watchzerg]]></dc:creator>
		<pubDate>Sun, 13 Jul 2014 11:38:12 +0000</pubDate>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://watchzerg.wordpress.com/2014/07/13/logback_config_demo/</guid>

					<description><![CDATA[我自己的logback一般先用这个总结好的架子，需要的再往上添（搞毛线？wordpress.com官方说用“[ [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>我自己的logback一般先用这个总结好的架子，需要的再往上添（搞毛线？wordpress.com官方说用“[ code ]”来标记，编辑器里又自动用&lt;code&gt;标记，但即使指定lang=&#8221;xml&#8221;，也没法正确的现实xml内容啊）：</p>
<p>&nbsp;</p>
<blockquote><p>&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;UTF-8&#8243;?&gt;<br />
&lt;!&#8211; &lt;configuration scan=&#8221;true&#8221; scanPeriod=&#8221;60 seconds&#8221;&gt; &#8211;&gt;<br />
&lt;configuration&gt;<br />
&lt;!&#8211; print configuration status on console &#8211;&gt;<br />
&lt;statusListener class=&#8221;ch.qos.logback.core.status.OnConsoleStatusListener&#8221;/&gt;</p>
<p>&lt;!&#8211; Beagle: eclipse plugin &#8211;&gt;<br />
&lt;!&#8211; &lt;consolePlugin /&gt; &#8211;&gt;</p>
<p>&lt;!&#8211; log path &#8211;&gt;<br />
&lt;property name=&#8221;LOG_PATH&#8221; value=&#8221;d:/log&#8221; /&gt;<br />
&lt;!&#8211; &lt;property resource=&#8221;resource1.properties&#8221; /&gt; &#8211;&gt;</p>
<p>&lt;!&#8211; ================================= appenders =================================== &#8211;&gt;</p>
<p>&lt;!&#8211; console appender (must be omitted in product environment) &#8211;&gt;<br />
&lt;appender name=&#8221;STDOUT&#8221; class=&#8221;ch.qos.logback.core.ConsoleAppender&#8221;&gt;<br />
&lt;encoder charset=&#8221;UTF-8&#8243;&gt;<br />
&lt;!&#8211; [%p] works fine with &#8220;grep console&#8221; &#8211;&gt;<br />
&lt;!&#8211; \(%F:%L\) for caller reference &#8211;&gt;<br />
&lt;pattern&gt;%d{HH:mm:ss.SSS} [%t] [%p] %c{1} &#8211; %m \(%F:%L\) %n&lt;/pattern&gt;<br />
&lt;/encoder&gt;<br />
&lt;/appender&gt;</p>
<p>&lt;!&#8211; default appender &#8211;&gt;<br />
&lt;appender name=&#8221;COMMON-DEFAULT-APPENDER&#8221; class=&#8221;ch.qos.logback.core.rolling.RollingFileAppender&#8221;&gt;<br />
&lt;File&gt;${LOG_PATH}/common-default.log&lt;/File&gt;<br />
&lt;rollingPolicy class=&#8221;ch.qos.logback.core.rolling.TimeBasedRollingPolicy&#8221;&gt;<br />
&lt;FileNamePattern&gt;${LOG_PATH}/common-default.%d.log.gz&lt;/FileNamePattern&gt;<br />
&lt;maxHistory&gt;30&lt;/maxHistory&gt;<br />
&lt;/rollingPolicy&gt;<br />
&lt;encoder charset=&#8221;UTF-8&#8243;&gt;<br />
&lt;Pattern&gt;%d [%t] %-5p %c{1} &#8211; %m%n&lt;/Pattern&gt;<br />
&lt;!&#8211; since default appender deal with massive messages, so somewhat losses can be tolerated &#8211;&gt;<br />
&lt;immediateFlush&gt;false&lt;/immediateFlush&gt;<br />
&lt;/encoder&gt;<br />
&lt;/appender&gt;</p>
<p>&lt;!&#8211; error appender &#8211;&gt;<br />
&lt;appender name=&#8221;COMMON-ERROR-APPENDER&#8221; class=&#8221;ch.qos.logback.core.rolling.RollingFileAppender&#8221;&gt;<br />
&lt;filter class=&#8221;ch.qos.logback.classic.filter.ThresholdFilter&#8221;&gt;<br />
&lt;level&gt;ERROR&lt;/level&gt;<br />
&lt;/filter&gt;<br />
&lt;File&gt;${LOG_PATH}/common-error.log&lt;/File&gt;<br />
&lt;rollingPolicy class=&#8221;ch.qos.logback.core.rolling.TimeBasedRollingPolicy&#8221;&gt;<br />
&lt;FileNamePattern&gt;${LOG_PATH}/common-error.%d.log.gz&lt;/FileNamePattern&gt;<br />
&lt;maxHistory&gt;365&lt;/maxHistory&gt;<br />
&lt;/rollingPolicy&gt;<br />
&lt;encoder charset=&#8221;UTF-8&#8243;&gt;<br />
&lt;Pattern&gt;%d [%t] %-5p %c{1} &#8211; %m%n&lt;/Pattern&gt;<br />
&lt;/encoder&gt;<br />
&lt;/appender&gt;</p>
<p>&lt;!&#8211; business appender &#8211;&gt;<br />
&lt;appender name=&#8221;BUSINESS-APPENDER&#8221; class=&#8221;ch.qos.logback.core.rolling.RollingFileAppender&#8221;&gt;<br />
&lt;File&gt;${LOG_PATH}/business.log&lt;/File&gt;<br />
&lt;rollingPolicy class=&#8221;ch.qos.logback.core.rolling.TimeBasedRollingPolicy&#8221;&gt;<br />
&lt;!&#8211; folders archive for month, files archive for day &#8211;&gt;<br />
&lt;FileNamePattern&gt;${LOG_PATH}/%d{yyyy-MM,aux}/business.%d.log.gz&lt;/FileNamePattern&gt;<br />
&lt;/rollingPolicy&gt;<br />
&lt;encoder charset=&#8221;UTF-8&#8243;&gt;<br />
&lt;Pattern&gt;%d [%t] %-5p %c{1} &#8211; %m%n&lt;/Pattern&gt;<br />
&lt;/encoder&gt;<br />
&lt;/appender&gt;</p>
<p>&lt;!&#8211; alarm email appender &#8211;&gt;<br />
&lt;appender name=&#8221;ALARM-APPENDER&#8221; class=&#8221;ch.qos.logback.classic.net.SMTPAppender&#8221;&gt;<br />
&lt;smtpHost&gt;localhost&lt;/smtpHost&gt;<br />
&lt;smtpPort&gt;587&lt;/smtpPort&gt;<br />
&lt;SSL&gt;true&lt;/SSL&gt;<br />
&lt;username&gt;master1@watchzerg.me&lt;/username&gt;<br />
&lt;password&gt;test_pass&lt;/password&gt;<br />
&lt;to&gt;master2@watchzerg.me&lt;/to&gt;<br />
&lt;from&gt;master3@watchzerg.me&lt;/from&gt;<br />
&lt;subject&gt;[ALARM] Fail to change price for goods %X{change_price_id}! &lt;/subject&gt;<br />
&lt;layout class=&#8221;ch.qos.logback.classic.html.HTMLLayout&#8221;&gt;<br />
&lt;pattern&gt;%d%t%p%c%m&lt;/pattern&gt;<br />
&lt;/layout&gt;<br />
&lt;charsetEncoding&gt;UTF-8&lt;/charsetEncoding&gt;<br />
&lt;asynchronousSending&gt;false&lt;/asynchronousSending&gt;<br />
&lt;!&#8211;<br />
&lt;cyclicBufferTracker class=&#8221;ch.qos.logback.core.spi.CyclicBufferTracker&#8221;&gt;<br />
&lt;maxNumberOfBuffers&gt;256&lt;/maxNumberOfBuffers&gt;<br />
&lt;/cyclicBufferTracker&gt;<br />
&#8211;&gt;<br />
&lt;evaluator class=&#8221;ch.qos.logback.classic.boolex.OnMarkerEvaluator&#8221;&gt;<br />
&lt;marker&gt;ALARM_EMAIL&lt;/marker&gt;<br />
&lt;/evaluator&gt;<br />
&lt;discriminator class=&#8221;ch.qos.logback.classic.sift.MDCBasedDiscriminator&#8221;&gt;<br />
&lt;key&gt;change_price_id&lt;/key&gt;<br />
&lt;defaultValue&gt;default&lt;/defaultValue&gt;<br />
&lt;/discriminator&gt;<br />
&lt;/appender&gt;</p>
<p>&lt;!&#8211; ================================= loggers =================================== &#8211;&gt;</p>
<p>&lt;!&#8211; business logger &#8211;&gt;<br />
&lt;logger name=&#8221;BUSINESS&#8221; level=&#8221;INFO&#8221; additivity=&#8221;false&#8221;&gt;<br />
&lt;appender-ref ref=&#8221;STDOUT&#8221;/&gt;<br />
&lt;appender-ref ref=&#8221;BUSINESS-APPENDER&#8221; /&gt;<br />
&lt;appender-ref ref=&#8221;ALARM-APPENDER&#8221;/&gt;<br />
&lt;/logger&gt;</p>
<p>&lt;!&#8211; root logger &#8211;&gt;<br />
&lt;root level=&#8221;DEBUG&#8221;&gt;<br />
&lt;appender-ref ref=&#8221;STDOUT&#8221;/&gt;<br />
&lt;appender-ref ref=&#8221;COMMON-DEFAULT-APPENDER&#8221;/&gt;<br />
&lt;appender-ref ref=&#8221;COMMON-ERROR-APPENDER&#8221;/&gt;<br />
&lt;appender-ref ref=&#8221;ALARM-APPENDER&#8221;/&gt;<br />
&lt;/root&gt;</p>
<p>&lt;/configuration&gt;</p></blockquote>
]]></content:encoded>
					
					<wfw:commentRss>https://watchzerg.wordpress.com/2014/07/13/logback_config_demo/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/5a39b92a93cdb32c75904702aef6c743964f034250355c6cf3c07790f896217b?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">watchzerg</media:title>
		</media:content>
	</item>
		<item>
		<title>logback_eclipse_plugin_beagle</title>
		<link>https://watchzerg.wordpress.com/2014/07/13/logback_eclipse_plugin_beagle/</link>
					<comments>https://watchzerg.wordpress.com/2014/07/13/logback_eclipse_plugin_beagle/#comments</comments>
		
		<dc:creator><![CDATA[watchzerg]]></dc:creator>
		<pubDate>Sun, 13 Jul 2014 11:34:06 +0000</pubDate>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://watchzerg.wordpress.com/2014/07/13/logback_eclipse_plugin_beagle/</guid>

					<description><![CDATA[http://logback.qos.ch/beagle/index.html   先安装依赖插件： http [&#8230;]]]></description>
										<content:encoded><![CDATA[<div>
<div><a href="http://logback.qos.ch/beagle/index.html">http://logback.qos.ch/beagle/index.html</a></div>
<div> </div>
<div>先安装依赖插件：</div>
<div><a href="http://download.eclipse.org/technology/nebula/snapshot" rel="nofollow">http://download.eclipse.org/technology/nebula/snapshot</a>    (注意这个是稳定的release版的地址，只需要安装“Nubula Release Individual Widgets”中的“Nebula Grid Feature”即可)</div>
<div>再安装logback-beagle插件：</div>
<div><a href="http://logback.qos.ch/p2/" rel="nofollow">http://logback.qos.ch/p2/</a> ( &#8220;Logback&#8221; &#8220;Logback Beagle&#8221; &#8220;SLF4J&#8221;这三个都得选)</div>
<div>完成后按“alt-shift-Q,Q”弹出view选择框，找到beagle打开即可（之后需要在logback-test.xml里配置&lt;consolePlugin /&gt;，参见logback文档）。</div>
<div> </div>
<div>在logback-test.xml里加上配置&lt;consolePlugin /&gt;即可</div>
<div>     &lt;configuration debug=&#8221;true&#8221;&gt;</div>
<div>       &lt;!&#8211; sends logs to logback-beagle &#8211;&gt;</div>
<div>       &lt;consolePlugin /&gt;</div>
<div>     &lt;/configuration&gt;</div>
<div>     ——实际上这个配置会自动创建一个SocketAppender，并把日志发到本机的4321端口。</div>
<div> </div>
<div>单击停止滚动，双击开始滚动</div>
<div>右键菜单可以跳转到调用行，也可以查看最多8行调用栈</div>
<div> </div>
<div>配置：</div>
<div>eclipse的preference里:</div>
<div>     Run/Debug &#8211; Beagle</div>
<div>          在这里可以自定义控制台输出的pattern</div>
<div>     General &#8211; Appearance &#8211; Colors and Fonts</div>
<div>          可以单独对Beagle设置字体</div>
<div> </div>
<div> </div>
<div> </div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://watchzerg.wordpress.com/2014/07/13/logback_eclipse_plugin_beagle/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/5a39b92a93cdb32c75904702aef6c743964f034250355c6cf3c07790f896217b?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">watchzerg</media:title>
		</media:content>
	</item>
		<item>
		<title>logback_doc_manual_09_logging_separation</title>
		<link>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_09_logging_separation/</link>
					<comments>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_09_logging_separation/#comments</comments>
		
		<dc:creator><![CDATA[watchzerg]]></dc:creator>
		<pubDate>Sun, 13 Jul 2014 11:33:30 +0000</pubDate>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_09_logging_separation/</guid>

					<description><![CDATA[http://logback.qos.ch/manual/loggingSeparation.html   主 [&#8230;]]]></description>
										<content:encoded><![CDATA[<div>
<div><a href="http://logback.qos.ch/manual/loggingSeparation.html">http://logback.qos.ch/manual/loggingSeparation.html</a></div>
<div> </div>
<div>主要处理多个应用程序运行在同一个web容器，并且每个应用使用各自独立的日志环境。</div>
<div>——想想一个tomcat运行了多个项目——也就是“一个JVM，多个ClassLoader，每个ClassLoader拥有自己独立的Logger Context”的问题。</div>
<div> </div>
<div>Context Selectors</div>
<div>     调用LoggerFactory.getLogger(&#8220;foo&#8221;)的时候，会要求SLF4J绑定一个ILoggerFactory，如果SLF4J使用的是logback，那么“绑定ILoggerFactory”的方法，会代理给一个ContextSelector实例，该实例会根据情况返回最合适的LoggerContext对象——这个对象实现了ILoggerFactory接口。</div>
<div>     默认总是返回DefaultContextSelector，可以在系统属性里通过logback.ContextSelector属性指定自己的类。</div>
<div> </div>
<div>ContextJNDISelector</div>
<div>     根据JNDI查找Selector——这样可以在各个项目的web.xml里配置自己的JNDI环境变量。</div>
<div>     为了在单个web项目重启和关闭的时候，对应的logger Context可以被回收，最好配置ContextDetachingSCL监听器</div>
<div>     不过每次获取logger都查找JNDI太慢，可以配置LoggerContextFilter过滤器来避免——会在每个http请求到来的时候把logger context放在线程内部，从而允许之后跳过JNDI搜索。</div>
<div>     此时最好把logger全声明成static的，减少logger的获取总次数。</div>
<div> </div>
<div>Taming static references in shared libraries</div>
<div>     如果有一个类属于共享包，被两个web项目同时引用</div>
<div>          1，当这个类使用非静态logger时，一切良好，来自两个web项目的调用，会返回各自的logger context。</div>
<div>          2，当这个类使用静态logger时，会错误的返回首次调用它的web项目的logger context——对这个问题ContextJNDISelector无能为力（eluded a solution for eons&#8230; 哈哈哈哈）</div>
<div> </div>
<div>     对于上述的“来自共类的静态logger，获取不同的logger context”的问题，有几个的办法：</div>
<div>          1，共享类改成非静态logger——一般不现实，因为共享类的源码往往不受项目控制。</div>
<div>          2，把共享类挪到web项目里——也够呛，一个两个类还好，那么多第三方依赖咋弄？</div>
<div>          3，所以还有一种取巧的办法：用SiftingAppender，根据JNDI信息把不同的日志分别输出到不同的文件里去（logback提供了JNDIBasedContextDiscriminator帮助做这事儿）——也就是说，两个项目分享同一个logger，等到其关联的appender需要把event输出到文件时，再临时决定输出到哪个文件。</div>
<div>     上述第3种方法有一个问题：</div>
<div>               假如项目A和项目B都使用共享包S。</div>
<div>                    项目A启动并调用S的时候，就已经把S的logger context设置为A了，日志会写入A.log中。</div>
<div>                    B启动并调用S的时候logger contex依然是A（不过因为配置了SiftingAppender的存在，B的日志依然可以写到正确的B.log中）</div>
<div>               ——也就是说，共享logger的问题并没有实质解决，这个logger还是只能属于A或者B其中之一，只不过logger在写日志前根据MDC里的JNDI可以将日志写到正确的文件中去。</div>
<div>               而初始化了两个不同的logger context都指向B.log，存在多个线程写同一个文件的不安全问题——需要对appender配置prudent参数来解决（会影响性能）。</div>
<div> </div>
<div>     （正常使用都是一个web container部署一个web项目，很少遇到上述情况。这部分文档看的很蛋疼……）</div>
<div> </div>
<div> </div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_09_logging_separation/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/5a39b92a93cdb32c75904702aef6c743964f034250355c6cf3c07790f896217b?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">watchzerg</media:title>
		</media:content>
	</item>
		<item>
		<title>logback_doc_manual_08_mapped_diagnostic_contexts</title>
		<link>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_08_mapped_diagnostic_contexts/</link>
					<comments>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_08_mapped_diagnostic_contexts/#comments</comments>
		
		<dc:creator><![CDATA[watchzerg]]></dc:creator>
		<pubDate>Sun, 13 Jul 2014 11:33:01 +0000</pubDate>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_08_mapped_diagnostic_contexts/</guid>

					<description><![CDATA[http://logback.qos.ch/manual/mdc.html   MDC（注意这个类在org.s [&#8230;]]]></description>
										<content:encoded><![CDATA[<div><a href="http://logback.qos.ch/manual/mdc.html">http://logback.qos.ch/manual/mdc.html</a></p>
<div> </div>
<div>MDC（注意这个类在org.slf4j包里）</div>
<div>     基于“多个线程同步处理多个请求”的假设来设计的，上下文信息记录。</div>
<div>          ——子线程会自动拷贝双亲线程的这类信息。</div>
<div>          ——如果没有附加处理的话，放入线程池处理的任务会丢失MDC上下文。</div>
<div>          该设计假定向MDC放数据的速度不会太快。</div>
<div> </div>
<div>最常用的web场景，是集成在一个servlet的Filter中，在请求时载入MDC信息，doFilter处理完成后卸载MDC信息。</div>
<div>——最好在“验证用户”这个Filter之后（或者之中）进行，这样可以把用户验证信息（包括但不限于用户名）写入MDC。</div>
<div> </div>
<div>交给线程池处理(submit)之前：MDC.getCopyOfContextMap()，把返回的map当作参数传给任务线程</div>
<div>线程池处理代码的第一行：MDC.setContextMapValues()，把接到的map参数设置到本线程的MDC中（别忘了最后清除掉）</div>
<div> </div>
<div>MDCInsertingServletFilter</div>
<div>     将web请求常用信息设置到MDC中：</div>
<div>          req.remoteHost as returned by the getRemoteHost() method</div>
<div>          req.xForwardedFor value of the &#8220;X-Forwarded-For&#8221; header</div>
<div>          req.requestURI       as returned by getRequestURI() method</div>
<div>          req.requestURL as returned by getRequestURL() method</div>
<div>          req.queryString as returned by getQueryString() method</div>
<div>          req.userAgent      value of the &#8220;User-Agent&#8221; header</div>
<div> </div>
<div>     web.xml中的配置</div>
<blockquote>
<div>&lt;filter&gt;</div>
<div>  &lt;filter-name&gt;MDCInsertingServletFilter&lt;/filter-name&gt;</div>
<div>  &lt;filter-class&gt;</div>
<div>    ch.qos.logback.classic.helpers.MDCInsertingServletFilter</div>
<div>  &lt;/filter-class&gt;</div>
<div>&lt;/filter&gt;</div>
<div>&lt;filter-mapping&gt;</div>
<div>  &lt;filter-name&gt;MDCInsertingServletFilter&lt;/filter-name&gt;</div>
<div>  &lt;url-pattern&gt;/*&lt;/url-pattern&gt;</div>
<div>&lt;/filter-mapping&gt; </div>
</blockquote>
<div>     注意filter顺序，经过该filter过滤之后，其它filter才能打印出MDC信息（特别是struts之类依赖filter处理主逻辑的）</div>
<div> </div>
<div>     使用例子：</div>
<div>     %X{req.remoteHost} %X{req.requestURI}%n%d &#8211; %m%n</div>
<div> </div>
<div>     ——其实没多大意义，还是自己写这个filter，挑选自己的有效信息比较好。</div>
<div> </div>
<div> </div>
<div> </div>
<div> </div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_08_mapped_diagnostic_contexts/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/5a39b92a93cdb32c75904702aef6c743964f034250355c6cf3c07790f896217b?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">watchzerg</media:title>
		</media:content>
	</item>
		<item>
		<title>logback_doc_manual_07_filters</title>
		<link>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_07_filters/</link>
					<comments>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_07_filters/#comments</comments>
		
		<dc:creator><![CDATA[watchzerg]]></dc:creator>
		<pubDate>Sun, 13 Jul 2014 11:32:25 +0000</pubDate>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_07_filters/</guid>

					<description><![CDATA[http://logback.qos.ch/manual/filters.html   logback-cla [&#8230;]]]></description>
										<content:encoded><![CDATA[<div><a href="http://logback.qos.ch/manual/filters.html">http://logback.qos.ch/manual/filters.html</a></p>
<div> </div>
<div>logback-classic有两种filter：Regular filters和turbo filters，挂在appender上</div>
<div> </div>
<div>Regular filters</div>
<div>     只有一个decide()方法，返回DENY, NEUTRAL or ACCEPT</div>
<div> </div>
<div>LevelFilter</div>
<div>     &lt;filter class=&#8221;ch.qos.logback.classic.filter.LevelFilter&#8221;&gt;</div>
<div>      &lt;level&gt;INFO&lt;/level&gt;</div>
<div>      &lt;onMatch&gt;ACCEPT&lt;/onMatch&gt;</div>
<div>      &lt;onMismatch&gt;DENY&lt;/onMismatch&gt;</div>
<div>     &lt;/filter&gt;</div>
<div> </div>
<div>ThresholdFilter</div>
<div>     高于或等于指定日志级别的记录，会返回NEUTRAL</div>
<div>     &lt;filter class=&#8221;ch.qos.logback.classic.filter.ThresholdFilter&#8221;&gt;</div>
<div>      &lt;level&gt;INFO&lt;/level&gt;</div>
<div>     &lt;/filter&gt;     </div>
<div> </div>
<div>EvaluatorFilter</div>
<div>     EventEvaluator的实现判断某个条件是否满足。</div>
<div>     </div>
<div>     GEventEvaluator</div>
<div>          接受groovy语法的布尔表达式作为判断条件，需要依赖Groovy运行时，表达式语句在配置的时候完成编译。</div>
<div>          logback会自动将目标事件作为一个变量传进来，可以用“event”或者“e”来引用。</div>
<div>          TRACE, DEBUG, INFO, WARN and ERROR这些级别也引入了，所以可以这样判断相等： &#8220;event.level == DEBUG&#8221; 。</div>
<div>          其他比较符，大于小于，需要转换成int再比较。</div>
<blockquote>
<div>    &lt;filter class=&#8221;ch.qos.logback.core.filter.EvaluatorFilter&#8221;&gt;      </div>
<div>      &lt;evaluator class=&#8221;ch.qos.logback.classic.boolex.GEventEvaluator&#8221;&gt; </div>
<div>        &lt;expression&gt;</div>
<div>           e.level.toInt() &gt;= WARN.toInt() &amp;amp;&amp;amp;  &lt;!&#8211; Stands for &amp;&amp; in XML &#8211;&gt;</div>
<div>           !(e.mdc?.get(&#8220;req.userAgent&#8221;) =~ /Googlebot|msnbot|Yahoo/ )</div>
<div>        &lt;/expression&gt;</div>
<div>      &lt;/evaluator&gt;</div>
<div>      &lt;OnMismatch&gt;DENY&lt;/OnMismatch&gt;</div>
<div>      &lt;OnMatch&gt;NEUTRAL&lt;/OnMatch&gt;</div>
<div>    &lt;/filter&gt;</div>
</blockquote>
<div> </div>
<div>     JaninoEventEvaluator</div>
<div>          使用java表达式，使用上比基于groovy的GEventEvaluator繁琐，但执行速度更快。</div>
<div>          详情略。</div>
<div>          </div>
<div>Matchers</div>
<div>     执行上面的过滤器时，可以调用String.matches()方法，但代价是每次需要重编译一个正则Pattern对象。</div>
<div>     所以可以预先定义和编译一个，以便复用。</div>
<div>     详情略。</div>
<div> </div>
<div>TurboFilters</div>
<div>     跟普通过滤器功能一样，但是：</div>
<div>          1，TurboFilter是跟logging context关联的，而不是跟appender关联。作用域更大。不仅在指定appender使用时，而且在每次logging请求时都会被调用。</div>
<div>          2，他们是在LoggingEvent对象创建之前被调用，过滤时不需要event实例做参数，所以性能更高（因为在event创建之前就已经执行过滤了）。</div>
<div>     内置了一些TurboFilter：</div>
<div> </div>
<div>          MDCFilter     测试指定的值是否存在于MDC中</div>
<div>          DynamicThresholdFilter     基于MDC的key和level来限流</div>
<div>          MarkerFilter     测试指定的marker是否出现在请求中</div>
<div>          DuplicateMessageFilter</div>
<div>               自动过滤相同的消息。</div>
<div>                    使用简单的字符串比对——即使两个字符串基本相同，相差一两个字母：也会被认为不同。</div>
<div>                    仅比较raw字符串，用{}转义过的字符串不去比较。</div>
<div>                    可以通过AllowedRepetitions设置允许的重复上限，超过上限的会被抛弃。默认大小为5</div>
<div>                    需要通过一个内部cache来保存老的消息以便判断，可以通过CacheSize设置缓存大小，默认100.</div>
<div>          </div>
<div>在evaluator的expression里，将logging时间与项目启动时间对比，可以控制仅输出“项目启动后20秒内的某类型日志”——这个对于“确认某个定时任务在启动时是运行状态”很有用，例如：</div>
<blockquote>
<div>&lt;filter class=&#8221;ch.qos.logback.core.filter.EvaluatorFilter&#8221;&gt;</div>
<div>  &lt;evaluator name=&#8221;loggingTaskEval&#8221;&gt;</div>
<div>    &lt;expression&gt;</div>
<div>      logger.getName().contains(&#8220;LoggingTask&#8221;) &amp;amp;&amp;amp;</div>
<div>      message.contains(&#8220;Howdydy-diddly-ho&#8221;) &amp;amp;&amp;amp;</div>
<div>      (timeStamp &#8211; event.getStartTime()) &gt;= 20000</div>
<div>    &lt;/expression&gt;</div>
<div>  &lt;/evaluator&gt;</div>
<div>  &lt;OnMatch&gt;DENY&lt;/OnMatch&gt;</div>
<div>&lt;/filter&gt;</div>
</blockquote>
<div> </div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_07_filters/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/5a39b92a93cdb32c75904702aef6c743964f034250355c6cf3c07790f896217b?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">watchzerg</media:title>
		</media:content>
	</item>
		<item>
		<title>logback_doc_manual_06_layouts</title>
		<link>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_06_layouts/</link>
					<comments>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_06_layouts/#comments</comments>
		
		<dc:creator><![CDATA[watchzerg]]></dc:creator>
		<pubDate>Sun, 13 Jul 2014 11:31:54 +0000</pubDate>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_06_layouts/</guid>

					<description><![CDATA[http://logback.qos.ch/manual/layouts.html   PatternLayo [&#8230;]]]></description>
										<content:encoded><![CDATA[<div><a href="http://logback.qos.ch/manual/layouts.html">http://logback.qos.ch/manual/layouts.html</a></p>
<div> </div>
<div>PatternLayout</div>
<div>     转换模式类似于C语言里的printf()。</div>
<div> </div>
<div>转移字符：</div>
<div>     c{length}</div>
<div>     lo{length}</div>
<div>     logger{length}</div>
<div>          其中的length代表输出的logger长度。</div>
<div>          设为0的话例外，仅输出最右边的logger名。</div>
<div>          其余情况会自动计算，尽量使得输出的总字符串长度小于指定长度——但是，最右边的logger名称无论如何会完整保留，同时前面的每一级logger，最少会被精简到1个字符。</div>
<div>          ——%c{1}</div>
<div><span style="color:#eb0073;">     C{length}</span></div>
<div><span style="color:#eb0073;">     class{length}</span></div>
<div><span style="color:#eb0073;">          打印调用者的类名称，设置方法与上面一样。</span></div>
<div><span style="color:#eb0073;">          性能不高。</span></div>
<div>     contextName</div>
<div>     cn</div>
<div>          打印logger在event最初绑定的logger context的名称。</div>
<div>     d{pattern}</div>
<div>     date{pattern}</div>
<div>     d{pattern, timezone}</div>
<div>     date{pattern, timezone}</div>
<div>          输入日志时间，使用java.text.SimpleDateFormat的日期格式化方法。</div>
<div>          如果不指定日期格式，默认使用ISO8601，也就是2006-10-20 14:06:49,812这种形式。</div>
<div>          ——%d</div>
<div><span style="color:#eb0073;">     F / file</span></div>
<div><span style="color:#eb0073;">          输出java源文件的名称。</span></div>
<div><span style="color:#eb0073;">          性能不高。</span></div>
<div>     caller{depth}</div>
<div>     caller{depth, evaluator-1, &#8230; evaluator-n}</div>
<div>          打印日志事件的调用堆栈。</div>
<div>          使用评估器evaluator决定是否打印。</div>
<div><span style="color:#eb0073;">     L</span></div>
<div><span style="color:#eb0073;">     line</span></div>
<div><span style="color:#eb0073;">          输出日志记录请求发起的行数。</span></div>
<div><span style="color:#eb0073;">          性能不高。</span></div>
<div>     m</div>
<div>     msg</div>
<div>     message</div>
<div>          日志正文</div>
<div>          ——%m</div>
<div><span style="color:#eb0073;">     M</span></div>
<div><span style="color:#eb0073;">     method</span></div>
<div><span style="color:#eb0073;">          日志调用方法名。</span></div>
<div><span style="color:#eb0073;">          性能不高</span></div>
<div>     n</div>
<div>          操作系统对应的换行符</div>
<div>          ——%n</div>
<div>     p</div>
<div>     le</div>
<div>     level</div>
<div>          日志等级</div>
<div>     r</div>
<div>     relative</div>
<div>          应用程序启动到日志创建的相对时间</div>
<div>     t</div>
<div>     thread</div>
<div>          线程名</div>
<div>          ——%t</div>
<div>     X{key:-defaultVal}</div>
<div>     mdc{key:-defaultVal}</div>
<div>          MDC信息</div>
<div>     ex{depth} </div>
<div>     exception{depth} </div>
<div>     throwable{depth} </div>
<div>     ex{depth, evaluator-1, &#8230;, evaluator-n} </div>
<div>     exception{depth, evaluator-1, &#8230;, evaluator-n} </div>
<div>     throwable{depth, evaluator-1, &#8230;, evaluator-n}</div>
<div>          输出异常堆栈深度（如果有的话），默认full全部输出。</div>
<div>          可以指定的参数值：</div>
<div>               short：打印堆栈的第一行</div>
<div>               full：打印所有行</div>
<div>               任何数字：指定行数</div>
<div>          使用评估器evaluator决定是否打印。</div>
<div>     xEx{depth} </div>
<div>     xException{depth} </div>
<div>     xThrowable{depth} </div>
<div>     xEx{depth, evaluator-1, &#8230;, evaluator-n} </div>
<div>     xException{depth, evaluator-1, &#8230;, evaluator-n} </div>
<div>     xThrowable{depth, evaluator-1, &#8230;, evaluator-n}</div>
<div>          跟上面的类似，但是附加了包信息。</div>
<div>          如果包信息不准确（是猜测的），那么会自动在包信息前面附加一个“~”字符。</div>
<div>          如果在日志信息模式里，未指定任何异常格式，那么系统会自动在末尾加上一个%xEx。</div>
<div>          如果不想打印包信息（例如netbean里会出问题），那么在日志模式的末尾明确指定%ex即可，就会输出不包含包信息的堆栈。</div>
<div>          如果想不打印任何异常堆栈信息，可以使用%nopex。</div>
<div>          ——%xEx</div>
<div>     nopex </div>
<div>     nopexception          </div>
<div>          加上%nopex可以阻止系统自动在日志模式末尾添加%xEx——也就是完全禁止异常堆栈打印。</div>
<div>     marker</div>
<div>          输出关联的marker信息，如果marker多级关联，会都打印出来。</div>
<div>     property{key}</div>
<div>          输出key关联的属性——定义在logger context或者system properties里面。</div>
<div>     replace(p){r, t}</div>
<div>          将p中的所有符合r正则的字符串，都替换成t。</div>
<div>          例如%replace(%logger%msg){&#8216;\.&#8217;, &#8216;/&#8217;}，会将输出的logger和msg信息中的点号都替换成斜杠。</div>
<div>     rEx{depth} </div>
<div>     rootException{depth} </div>
<div>     rEx{depth, evaluator-1, &#8230;, evaluator-n} </div>
<div>     rootException{depth, evaluator-1, &#8230;, evaluator-n}</div>
<div>          类似于xEx，也会打印异常的包信息，但是会将root exception打印到前面，跟普通的异常打印顺序是反着的。</div>
<div> </div>
<div>     转义百分号： \%</div>
<div>     正常情况下转义字符会被正确分割，但有些时候例外，例如%date%nHello，系统会解析%nHello失败。如果真的需要在%n后紧跟一个Hello，可以这样：%date%n{}Hello</div>
<div> </div>
<div>     我一般用这个：</div>
<div>     %d [%t] %-5p  %c{1} &#8211; %m%n</div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</div>
<div>Format modifiers</div>
<div>     控制数据段的补齐。<br />      例如 %20.30logger </div>
<div>          如果logger长度小于20，则从左边用空格补齐；如果logger长度大于30，则从开头(左边)切去多余字符。</div>
<div>          如果20或者30前面有负号，则左右颠倒。</div>
<div>     假如想给日志级别只输出1个字符（T,D,W,I,E），不需要自己写一个Converter，而只需要配置一下即可：%.-1level</div>
<div> </div>
<div>转义选项：</div>
<div>     如果转义选项里面包含特殊字符（特别是在使用正则表达式的时候），例如大小括号、逗号、空格，那么可以用单引号或双引号括起来，例如：</div>
<div>          &lt;pattern&gt;%-5level &#8211; %replace(%msg){&#8216;\d{14,16}&#8217;, &#8216;XXXX&#8217;}%n&lt;/pattern&gt;</div>
<div>     ——这个可以把14到16位的数字（信用卡号）转换为XXXX。</div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</div>
<div>括号的特殊作用：</div>
<div>     %-30(%d{HH:mm:ss.SSS} [%thread]) %-5level %logger{32} &#8211; %msg%n</div>
<div>     可以让括号里的两个表达式联合起来按照30个字符补齐。</div>
<div>     括号可以用反斜杠转义：\(%d{HH:mm:ss.SSS} [%thread]\)</div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</div>
<div>Coloring</div>
<div>     着色，window需要引其它包，linux和mac os本身支持着色。</div>
<div>     样例：&lt;pattern&gt;[%thread] %highlight(%-5level) %cyan(%logger{15}) &#8211; %msg %n&lt;/pattern&gt;</div>
<div>          %highlight会将ERROR设为红色加粗，WARN设为红色，INFO设为蓝色，其余默认。</div>
<div>          %cyan会将logger名称设为蓝绿色。</div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</div>
<div>Evaluators</div>
<div>     EventEvaluator类的实现，用来评估一个事件是否符合打印条件。</div>
<blockquote>
<div>  &lt;evaluator name=&#8221;DISP_CALLER_EVAL&#8221;&gt;</div>
<div>    &lt;expression&gt;logger.contains(&#8220;chapters.layouts&#8221;) &amp;amp;&amp;amp; \</div>
<div>      message.contains(&#8220;who calls thee&#8221;)&lt;/expression&gt;</div>
<div>  &lt;/evaluator&gt;</div>
<div> </div>
<div>  &lt;appender name=&#8221;STDOUT&#8221; class=&#8221;ch.qos.logback.core.ConsoleAppender&#8221;&gt; </div>
<div>    &lt;encoder&gt;</div>
<div>      &lt;pattern&gt;</div>
<div>        %-4relative [%thread] %-5level &#8211; %msg%n%caller{2, DISP_CALLER_EVAL}</div>
<div>      &lt;/pattern&gt;</div>
<div>    &lt;/encoder&gt;</div>
<div>  &lt;/appender&gt;</div>
</blockquote>
<div>     注意因为xml的关系，要用&amp;amp;转义&amp;</div>
<div>     应用场景：</div>
<div>          例如，如果日志级别是WARN以上，并且logger是来自一个财务模块——那么就打印caller信息。</div>
<div> </div>
<div>     注意：</div>
<div>          在%caller转义模式中，当Evaluators返回true的时候才输出。</div>
<div>          在%ex转义模式中，当Evaluatorstrue的时候不输出。</div>
<div> </div>
<div>     例如下面的配置，当异常对象为TestException时，不输出。</div>
<blockquote>
<div>  &lt;evaluator name=&#8221;DISPLAY_EX_EVAL&#8221;&gt;</div>
<div>    &lt;expression&gt;throwable != null &amp;amp;&amp;amp; throwable instanceof  \</div>
<div>      chapters.layouts.TestException&lt;/expression&gt;</div>
<div>  &lt;/evaluator&gt;</div>
<div>        </div>
<div>  &lt;appender name=&#8221;STDOUT&#8221; class=&#8221;ch.qos.logback.core.ConsoleAppender&#8221;&gt;</div>
<div>    &lt;encoder&gt;</div>
<div>      &lt;pattern&gt;%msg%n%ex{full, DISPLAY_EX_EVAL}&lt;/pattern&gt;</div>
<div>    &lt;/encoder&gt;</div>
<div>  &lt;/appender&gt;</div>
</blockquote>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</div>
<div>Creating a custom conversion specifier</div>
<div>     略</div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</div>
<div>HTMLLayout</div>
<div>     使用html表格来布局日志信息。</div>
<div>     可以使用普通的pattern转义符，但转义字符之前，不许用包括空格在内的任何字符分隔。</div>
<blockquote>
<div>  &lt;appender name=&#8221;FILE&#8221; class=&#8221;ch.qos.logback.core.FileAppender&#8221;&gt;</div>
<div>    &lt;encoder class=&#8221;ch.qos.logback.core.encoder.LayoutWrappingEncoder&#8221;&gt;</div>
<div>      <b>&lt;layout class=&#8221;ch.qos.logback.classic.html.HTMLLayout&#8221;&gt;</b></div>
<div><b>        &lt;pattern&gt;%relative%thread%mdc%level%logger%msg&lt;/pattern&gt;</b></div>
<div><b>      &lt;/layout&gt;</b></div>
<div>    &lt;/encoder&gt;</div>
<div>    &lt;file&gt;test.html&lt;/file&gt;</div>
<div>  &lt;/appender&gt;</div>
</blockquote>
<div> </div>
<div>     HTMLLayout会自动创建一个DefaultThrowableRenderer，将异常信息打印到完整的一行里。如果不想这样，可以指定一个NOPThrowableRenderer。</div>
<div> </div>
<div>用CSS指定表格的样式：略</div>
<div> </div>
<div>该Layout最常见的用法是配合SMTPAppender，发送html格式的日志邮件。</div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</div>
<div>Logback access</div>
<div>     略</div>
<div> </div>
<div> </div>
<div> </div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_06_layouts/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/5a39b92a93cdb32c75904702aef6c743964f034250355c6cf3c07790f896217b?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">watchzerg</media:title>
		</media:content>
	</item>
		<item>
		<title>logback_doc_manual_05_encoders</title>
		<link>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_05_encoders/</link>
					<comments>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_05_encoders/#comments</comments>
		
		<dc:creator><![CDATA[watchzerg]]></dc:creator>
		<pubDate>Sun, 13 Jul 2014 11:31:07 +0000</pubDate>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_05_encoders/</guid>

					<description><![CDATA[http://logback.qos.ch/manual/encoders.html   Encoder    [&#8230;]]]></description>
										<content:encoded><![CDATA[<div><a href="http://logback.qos.ch/manual/encoders.html">http://logback.qos.ch/manual/encoders.html</a></p>
<div> </div>
<div>Encoder</div>
<div>     负责将事件对象转换为字节数组.</div>
<div>     目前只有PatternLayoutEncoder是唯一有用的Encoder。</div>
<div> </div>
<div>LayoutWrappingEncoder</div>
<div>     兼容的包装器（因为老版本的logback是跳过Encoder直接依赖Layout的）</div>
<div> </div>
<div>PatternLayoutEncoder</div>
<div>     针对PatternLayout（最常用的layout）定制的兼容包装器。</div>
<div> </div>
<div>     immediateFlush属性：是否将日志立刻写入磁盘，默认为true。将这个选项设为false可以达高4到5倍的吞吐量。</div>
<blockquote>
<div>&lt;appender name=&#8221;FILE&#8221; class=&#8221;ch.qos.logback.core.FileAppender&#8221;&gt; </div>
<div>  &lt;file&gt;foo.log&lt;/file&gt;</div>
<div>  &lt;encoder&gt;</div>
<div>    &lt;pattern&gt;%d %-5level [%thread] %logger{0}: %msg%n&lt;/pattern&gt;</div>
<div>    &lt;!&#8211; this quadruples logging throughput &#8211;&gt;</div>
<div>    <b>&lt;immediateFlush&gt;false&lt;/immediateFlush&gt;</b></div>
<div>  &lt;/encoder&gt; </div>
<div>&lt;/appender&gt;</div>
</blockquote>
<div> </div>
<div>     outputPatternAsHeader属性：在日志文件的顶部输出一行字符串样式，默认flase。</div>
<blockquote>
<div>&lt;appender name=&#8221;FILE&#8221; class=&#8221;ch.qos.logback.core.FileAppender&#8221;&gt; </div>
<div>  &lt;file&gt;foo.log&lt;/file&gt;</div>
<div>  &lt;encoder&gt;</div>
<div>    &lt;pattern&gt;%d %-5level [%thread] %logger{0}: %msg%n&lt;/pattern&gt;</div>
<div>    <b>&lt;outputPatternAsHeader&gt;true&lt;/outputPatternAsHeader&gt;</b></div>
<div>  &lt;/encoder&gt; </div>
<div>&lt;/appender&gt;</div>
</blockquote>
<div>     输出结果：</div>
<blockquote>
<div>#logback.classic pattern: %d [%thread] %-5level %logger{36} &#8211; %msg%n</div>
<div>2012-04-26 14:54:38,461 [main] DEBUG com.foo.App &#8211; Hello world</div>
<div>2012-04-26 14:54:38,461 [main] DEBUG com.foo.App &#8211; Hi again</div>
</blockquote>
<div> </div>
<div> </div>
<div> </div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_05_encoders/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/5a39b92a93cdb32c75904702aef6c743964f034250355c6cf3c07790f896217b?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">watchzerg</media:title>
		</media:content>
	</item>
		<item>
		<title>logback_doc_manual_04_appenders</title>
		<link>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_04_appenders/</link>
					<comments>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_04_appenders/#comments</comments>
		
		<dc:creator><![CDATA[watchzerg]]></dc:creator>
		<pubDate>Sun, 13 Jul 2014 11:30:34 +0000</pubDate>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_04_appenders/</guid>

					<description><![CDATA[Appender都集成ch.qos.logback.core.Appender接口。 每个Appender可以 [&#8230;]]]></description>
										<content:encoded><![CDATA[<div>Appender都集成ch.qos.logback.core.Appender接口。</div>
<div></div>
<div>每个Appender可以绑定若干个Filter。</div>
<div></div>
<div>每个Appender可以将任务代理给Layout或者Encoder。</div>
<div>每个Layout或者Encoder只能属于1个Appender。</div>
<div>Appener也可以不包含Layout或者encoder，例如SocketAppender，直接把Event序列化传输。</div>
<div></div>
<div>ch.qos.logback.core.AppenderBase这是一个抽象类，对Appender接口提供了骨架实现，线程安全。</div>
<div>ch.qos.logback.core.UnsynchronizedAppenderBase是对应的线程不安全的类，但是可以将线程安全性委托给下一层的类（例如OutputStream）</div>
<div></div>
<div>OutputStreamAppender是文件输出和控制台输出Appender的父类，类层次结构如下：</div>
<div><a href="https://watchzerg.wordpress.com/wp-content/uploads/2014/07/logback-4-1.png"><img data-attachment-id="263" data-permalink="https://watchzerg.wordpress.com/logback-4-1/" data-orig-file="https://watchzerg.wordpress.com/wp-content/uploads/2014/07/logback-4-1.png" data-orig-size="724,596" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}" data-image-title="logback-4-1" data-image-description="" data-image-caption="" data-medium-file="https://watchzerg.wordpress.com/wp-content/uploads/2014/07/logback-4-1.png?w=300" data-large-file="https://watchzerg.wordpress.com/wp-content/uploads/2014/07/logback-4-1.png?w=720" class="alignnone size-medium wp-image-263" src="https://watchzerg.wordpress.com/wp-content/uploads/2014/07/logback-4-1.png?w=300&#038;h=246" alt="logback-4-1" width="300" height="246" srcset="https://watchzerg.wordpress.com/wp-content/uploads/2014/07/logback-4-1.png?w=300 300w, https://watchzerg.wordpress.com/wp-content/uploads/2014/07/logback-4-1.png?w=600 600w, https://watchzerg.wordpress.com/wp-content/uploads/2014/07/logback-4-1.png?w=150 150w" sizes="(max-width: 300px) 100vw, 300px" /></a></div>
<div>
<div>ConsoleAppender</div>
<div>     输出到System.out or System.err</div>
<div></div>
<div>可配置属性：</div>
<div>     encoder</div>
<div>     target:     默认是System.out</div>
<div>     withJansi：     默认false，用来在windows中支持控制台色彩的</div>
<div></div>
<div>样例：</div>
<div>  &lt;appender name=&#8221;STDOUT&#8221; class=&#8221;ch.qos.logback.core.ConsoleAppender&#8221;&gt;</div>
<div>    &lt;encoder&gt;</div>
<div>      &lt;pattern&gt;%-4relative [%thread] %-5level %logger{35} &#8211; %msg %n&lt;/pattern&gt;</div>
<div>    &lt;/encoder&gt;</div>
<div>  &lt;/appender&gt;</div>
<div></div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>FileAppender</div>
<div>     写入到文件（新消息到来，写入前，才会判断是否该分割文件等）</div>
<div></div>
<div>可配置属性：</div>
<div>     append：     文件追加，默认为true</div>
<div>     encoder：</div>
<div>     file：     文件路径和名词（如果windows下，记得分隔符转义）</div>
<div>     prudent：     谨慎模式，不同JVM（甚至存在于不同主机上）安全的写入同一个文件。默认关闭。</div>
<div></div>
<div>默认每行都flush到磁盘，可以修改Encoder的immediateFlush属性来改变这一行为。</div>
<div></div>
<div>样例：</div>
<div>  &lt;appender name=&#8221;FILE&#8221; class=&#8221;ch.qos.logback.core.FileAppender&#8221;&gt;</div>
<div>    &lt;file&gt;testFile.log&lt;/file&gt;</div>
<div>    &lt;append&gt;true&lt;/append&gt;</div>
<div>    &lt;encoder&gt;</div>
<div>      &lt;pattern&gt;%-4relative [%thread] %-5level %logger{35} &#8211; %msg%n&lt;/pattern&gt;</div>
<div>    &lt;/encoder&gt;</div>
<div>  &lt;/appender&gt;</div>
<div></div>
<div>唯一名词的记录文件（通过启动时间戳）：</div>
<div>  &lt;timestamp key=&#8221;bySecond&#8221; datePattern=&#8221;yyyyMMdd&#8217;T&#8217;HHmmss&#8221;/&gt;</div>
<div>  &lt;appender name=&#8221;FILE&#8221; class=&#8221;ch.qos.logback.core.FileAppender&#8221;&gt;</div>
<div>    &lt;file&gt;log-${bySecond}.txt&lt;/file&gt;</div>
<div>    &lt;encoder&gt;</div>
<div>      &lt;pattern&gt;%logger{35} &#8211; %msg%n&lt;/pattern&gt;</div>
<div>    &lt;/encoder&gt;</div>
<div>  &lt;/appender&gt;</div>
<div>——这样就可以在每次项目启动时生成一个新的文件。</div>
<div>默认是使用xml解析的时间，也可以指定使用log context的创建时间：</div>
<div>     &lt;timestamp key=&#8221;bySecond&#8221; datePattern=&#8221;yyyyMMdd&#8217;T&#8217;HHmmss&#8221;</div>
<div>             timeReference=&#8221;contextBirth&#8221;/&gt;</div>
<div></div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>RollingFileAppender</div>
<div>     滚动记录日志文件</div>
<div>     有两个子组件：</div>
<div>          RollingPolicy ——接管“滚动”操作，控制该操作如何发生</div>
<div>          TriggeringPolicy ——决定滚动操作是否发生，何时发生</div>
<div>     默认情况下，必须同时含有上述两个组件。不过有的RollingPolicy也实现了后者的接口，那么可以身兼2职。</div>
<div></div>
<div>可配置属性：</div>
<div>     file：</div>
<div>     append：</div>
<div>     encoder：</div>
<div>     rollingPolicy：</div>
<div>     triggeringPolicy：</div>
<div>     prudent：</div>
<div></div>
<div>RollingPolicy</div>
<div>     包含的操作：将当前的日志文件归档（并重命名），压缩（如果需要）</div>
<div></div>
<div>TimeBasedRollingPolicy</div>
<div>     最常用的，基于时间滚动，同时实现了RollingPolicy和TriggeringPolicy</div>
<div>     可配置属性：</div>
<div>          fileNamePattern：     文件名匹配格式</div>
<div>               文件名+日期定义器“%d”</div>
<div>               日期定义器的格式在SimpleDateFormat中定义</div>
<div>               滚动周期是通过日期定义器推断出来的</div>
<div>               其父元素RollingFileAppender中file属性可以省略（因为可以用fileNamePattern猜测出当前时间的日志名）</div>
<div>                    也可以不省略，这样可以为“当前日志文件”和“归档日志文件”分别制定不同的路径</div>
<div>               日志定义器中的正反斜杠都会被认为是目录分隔符</div>
<div>               可以指定多个日期定义器，但只能有1个是主要的，其余的必须标记为aux（辅助的）</div>
<div>          maxHistory：     最大文件数</div>
<div>          cleanHistoryOnStart：     启动时清除历史归档日志</div>
<div></div>
<div>     对fileNamePattern的更详细的解释和示例：</div>
<div>          /wombat/foo.%d</div>
<div>               按天分隔日志</div>
<div>               未指定格式，所以默认为yyyy-MM-dd（按天滚动）</div>
<div>               如果在RollingFileAppender中指定了file（默认日志文件名）：</div>
<div>                    今天日志为 /wombat/foo.2006-11-24</div>
<div>                    昨天日志为 /wombat/foo.2006-11-23</div>
<div>               如果没有在RollingFileAppender中指定file为“/wombat/foo.txt”，</div>
<div>                    今天日志为 /wombat/foo.txt</div>
<div>                    昨天日志为 /wombat/foo.2006-11-23</div>
<div>               ——其实不指定默认日志文件名的方式更好，因为避免了滚动时重命名操作，也就避免了潜在异常。</div>
<div>          /wombat/%d{yyyy/MM}/foo.txt</div>
<div>               按“年/月”分两级文件夹，文件名固定为“foo.txt”</div>
<div>               如果在RollingFileAppender中指定了file（默认日志文件名）：</div>
<div>                    2006年10月日志为 /wombat/2006/10/foo.txt</div>
<div>                    2006年11月日志为 /wombat/2006/11/foo.txt</div>
<div>               如果没有在RollingFileAppender中指定file为“/wombat/foo.txt”，</div>
<div>                    当前正在写的日志永远为 /wombat/foo.txt</div>
<div>                    归档的日志格式为 /wombat/2006/10/foo.txt</div>
<div>          /wombat/foo.%d{yyyy-ww}.log</div>
<div>               每个星期归档一个新文件（注意具体“哪天算是一个星期的第一天”取决于系统locale属性）</div>
<div>          /wombat/foo%d{yyyy-MM-dd_HH}.log</div>
<div>               每小时一次归档</div>
<div>          /wombat/foo%d{yyyy-MM-dd_HH-mm}.log</div>
<div>               每分钟一次归档</div>
<div>          /foo/%d{yyyy-MM,aux}/%d.log</div>
<div>               每天一次归档，但每个月一个新文件夹</div>
<div></div>
<div>     如果fileNamePattern文件名是以.gz或者.zip结尾的，那么TimeBasedRollingPolicy会自动压缩：</div>
<div>          /wombat/foo.%d.gz</div>
<div></div>
<div>     日志归档是“记录日志的事件”触发的，所以有一定延迟。例如第二天的第一条日志是临晨01:00才过来，那么这个时候才会归档前一天的日志。</div>
<div></div>
<div>配置样例：</div>
<div>  &lt;appender name=&#8221;FILE&#8221; class=&#8221;ch.qos.logback.core.rolling.RollingFileAppender&#8221;&gt;</div>
<div>    &lt;file&gt;logFile.log&lt;/file&gt;</div>
<div>    &lt;rollingPolicy class=&#8221;ch.qos.logback.core.rolling.TimeBasedRollingPolicy&#8221;&gt;</div>
<div>      &lt;fileNamePattern&gt;logFile.%d{yyyy-MM-dd}.log&lt;/fileNamePattern&gt;</div>
<div>      &lt;maxHistory&gt;30&lt;/maxHistory&gt;</div>
<div>    &lt;/rollingPolicy&gt;</div>
<div></div>
<div>    &lt;encoder&gt;</div>
<div>      &lt;pattern&gt;%-4relative [%thread] %-5level %logger{35} &#8211; %msg%n&lt;/pattern&gt;</div>
<div>    &lt;/encoder&gt;</div>
<div>  &lt;/appender&gt;</div>
<div></div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>FixedWindowRollingPolicy</div>
<div>     可配置属性：</div>
<div>          minIndex:</div>
<div>          maxIndex:</div>
<div>          fileNamePattern:</div>
<div>               必须包含“%i”占位符，用来表示将当前索引值插入什么位置。</div>
<div>               例如“MyLogFile%i.log”配合“最小1，最大3”，表示文件名为：MyLogFile1.log, MyLogFile2.log, MyLogFile3.log</div>
<div>               同样加上zip或gz后缀可以启用压缩</div>
<div>     因为每次需要很多重命名操作（重命名次数等于window size），所以如果设置size超过20，会被强制指定为20.</div>
<div></div>
<div>     配置样例：</div>
<div>  &lt;appender name=&#8221;FILE&#8221; class=&#8221;ch.qos.logback.core.rolling.RollingFileAppender&#8221;&gt;</div>
<div>    &lt;file&gt;test.log&lt;/file&gt;</div>
<div></div>
<div>    &lt;rollingPolicy class=&#8221;ch.qos.logback.core.rolling.FixedWindowRollingPolicy&#8221;&gt;</div>
<div>      &lt;fileNamePattern&gt;tests.%i.log.zip&lt;/fileNamePattern&gt;</div>
<div>      &lt;minIndex&gt;1&lt;/minIndex&gt;</div>
<div>      &lt;maxIndex&gt;3&lt;/maxIndex&gt;</div>
<div>    &lt;/rollingPolicy&gt;</div>
<div></div>
<div>    &lt;triggeringPolicy class=&#8221;ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy&#8221;&gt;</div>
<div>      &lt;maxFileSize&gt;5MB&lt;/maxFileSize&gt;</div>
<div>    &lt;/triggeringPolicy&gt;</div>
<div>    &lt;encoder&gt;</div>
<div>      &lt;pattern&gt;%-4relative [%thread] %-5level %logger{35} &#8211; %msg%n&lt;/pattern&gt;</div>
<div>    &lt;/encoder&gt;</div>
<div>  &lt;/appender&gt;</div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>SizeAndTimeBasedFNATP（File Naming And Triggering Policy）——是TimeBasedRollingPolicy的一个子组件</div>
<div>     配置样例：</div>
<div>  &lt;appender name=&#8221;ROLLING&#8221; class=&#8221;ch.qos.logback.core.rolling.RollingFileAppender&#8221;&gt;</div>
<div>    &lt;file&gt;mylog.txt&lt;/file&gt;</div>
<div>    &lt;rollingPolicy class=&#8221;ch.qos.logback.core.rolling.TimeBasedRollingPolicy&#8221;&gt;</div>
<div>      &lt;!&#8211; rollover daily &#8211;&gt;</div>
<div>      &lt;fileNamePattern&gt;mylog-%d{yyyy-MM-dd}.%i.txt&lt;/fileNamePattern&gt;</div>
<div>      &lt;timeBasedFileNamingAndTriggeringPolicy</div>
<div>            class=&#8221;ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP&#8221;&gt;</div>
<div>        &lt;!&#8211; or whenever the file size reaches 100MB &#8211;&gt;</div>
<div>        &lt;maxFileSize&gt;100MB&lt;/maxFileSize&gt;</div>
<div>      &lt;/timeBasedFileNamingAndTriggeringPolicy&gt;</div>
<div>    &lt;/rollingPolicy&gt;</div>
<div>    &lt;encoder&gt;</div>
<div>      &lt;pattern&gt;%msg%n&lt;/pattern&gt;</div>
<div>    &lt;/encoder&gt;</div>
<div>  &lt;/appender&gt;</div>
<div>     ——每天滚动一个文件，如果文件体积达到100M，则也拆分。</div>
<div>     ——也支持自动删除老文件，可以通过maxHistory指定保存的最多文件数（每天最多这么多，还是一共最多这么多？）</div>
<div></div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>SizeBasedTriggeringPolicy——一般配合FixedWindowRollingPolicy使用</div>
<div>     指定文件超过“maxFileSize”指定大小时，上层RollingFileAppender触发滚动操作。</div>
<div>     默认“10MB”，可以指定各种后缀：KB,MB,GB</div>
<div></div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div></div>
<div>SocketAppender and SSLSocketAppender</div>
<div>以及后面关于网络，数据库，远程日志服务器，JNDI等……省略……</div>
<div></div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>SiftingAppender</div>
<div>     可以根据指定的变量分割文件。例如根据用户ID，则每个用户一个日志文件。</div>
<div></div>
<div>     可配置参数：</div>
<div>          timeout：如果一个关联的appender如果超过默认30分钟没有被访问，则被SiftingAppender卸载掉。</div>
<div>          maxAppenderCount：可以最大追踪的关联appender数量，默认int最大值。</div>
<div>     这个Appener会把日志记录动作代理给关联的appender。</div>
<div>     选择条件由Discriminator指定，默认为MDCBasedDiscriminator。</div>
<div></div>
<div>     示例，假设应用程序这样设置了MDC信息：</div>
<blockquote>
<div>logger.debug(&#8220;Application started&#8221;);</div>
<div>MDC.put(&#8220;userid&#8221;, &#8220;Alice&#8221;);</div>
<div>logger.debug(&#8220;Alice says hello&#8221;);</div>
</blockquote>
<div>     然后这样配置：</div>
<div>  &lt;appender name=&#8221;SIFT&#8221; class=&#8221;ch.qos.logback.classic.sift.SiftingAppender&#8221;&gt;</div>
<div>    &lt;!&#8211; in the absence of the class attribute, it is assumed that the</div>
<div>         desired discriminator type is</div>
<div>         ch.qos.logback.classic.sift.MDCBasedDiscriminator &#8211;&gt;</div>
<div>    &lt;discriminator&gt;</div>
<div>      &lt;key&gt;userid&lt;/key&gt;</div>
<div>      &lt;defaultValue&gt;unknown&lt;/defaultValue&gt;</div>
<div>    &lt;/discriminator&gt;</div>
<div>    &lt;sift&gt;</div>
<div>      &lt;appender name=&#8221;FILE-${userid}&#8221; class=&#8221;ch.qos.logback.core.FileAppender&#8221;&gt;</div>
<div>        &lt;file&gt;${userid}.log&lt;/file&gt;</div>
<div>        &lt;append&gt;false&lt;/append&gt;</div>
<div>        &lt;layout class=&#8221;ch.qos.logback.classic.PatternLayout&#8221;&gt;</div>
<div>          &lt;pattern&gt;%d [%thread] %level %mdc %logger{35} &#8211; %msg%n&lt;/pattern&gt;</div>
<div>        &lt;/layout&gt;</div>
<div>      &lt;/appender&gt;</div>
<div>    &lt;/sift&gt;</div>
<div>  &lt;/appender&gt;</div>
<div></div>
<div>     因为确定timeout和maxAppenderCount比较困难，所以如果程序可以知道“执行到某个地方很可能应该关闭对应的appender”，那么可以明确指定一个FINALIZE_SESSION的marker。这样siftingAppender关联的对应appender，会在接到这个marker的几秒钟后关闭。例如：</div>
<div>import static ch.qos.logback.classic.ClassicConstants.FINALIZE_SESSION_MARKER;</div>
<div>  void job(String jobId) {</div>
<div>    MDC.put(&#8220;jobId&#8221;, jobId);</div>
<div>    logger.info(&#8220;Starting job.&#8221;);</div>
<div></div>
<div>    // will cause the nested appender reach end-of-life. It will</div>
<div>    // linger for a few seconds.</div>
<div>    logger.info(FINALIZE_SESSION_MARKER, &#8220;About to end the job&#8221;);</div>
<div></div>
<div>    try {</div>
<div>      .. perform clean up</div>
<div>    } catch(Exception e);</div>
<div>      // This log statement will be handled by the lingering appender.</div>
<div>      // No new appender will be created.</div>
<div>      logger.error(&#8220;unexpected error while cleaning up&#8221;, e);</div>
<div>    }</div>
<div>  }</div>
<div></div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>SMTPAppender</div>
<div>     将日志事件缓存指定的数量，被特定事件触发后，异步发送邮件。</div>
<div>          smtpHost</div>
<div>          smtpPort     默认25</div>
<div>          to          发送目标，多个联系人可以用逗号隔开，也可以用多个&lt;to&gt;元素</div>
<div>          from      发送者邮箱，如果想包含名字，可以用特定格式“Adam Smith &amp;lt;smith@moral.org&amp;gt;”</div>
<div>          subject     邮件标题，可以使用PatternLayout的转义字符，会用“触发该邮件的日志事件”的信息替换转义字符</div>
<div>          discriminator     默认只有一个缓存。通过指定该属性，可以有多个缓存，这样可以根据事件信息发给不同的人或者ip</div>
<div>          evaluator     声明一个&lt;EventEvaluator/&gt;元素，通过class属性指定类型。默认为OnErrorEvaluator，也可以自己指定OnMarkerEvaluator,JaninoEventEvaluator,GEventEvaluator</div>
<div>          cyclicBufferTracker     环形缓存跟踪器，基于discriminator的返回值工作。默认保存缓存大小为256</div>
<div>          username</div>
<div>          password</div>
<div>          STARTTLS     如果开启，会发起STARTTLS命令，导致连接转换为SSL。连接默认是不使用加密的。默认为false</div>
<div>          SSL          如果开启，那么使用SSL连接。默认false。</div>
<div>          charsetEncoding     默认UTF-8</div>
<div>          localhost     如果SMTP发送方的hostname没配置好，邮件服务器可能拒绝请求，这个时候可以设置这个值为客户端全名。</div>
<div>          asynchronousSending     异步发送，默认true。特定情况下需要设置为false，例如应用程序发送完邮件就会立即关闭。</div>
<div>          includeCallerData     包含调用者信息，默认为false。</div>
<div>          sessionViaJNDI     logback依赖javax.mail.Session来发送邮件。该属性默认为false，SMTPAppender会根据配置构建新的Session。如果设为true，会去web容器寻找Session对象，此时应用程序不应该再依赖mail.jar等</div>
<div>          jndiLocation     查找JNDI的路径，例如&#8221;java:comp/env/mail/Session&#8221;</div>
<div></div>
<div>     最多保存256条日志事件，否则内存消耗太大（不建议自己指定其它值）。</div>
<div>     发邮件依赖JavaMail API (mail.jar)和JavaBeans Activation Framework (activation.jar) ——maven里引入前者会自动依赖后者。</div>
<div></div>
<div>     发送者和接收者都可以是动态属性：</div>
<blockquote>
<div>&lt;appender name=&#8221;EMAIL&#8221; class=&#8221;ch.qos.logback.classic.net.SMTPAppender&#8221;&gt;</div>
<div>  &lt;smtpHost&gt;${smtpHost}&lt;/smtpHost&gt;</div>
<div>  &lt;to&gt;<b>${to}</b>&lt;/to&gt;</div>
<div>  &lt;from&gt;<b>${from}</b>&lt;/from&gt;</div>
<div>  &lt;layout class=&#8221;ch.qos.logback.classic.html.HTMLLayout&#8221;/&gt;</div>
<div>&lt;/appender&gt;</div>
</blockquote>
<div>     注意上面的layout也可以用patternLayout：</div>
<blockquote>
<div>    &lt;layout class=&#8221;ch.qos.logback.classic.PatternLayout&#8221;&gt;</div>
<div>      &lt;pattern&gt;%date %-5level %logger{35} &#8211; %message%n&lt;/pattern&gt;</div>
<div>    &lt;/layout&gt;</div>
</blockquote>
<div></div>
<div>触发事件：</div>
<div>     默认是OnErrorEvaluator，但可以自己定制。SMTPAppender仅维护一个Evaluator，这个Evaluator可以自己维护状态，例如可以实现一个CounterBasedEvaluator。</div>
<div></div>
<div>基于标记Marker的事件触发：</div>
<blockquote>
<div>Marker notifyAdmin = MarkerFactory.getMarker(&#8220;NOTIFY_ADMIN&#8221;);</div>
<div>logger.error(notifyAdmin,</div>
<div>  &#8220;This is a serious an error requiring the admin&#8217;s attention&#8221;,</div>
<div>   new Exception(&#8220;Just testing&#8221;));</div>
</blockquote>
<div></div>
<blockquote>
<div>  &lt;appender name=&#8221;EMAIL&#8221; class=&#8221;ch.qos.logback.classic.net.SMTPAppender&#8221;&gt;</div>
<div>    &lt;evaluator class=&#8221;ch.qos.logback.classic.boolex.OnMarkerEvaluator&#8221;&gt;</div>
<div>      &lt;marker&gt;NOTIFY_ADMIN&lt;/marker&gt;</div>
<div>      &lt;!&#8211; you specify add as many markers as you want &#8211;&gt;</div>
<div>      &lt;marker&gt;TRANSACTION_FAILURE&lt;/marker&gt;</div>
<div>    &lt;/evaluator&gt;</div>
<div>  &lt;/appender&gt;</div>
</blockquote>
<div></div>
<div>还可以使用更加通用的JaninoEventEvaluator或者GEventEvaluator，他们提供更复杂更强大的甄别功能（也包含了OnMarkerEvaluator的功能）。</div>
<div></div>
<div>身份验证/STARTTLS/SSL</div>
<div>     SMTPAppender支持用户名和密码的加密验证。</div>
<div>     STARTTLS方式是先使用非加密方式建立连接，然后切换到SSL（常用于server-server交互）。</div>
<div>     SSL方式是直接建立SSL连接（一般用于client-sever交互）。</div>
<div></div>
<div>Appender configuration for Gmail (SSL)</div>
<blockquote>
<div>&lt;appender name=&#8221;EMAIL&#8221; class=&#8221;ch.qos.logback.classic.net.SMTPAppender&#8221;&gt;</div>
<div>    &lt;smtpHost&gt;smtp.gmail.com&lt;/smtpHost&gt;</div>
<div>    &lt;smtpPort&gt;465&lt;/smtpPort&gt;</div>
<div>    &lt;SSL&gt;true&lt;/SSL&gt;</div>
<div>    &lt;username&gt;YOUR_USERNAME@gmail.com&lt;/username&gt;</div>
<div>    &lt;password&gt;YOUR_GMAIL_PASSWORD&lt;/password&gt;</div>
<div>  &lt;/appender&gt;</div>
</blockquote>
<div></div>
<div>SMTPAppender for Gmail (STARTTLS)</div>
<blockquote>
<div>  &lt;appender name=&#8221;EMAIL&#8221; class=&#8221;ch.qos.logback.classic.net.SMTPAppender&#8221;&gt;</div>
<div>    &lt;smtpHost&gt;smtp.gmail.com&lt;/smtpHost&gt;</div>
<div>    &lt;smtpPort&gt;587&lt;/smtpPort&gt;</div>
<div>    &lt;STARTTLS&gt;true&lt;/STARTTLS&gt;</div>
<div>    &lt;username&gt;YOUR_USERNAME@gmail.com&lt;/username&gt;</div>
<div>    &lt;password&gt;YOUR_GMAIL_xPASSWORD&lt;/password&gt;</div>
<div>  &lt;/appender&gt;</div>
</blockquote>
<div></div>
<div>Discriminator</div>
<div>     用MDCBasedDiscriminator做示例，根据MDC的值，维护多个缓存</div>
<blockquote>
<div>  &lt;appender name=&#8221;EMAIL&#8221; class=&#8221;ch.qos.logback.classic.net.SMTPAppender&#8221;&gt;</div>
<div><b>    &lt;discriminator class=&#8221;ch.qos.logback.classic.sift.MDCBasedDiscriminator&#8221;&gt;</b></div>
<div><b>      &lt;key&gt;req.remoteHost&lt;/key&gt;</b></div>
<div><b>      &lt;defaultValue&gt;default&lt;/defaultValue&gt;</b></div>
<div><b>    &lt;/discriminator&gt;</b></div>
<div>    &lt;subject&gt;${HOSTNAME} &#8212; <b>%X{req.remoteHost}</b> %msg&#8221;&lt;/subject&gt;</div>
<div>    &lt;layout class=&#8221;ch.qos.logback.classic.html.HTMLLayout&#8221;&gt;</div>
<div>      &lt;pattern&gt;%date%level%thread%<b>X{req.remoteHost}</b>%X{req.requestURL}%logger%msg&lt;/pattern&gt;</div>
<div>    &lt;/layout&gt;</div>
<div>  &lt;/appender&gt;</div>
</blockquote>
<div>     上面的例子先利用了MDCInsertingServletFilter把请求方的hostname或ip设置到MDC中。</div>
<div>     每一个remoteHost都有一个自己的buffer，一旦某个remoteHost触发了发送邮件的请求，那么该buffer里的256条信息会被发送出去。</div>
<div></div>
<div>Buffer管理：</div>
<div>     上面的例子，每一个远程地址都有自己的buffer，会极大的消耗内存。</div>
<div>     默认情况下，logback内部最多允许64个buffer同时存在，LRU算法换出。超过30分钟未使用的buffer也会被换出。该值可以通过maxNumberOfBuffers来设置。</div>
<div>
<div>
<div>          这里有问题，通过各种手段都无法设置此值，貌似是个bug，我在尽我所能查遍所有资料后，在stackoverflowh和官方jira上提了这个问题：</div>
<div>          <a href="http://stackoverflow.com/questions/24836151">http://stackoverflow.com/questions/24836151</a></div>
<div>          <a href="http://jira.qos.ch/browse/LOGBACK-996">http://jira.qos.ch/browse/LOGBACK-996</a></div>
</div>
</div>
<div>     在高强度系统中，上面的2个保护机制不够，需要加入手工管理：通过明确指定“FINALIZE_SESSION”这个Marker，来告诉logback去释放对应的buffer，这样就可以安全的将maxNumberOfBuffers设置为512乃至1024。（具体设置办法参照SiftingAppender里描述的）</div>
<div></div>
<div>这里是官方的一个SMTPAppender的例子：</div>
<div><a href="http://logback.qos.ch/recipes/emailPerTransaction.html">http://logback.qos.ch/recipes/emailPerTransaction.html</a></div>
<div>注意Marker可以叠加，所以如果有必要，可以把“发送邮件的Marker”和“终结Session（以便清理buffer）的Marker”关联在一起。</div>
<div>     Marker SMTP_TRIGGER = MarkerFactory.getMarker(&#8220;SMTP_TRIGGER&#8221;);</div>
<div>     SMTP_TRIGGER.add(FINALIZE_SESSION_MARKER);</div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>AsyncAppender</div>
<div>     类似于单独的一个事件分发器，所以必须引用另一个appender。</div>
<div>     用一个BlockingQueue缓冲事件，然后创建一个线程，从队列里获取事件并分发给引用的appender。</div>
<div>     默认情况下，如果队列达到80%的容量，则丢弃TRACE,DEBUG,INFO级别的日志。</div>
<div>     应用程序停止的时候，会通知LoggerContext停止，在停止各个Appender时，AsyncAppender会停止接收日志，并将信息flush到磁盘。</div>
<div></div>
<div>     配置参数：</div>
<div>          queueSize：默认256</div>
<div>          discardingThreshold：默认队列20%可用的时候开始选择性抛弃信息，设为0表示不抛弃</div>
<div>          includeCallerData：是否包括调用者信息（重开销），默认只复制线程名和MDC信息（因为切换了线程，其余信息会丢失）</div>
<div>     队列全满的时候，写日志动作会被block，直到队列有可用空间。</div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>自定义Appender</div>
<div>     略</div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>Logback Access</div>
<div>     大部分Appender，在logback-classic与logback-access中使用方式类似。</div>
</div>
<div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_04_appenders/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/5a39b92a93cdb32c75904702aef6c743964f034250355c6cf3c07790f896217b?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">watchzerg</media:title>
		</media:content>

		<media:content url="https://watchzerg.wordpress.com/wp-content/uploads/2014/07/logback-4-1.png?w=300" medium="image">
			<media:title type="html">logback-4-1</media:title>
		</media:content>
	</item>
		<item>
		<title>logback_doc_manual_03_configuration</title>
		<link>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_03_configuration/</link>
					<comments>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_03_configuration/#comments</comments>
		
		<dc:creator><![CDATA[watchzerg]]></dc:creator>
		<pubDate>Sun, 13 Jul 2014 11:22:01 +0000</pubDate>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_03_configuration/</guid>

					<description><![CDATA[http://logback.qos.ch/manual/configuration.html   &#821 [&#8230;]]]></description>
										<content:encoded><![CDATA[<div>
<div><a href="http://logback.qos.ch/manual/configuration.html">http://logback.qos.ch/manual/configuration.html</a></div>
<div> </div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>与spring的配置：</div>
<div>貌似官网上没有介绍，但是作者在github上建立了一个扩展项目用于logback与spring结合。</div>
<div><a href="https://github.com/qos-ch/logback-extensions">https://github.com/qos-ch/logback-extensions</a></div>
<div>目前最新版本是0.1.2，很多maven公开库里已经有了。</div>
<div> </div>
<div>maven配置：</div>
<div>&lt;dependency&gt;  </div>
<div>     &lt;groupId&gt;org.logback-extensions&lt;/groupId&gt;  </div>
<div>     &lt;artifactId&gt;logback-ext-spring&lt;/artifactId&gt;  </div>
<div>     &lt;version&gt;0.1.2&lt;/version&gt;  </div>
<div>&lt;/dependency&gt;</div>
<div> </div>
<div>web.xml配置日志框架启动监听器：</div>
<div>&lt;!&#8211; logback配置文件 &#8211;&gt;</div>
<div>&lt;context-param&gt;</div>
<div>     &lt;param-name&gt;logbackConfigLocation&lt;/param-name&gt;</div>
<div>     &lt;param-value&gt;/WEB-INF/classes/logback.xml&lt;/param-value&gt;</div>
<div>&lt;/context-param&gt;</div>
<div>&lt;!&#8211; logback加载监听器 &#8211;&gt;</div>
<div>&lt;listener&gt;</div>
<div>     &lt;listener-class&gt;</div>
<div>          ch.qos.logback.ext.spring.web.LogbackConfigListener</div>
<div>     &lt;/listener-class&gt;</div>
<div>&lt;/listener&gt;</div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>logback中的配置：</div>
<div> </div>
<div>可以用java程序配置，也可以用xml或者groovy脚本配置。</div>
<div>使用 <a href="http://logback.qos.ch/translator/" rel="nofollow">http://logback.qos.ch/translator/</a> 可以把log4j的配置自动转换过来。</div>
<div> </div>
<div>logback内部查找配置的过程：</div>
<div>     1，在classpath查找“logback.groovy”</div>
<div>     2，在classpath查找“logback-test.xml”</div>
<div>     3，在classpath查找“logback.xml”</div>
<div>     4，使用自身的BasicConfigurator做基本配置，所有日志被输出到控制台。</div>
<div>     —— 一般把“logback-test.xml”放到maven的测试路径，把“logback.xml”放到maven的正式路径，前者优先级更高。</div>
<div> </div>
<div>logback的状态，加载配置文件的过程：</div>
<div>     代码打印：</div>
<div>          LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();</div>
<div>          StatusPrinter.print(lc);</div>
<div>     配置文件形式打印：</div>
<div>          &lt;configuration debug=&#8221;true&#8221;&gt;</div>
<div>            &#8230; </div>
<div>          &lt;/configuration&gt;</div>
<div>     也可以通过设置StatusListener来监听logback的启动和打印状态——在生产环境挺有用，因为配置文件路径挺深。</div>
<div> </div>
<div>通过在系统变量里加入&#8221;logback.configurationFile&#8221;指定logback配置文件路径：</div>
<div>     java -Dlogback.configurationFile=/path/to/config.xml chapters.configuration.MyApp1</div>
<div> </div>
<div>设置自动扫描和遇到变更时重新加载配置文件（不指定周期的话默认每1分钟）：</div>
<div>     &lt;configuration scan=&#8221;true&#8221; scanPeriod=&#8221;30 seconds&#8221;&gt; </div>
<div>       &#8230; </div>
<div>     &lt;/configuration&gt; </div>
<div>     每当N个（logback会自动调节）日志请求，logback会检查一下扫描周期是否已经到达，如到达再检查配置文件。</div>
<div> </div>
<div>通过web访问状态信息：</div>
<div>在web.xml配置：</div>
<div>     &lt;servlet&gt;</div>
<div>         &lt;servlet-name&gt;ViewStatusMessages&lt;/servlet-name&gt;</div>
<div>         &lt;servlet-class&gt;ch.qos.logback.classic.ViewStatusMessagesServlet&lt;/servlet-class&gt;</div>
<div>      &lt;/servlet&gt;</div>
<div>      &lt;servlet-mapping&gt;</div>
<div>         &lt;servlet-name&gt;ViewStatusMessages&lt;/servlet-name&gt;</div>
<div>         &lt;url-pattern&gt;/lbClassicStatus&lt;/url-pattern&gt;</div>
<div>      &lt;/servlet-mapping&gt;</div>
<div>然后访问：http://host/yourWebapp/lbClassicStatus</div>
<div> </div>
<div>注册控制台状态监听器：</div>
<div>     java代码方式：</div>
<div>          LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); </div>
<div>          StatusManager statusManager = lc.getStatusManager();</div>
<div>          OnConsoleStatusListener onConsoleListener = new OnConsoleStatusListener();</div>
<div>          statusManager.add(onConsoleListener);</div>
<div>     用配置文件方式：</div>
<div>          &lt;configuration&gt;</div>
<div>            &lt;statusListener class=&#8221;ch.qos.logback.core.status.OnConsoleStatusListener&#8221; /&gt;  </div>
<div>            &#8230;</div>
<div>          &lt;/configuration&gt;</div>
<div>     系统变量方式：</div>
<div>          java -Dlogback.statusListenerClass=ch.qos.logback.core.status.OnConsoleStatusListener</div>
<div> </div>
<div>停止logback：</div>
<div>     java代码方式：</div>
<div>          LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();</div>
<div>          loggerContext.stop();</div>
<div>     web应用：</div>
<div>          ServletContextListener.contextDestroyed()会自动调用上面的stop方法。</div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>配置文件格式：</div>
<div>     最外层是&lt;configuration&gt;元素，里面有&lt;appender&gt;&lt;logger&gt;&lt;root&gt;元素</div>
<div> </div>
<div>&lt;logger&gt;元素：</div>
<div>     level属性可以这些值：TRACE, DEBUG, INFO, WARN, ERROR, ALL, OFF，也可以明确指定继承：INHERITED或者NULL</div>
<div>     包含若干&lt;appender-ref&gt;元素，指定appender的名字。</div>
<div> </div>
<div>从DEBUG改为INFO级别：</div>
<div>&lt;configuration&gt;</div>
<div>  &lt;appender name=&#8221;STDOUT&#8221; class=&#8221;ch.qos.logback.core.ConsoleAppender&#8221;&gt;</div>
<div>    &lt;!&#8211; encoders are assigned the type</div>
<div>         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default &#8211;&gt;</div>
<div>    &lt;encoder&gt;</div>
<div>      &lt;pattern&gt;%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} &#8211; %msg%n&lt;/pattern&gt;</div>
<div>    &lt;/encoder&gt;</div>
<div>  &lt;/appender&gt;</div>
<div> </div>
<div>  &lt;logger name=&#8221;chapters.configuration&#8221; level=&#8221;INFO&#8221;/&gt;</div>
<div> </div>
<div>  &lt;!&#8211; Strictly speaking, the level attribute is not necessary since &#8211;&gt;</div>
<div>  &lt;!&#8211; the level of the root level is set to DEBUG by default.       &#8211;&gt;</div>
<div>  &lt;root level=&#8221;DEBUG&#8221;&gt;          </div>
<div>    &lt;appender-ref ref=&#8221;STDOUT&#8221; /&gt;</div>
<div>  &lt;/root&gt;  </div>
<div>&lt;/configuration&gt;</div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>配置Appender：</div>
<div>     name和class属性</div>
<div>     内嵌0个或1个layout元素，0个或多个encoder元素，0个或多个filter元素。还可以内嵌任意数量的appdenter类的属性（例如自定义的appender类）。</div>
<div>     layout元素应该内嵌具体的layout类，但是默认就是PatternLayoutEncoder。</div>
<div> </div>
<div>Appender的累加性：</div>
<div>     logger会记录在所有绑定在它自身的appender，同时也会记录在该logger祖先的appender上，所以有可能重复记录！</div>
<div> </div>
<div>配置Logger Context（可以用在“多个项目写入同一个日志文件”这种情况）：</div>
<div>&lt;configuration&gt;</div>
<div>  &lt;contextName&gt;myAppName&lt;/contextName&gt;</div>
<div>  &#8230;</div>
<div>&lt;/configuration&gt;</div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>变量替换：</div>
<div>&lt;configuration&gt;</div>
<div>  &lt;property name=&#8221;USER_HOME&#8221; value=&#8221;/home/sebastien&#8221; /&gt;</div>
<div> </div>
<div>  &lt;appender name=&#8221;FILE&#8221; class=&#8221;ch.qos.logback.core.FileAppender&#8221;&gt;</div>
<div>    &lt;file&gt;${USER_HOME}/myApp.log&lt;/file&gt;</div>
<div>    &#8230;</div>
<div>  &lt;/appender&gt;</div>
<div>   &#8230;</div>
<div>&lt;/configuration&gt;</div>
<div>——上面的变量定义在系统属性里也可以：java -DUSER_HOME=&#8221;/home/sebastien&#8221; MyApp2</div>
<div> </div>
<div>变量也可以定义在文件里：</div>
<div>&lt;configuration&gt;</div>
<div>  &lt;property file=&#8221;src/main/java/chapters/configuration/variables1.properties&#8221; /&gt;</div>
<div>  &lt;appender name=&#8221;FILE&#8221; class=&#8221;ch.qos.logback.core.FileAppender&#8221;&gt;</div>
<div>     &lt;file&gt;${USER_HOME}/myApp.log&lt;/file&gt;</div>
<div>     &#8230;</div>
<div>   &lt;/appender&gt;</div>
<div>   &#8230;</div>
<div>&lt;/configuration&gt;</div>
<div>——对应路径的文件里应该加入“USER_HOME=/home/sebastien”</div>
<div>（这路径挺诡异啊，是maven的结构，那打包后岂不是不能用了？）</div>
<div>像这样引用classpath的还靠谱些：</div>
<div>&lt;property resource=&#8221;resource1.properties&#8221; /&gt;</div>
<div> </div>
<div>变量可以指定作用域：local，context，system</div>
<div>变量可以相互引用：</div>
<div>     USER_HOME=/home/sebastien</div>
<div>     fileName=myApp.log</div>
<div>     destination=${USER_HOME}/${fileName}</div>
<div>命名引用：如果&#8221;userid&#8221;会被替换为&#8221;alice&#8221;，那么&#8221;${${userid}.password}&#8221;会被替换为&#8221;alice.password&#8221;对应的值。</div>
<div>变量可以指定默认值：${aName:-golden}  ——这就指定了默认值golden</div>
<div>变量的默认值也可以引用变量： &#8220;${id:-${userid}}</div>
<div> </div>
<div>预置变量：HOSTNAME,CONTEXT_NAME</div>
<div> </div>
<div>可以通过timestamp元素定义一个当前的日期和时间的动态元素。</div>
<div> </div>
<div>可以自己继承PropertyDefiner实现动态生成属性，现在内置了2个动态属性生成器：</div>
<div>     FileExistsPropertyDefiner     如果指定路径文件存在，则将指定属性设为“true”，反之亦然</div>
<div>     ResourceExistsPropertyDefiner     如果指定资源存在，则将指定属性设为“true”，反之亦然</div>
<div> </div>
<div>条件语句：</div>
<div>   &lt;!&#8211; if-then form &#8211;&gt;</div>
<div>   &lt;if condition=&#8221;some conditional expression&#8221;&gt;</div>
<div>    &lt;then&gt;</div>
<div>      &#8230;</div>
<div>    &lt;/then&gt;</div>
<div>  &lt;/if&gt;</div>
<div> </div>
<div>  &lt;!&#8211; if-then-else form &#8211;&gt;</div>
<div>  &lt;if condition=&#8221;some conditional expression&#8221;&gt;</div>
<div>    &lt;then&gt;</div>
<div>      &#8230;</div>
<div>    &lt;/then&gt;</div>
<div>    &lt;else&gt;</div>
<div>      &#8230;</div>
<div>    &lt;/else&gt;    </div>
<div>  &lt;/if&gt;</div>
<div> </div>
<div>判断条件只支持context变量和system变量，用property()或者p()来引用——如果没有设定对应变量，这两个方法会返回空串（而不是null）</div>
<div>isDefine()和isNull()分别判断变量是否设置和变量是否为空。</div>
<div>     &lt;if condition=&#8217;property(&#8220;HOSTNAME&#8221;).contains(&#8220;torino&#8221;)&#8217;&gt;</div>
<div>     &#8230;</div>
<div>     &lt;/if&gt;</div>
<div> </div>
<div>可以从JNDI读取变量值（作用域为local）。也可以将从JNDI读取的变量存入另一个不同作用域的变量。</div>
<div>     &lt;configuration&gt;</div>
<div>       &lt;insertFromJNDI env-entry-name=&#8221;java:comp/env/appName&#8221; as=&#8221;appName&#8221; /&gt;</div>
<div>       &#8230;</div>
<div>     &lt;/configuration&gt;</div>
<div> </div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>文件包含（可以使用相对路径。当前路径已经在当前项目中定义，所以没必要与配置文件路径关联）：</div>
<div>&lt;configuration&gt;</div>
<div>  &lt;include file=&#8221;src/main/java/chapters/configuration/includedConfig.xml&#8221;/&gt;</div>
<div>  &#8230;</div>
<div>&lt;/configuration&gt;     </div>
<div>被包含的文件必须用&lt;include&gt;标签包裹：</div>
<div>&lt;included&gt;</div>
<div>  &lt;appender name=&#8221;includedConsole&#8221; class=&#8221;ch.qos.logback.core.ConsoleAppender&#8221;&gt;</div>
<div>    &lt;encoder&gt;</div>
<div>      &lt;pattern&gt;&#8221;%d &#8211; %m%n&#8221;&lt;/pattern&gt;</div>
<div>    &lt;/encoder&gt;</div>
<div>  &lt;/appender&gt;</div>
<div>&lt;/included&gt;</div>
<div>还可以关联资源（例如classpath下的某个文件）：</div>
<div>     &lt;include resource=&#8221;includedConfig.xml&#8221;/&gt;</div>
<div>还可以关联URL：</div>
<div>     &lt;include url=&#8221;<a href="http://some.host.com/includedConfig.xml&#8221;/&#038;gt" rel="nofollow">http://some.host.com/includedConfig.xml&#8221;/&#038;gt</a>;</div>
<div>可以指定此次文件包含为“可选的”：</div>
<div>     &lt;include optional=&#8221;true&#8221; &#8230;./&gt;</div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>LoggerContextListener</div>
<div>其中一个实现LevelChangePropagator会监听日志环境的合适的生命周期，并把日志级别的变化传播给JUL，这样JUL关闭的日志不会再传递给slf4j，用这种方式对性能冲击较小，适合jul-to-slf4j的桥接包。</div>
<div> </div>
<div> </div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_03_configuration/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/5a39b92a93cdb32c75904702aef6c743964f034250355c6cf3c07790f896217b?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">watchzerg</media:title>
		</media:content>
	</item>
		<item>
		<title>logback_doc_manual_02_architecture</title>
		<link>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_02_architecture/</link>
					<comments>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_02_architecture/#comments</comments>
		
		<dc:creator><![CDATA[watchzerg]]></dc:creator>
		<pubDate>Sun, 13 Jul 2014 11:21:20 +0000</pubDate>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_02_architecture/</guid>

					<description><![CDATA[http://logback.qos.ch/manual/architecture.html   Logger [&#8230;]]]></description>
										<content:encoded><![CDATA[<div><a href="http://logback.qos.ch/manual/architecture.html">http://logback.qos.ch/manual/architecture.html</a></p>
<div> </div>
<div>Logger, Appender and Layout</div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>Logger:</div>
<div> </div>
<div>Logger继承关系：</div>
<div>com.foo是com.foo.Bar的双亲（parent），同时也是其祖先（ancestor）</div>
<div>java是java.util.Vector的祖先，但不是其双亲。</div>
<div> </div>
<div>root Logger是所有logger的祖先，可以这样获取：</div>
<div>Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);</div>
<div> </div>
<div>日志级别，在ch.qos.logback.classic.Level中，有TRACE, DEBUG, INFO, WARN and ERROR</div>
<div>日志级别类是final的，如果想扩展，可以用Marker类。</div>
<div> </div>
<div>如果一个logger没有指定级别，那么它继承最近的祖先的级别。</div>
<div>root Logger默认是debug级别。</div>
<div> </div>
<div>日志级别：TRACE &lt; DEBUG &lt; INFO &lt;  WARN &lt; ERROR.</div>
<div>如果日志记录请求——例如logger.info()——的级别大于等于其logger的级别，那么该请求生效。</div>
<div> </div>
<div>使用LoggerFactory.getLogger(String param)获取的logger，只要参数一致，那么获取到的logger也一致。</div>
<div>即使先创建子logger，再创建双亲logger，后者也会正确的插到logger树上。</div>
<div> </div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>Appenders and Layouts:</div>
<div>     一个logger可以绑定多个appender。</div>
<div>     默认情况：每一个日志请求，会被发送到logger对应的所有Appender，以及更高层logger对应的所有appender上。</div>
<div>     如果把某个logger的additivity标志设为false，那么这个logger会记录自身和下层（孙子logger）的日志，但不会再向上传递——也就是把下层的logger的日志拦截到了当前这一层logger为止了。</div>
<div> </div>
<div>     PatternLayout控制输出的格式，类似C语言的printf格式。</div>
<div>     </div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>参数化记录日志：</div>
<div>     与slf4j完全相同</div>
<div> </div>
<div>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</div>
<div>日志记录的调用时序图：</div>
<div><a href="https://watchzerg.wordpress.com/wp-content/uploads/2014/07/logback-1-1.png"><img data-attachment-id="262" data-permalink="https://watchzerg.wordpress.com/logback-1-1/" data-orig-file="https://watchzerg.wordpress.com/wp-content/uploads/2014/07/logback-1-1.png" data-orig-size="1351,423" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}" data-image-title="logback-1-1" data-image-description="" data-image-caption="" data-medium-file="https://watchzerg.wordpress.com/wp-content/uploads/2014/07/logback-1-1.png?w=300" data-large-file="https://watchzerg.wordpress.com/wp-content/uploads/2014/07/logback-1-1.png?w=720" class="alignnone size-medium wp-image-262" src="https://watchzerg.wordpress.com/wp-content/uploads/2014/07/logback-1-1.png?w=300&#038;h=93" alt="logback-1-1" width="300" height="93" srcset="https://watchzerg.wordpress.com/wp-content/uploads/2014/07/logback-1-1.png?w=300 300w, https://watchzerg.wordpress.com/wp-content/uploads/2014/07/logback-1-1.png?w=600 600w, https://watchzerg.wordpress.com/wp-content/uploads/2014/07/logback-1-1.png?w=150 150w" sizes="(max-width: 300px) 100vw, 300px" /></a></div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://watchzerg.wordpress.com/2014/07/13/logback_doc_manual_02_architecture/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/5a39b92a93cdb32c75904702aef6c743964f034250355c6cf3c07790f896217b?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">watchzerg</media:title>
		</media:content>

		<media:content url="https://watchzerg.wordpress.com/wp-content/uploads/2014/07/logback-1-1.png?w=300" medium="image">
			<media:title type="html">logback-1-1</media:title>
		</media:content>
	</item>
	</channel>
</rss>
