随笔 - 22, 文章 - 0, 评论 - 1, 引用 - 0
数据加载中……

logback_doc_manual_04_appenders

http://logback.qos.ch/manual/appenders.html
Appender都集成ch.qos.logback.core.Appender接口。
每个Appender可以绑定若干个Filter。
每个Appender可以将任务代理给Layout或者Encoder。
每个Layout或者Encoder只能属于1个Appender。
Appener也可以不包含Layout或者encoder,例如SocketAppender,直接把Event序列化传输。
ch.qos.logback.core.AppenderBase这是一个抽象类,对Appender接口提供了骨架实现,线程安全。
ch.qos.logback.core.UnsynchronizedAppenderBase是对应的线程不安全的类,但是可以将线程安全性委托给下一层的类(例如OutputStream)
OutputStreamAppender是文件输出和控制台输出Appender的父类,类层次结构如下:


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


posted on 2014-07-13 18:57 王星游 阅读(1449) 评论(0)  编辑  收藏 所属分类: java


只有注册用户登录后才能发表评论。


网站导航: