2013-05-30 41 views
11

我需要爲動態加載和重新加載的類動態創建Logback記錄器和各種位。我有這些類的可變數量,儘管它會少於150個。性能是一個值得關注的問題,這是一個高度線程化並且非常併發的環境,所以使用MDC的想法不會因爲每當出現問題時每秒可能有數千次調用而發生變化。我也不想直接將記錄器傳遞到類中,我想讓他們像使用getLogger一樣將它們拖出空中。動態創建Logback Logger和Appender

每個類都必須將它所有的錯誤消息記錄到它自己的錯誤文件,並將它的所有跟蹤消息記錄到它自己的跟蹤文件中。這兩個文件都需要每晚滾動。此外,系統中登錄的任何內容都必須以主系統日誌結束。

我創建了下面的代碼片段來嘗試這個想法。它似乎有效,但結果並非我所期望的。這裏是一個可以直接運行測試程序:

package logbacktesting; 

import ch.qos.logback.classic.Level; 
import ch.qos.logback.classic.Logger; 
import ch.qos.logback.classic.LoggerContext; 
import ch.qos.logback.classic.encoder.PatternLayoutEncoder; 
import ch.qos.logback.classic.filter.LevelFilter; 
import ch.qos.logback.core.rolling.RollingFileAppender; 
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy; 
import ch.qos.logback.core.spi.FilterReply; 
import ch.qos.logback.core.util.StatusPrinter; 
import org.slf4j.LoggerFactory; 

public class Main { 

    public static void main(String[] args) { 

     Logger templateLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.myapp"); 
     LoggerContext loggerContext = templateLogger.getLoggerContext(); 

     String[] nameList = new String[] {"test1.class", "test2.class"}; 

     // Set up the pattern 
     PatternLayoutEncoder encoder = new PatternLayoutEncoder(); 
     encoder.setContext(loggerContext); 
     encoder.setPattern("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"); 
     encoder.start(); 

     // Spin over the names to create all the needed objects 
     for(int i = 0; i < nameList.length; i++) { 

      String name = nameList[i]; 

      // Set up the roll over policies and the name when it rolls over 
      TimeBasedRollingPolicy tracePolicy = new TimeBasedRollingPolicy(); 
      tracePolicy.setContext(loggerContext); 
      tracePolicy.setFileNamePattern(name + "-Trace-%d{yyyy-MM-dd}.log"); 
      tracePolicy.setMaxHistory(30); 

      TimeBasedRollingPolicy errorPolicy = new TimeBasedRollingPolicy(); 
      errorPolicy.setContext(loggerContext); 
      errorPolicy.setFileNamePattern(name + "-Error-logFile.%d{yyyy-MM-dd}.log"); 
      errorPolicy.setMaxHistory(30); 

      // Set up the filters to ensure things get split as expected 
      LevelFilter traceFilter = new LevelFilter(); 
      traceFilter.setContext(loggerContext); 
      traceFilter.setLevel(Level.TRACE); 
      traceFilter.setOnMatch(FilterReply.ACCEPT); 
      traceFilter.setOnMismatch(FilterReply.DENY); 

      LevelFilter errorFilter = new LevelFilter(); 
      errorFilter.setContext(loggerContext); 
      errorFilter.setLevel(Level.ERROR); 
      errorFilter.setOnMatch(FilterReply.ACCEPT); 
      errorFilter.setOnMismatch(FilterReply.DENY); 

      // Set up the trace and error appenders 
      RollingFileAppender rollingFileAppenderTrace = new RollingFileAppender(); 
      rollingFileAppenderTrace.setContext(loggerContext); 
      rollingFileAppenderTrace.setName(name + "-Trace"); 
      rollingFileAppenderTrace.setFile(name + "-Trace.log"); 
      rollingFileAppenderTrace.setEncoder(encoder); 
      rollingFileAppenderTrace.setRollingPolicy(tracePolicy); 
      rollingFileAppenderTrace.addFilter(traceFilter); 
      tracePolicy.setParent(rollingFileAppenderTrace); 

      RollingFileAppender rollingFileAppenderError = new RollingFileAppender(); 
      rollingFileAppenderError.setContext(loggerContext); 
      rollingFileAppenderError.setName(name + "-Error"); 
      rollingFileAppenderError.setFile(name + "-Error.log"); 
      rollingFileAppenderError.setEncoder(encoder); 
      rollingFileAppenderError.setRollingPolicy(errorPolicy); 
      rollingFileAppenderError.addFilter(errorFilter); 
      errorPolicy.setParent(rollingFileAppenderError); 

      // Start everything 
      tracePolicy.start(); 
      errorPolicy.start(); 
      traceFilter.start(); 
      errorFilter.start(); 
      rollingFileAppenderTrace.start(); 
      rollingFileAppenderError.start(); 

      // attach the rolling file appenders to the logger 
      Logger logger = (ch.qos.logback.classic.Logger) loggerContext.getLogger(name); 
      logger.addAppender(rollingFileAppenderTrace); 
      logger.addAppender(rollingFileAppenderError); 

     } 

     StatusPrinter.print(loggerContext); 

     // Test it to see what happens 
     for(int i = 0; i < nameList.length; i++) { 

      String name = nameList[i]; 

      Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(name); 
      logger.error("error message"); 
      logger.warn("warn message"); 
      logger.info("info message"); 
      logger.debug("debug message"); 
      logger.trace("trace message"); 
     } 

     Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.myapp"); 
     logger.error("generic error message "); 


    } 

} 

這裏是logback.xml文件:

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> 
     <encoder> 
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> 
     </encoder> 
    </appender> 

    <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> 

    <root level="debug"> 
     <appender-ref ref="STDOUT" /> 
     <appender-ref ref="FILE" /> 
    </root> 

</configuration> 

如果你運行該代碼,它將正確登錄到一切主要日誌文件。它會按預期創建2個跟蹤和2個錯誤日誌。但是跟蹤消息中沒有一個最終會出現在跟蹤日誌文件中,並且這兩個錯誤消息都將在class2錯誤文件中結束。它的行爲就像所有4個appender被添加到相同的記錄器,只有最後一個appender被添加實際工作。我很想知道我在這裏做什麼。謝謝!

+0

哪個版本logback是什麼? – fge

+2

看起來不錯。從粗略看,我能看到的唯一問題是你不應該共享編碼器。您必須爲每個File/RollingFileAppender創建一個新的。 – Ceki

+0

啊,很好。這絕對是造成問題的原因。另一個問題是調試的根級應該已經跟蹤了!非常感謝! –

回答

2

上面的代碼有幾個問題。首先是Ceki所說的:你不能共享編碼器。在循環中創建兩個編碼器可以改變正確方向的行爲。第二個問題是在XML文件中,根級別應該是跟蹤的,而不是調試。編碼器更換後顯然很明顯。