복붙노트

[SPRING] Log4J - SiftingAppender와 유사한 기능

SPRING

Log4J - SiftingAppender와 유사한 기능

저는 Log4J를 사용하는 프로젝트에서 일합니다. 요구 사항 중 하나는 각 스레드에 대해 별도의 로그 파일을 만드는 것입니다. 이 자체는 이상한 문제였습니다. 즉, 새로운 FileAppender를 즉시 작성하여 Logger 인스턴스에 첨부하여 정렬했습니다.

Logger logger = Logger.getLogger(<thread dependent string>);
FileAppender appender = new FileAppender();
appender.setFile(fileName);
appender.setLayout(new PatternLayout(lp.getPattern()));
appender.setName(<thread dependent string>);
appender.setThreshold(Level.DEBUG);
appender.activateOptions();
logger.addAppender(appender);

Spring Framework v3.0.0 (Commons Logging을 사용하는)은 위의 기술로 공을 사용하지 않습니다. Spring 로깅 데이터는 log4.configuration에 의해 초기화 된 Appenders에 의해서만 "인식"됩니다. 파일을 만들었지 만 Appenders가 만든 런타임이 아닙니다. 다시 정사각형으로 돌아갑니다.

약간의 조사가 끝나자 새롭고 향상된 LogBack에 알맞은 기능인 SiftingAppender (독립 파일에 대한 스레드 수준 로깅)가 필요하다는 사실을 알게되었습니다.

LogBack으로 이동하는 것은 옵션이 아니므로 Log4J에 머물러있어 SiftingAppender와 같은 기능을 어떻게 구현하고 Spring을 행복하게 유지할 수 있습니까?

주 : Spring은 JdbcTemplate 기능에만 사용되며 IOC는 사용하지 않습니다. Spring의 Commons Logging을 Log4J에 "연결"하기 위해 log4j.properties 파일에 다음 줄을 추가했다 :

여기에 지시 된대로.

해결법

  1. ==============================

    1.LogBack은 slf4j API를 통해 액세스됩니다. 커먼즈 로깅 인터페이스를 노출하지만, 구현에 직접가는 slf4j API에 대한 모든 로깅을 작성하는 jcl-over-sjf4j라는 어댑터 라이브러리가 있습니다 (LogBack). 당신이 maven을 사용한다면, 다음과 같은 의존 관계가 있습니다 :

    LogBack은 slf4j API를 통해 액세스됩니다. 커먼즈 로깅 인터페이스를 노출하지만, 구현에 직접가는 slf4j API에 대한 모든 로깅을 작성하는 jcl-over-sjf4j라는 어댑터 라이브러리가 있습니다 (LogBack). 당신이 maven을 사용한다면, 다음과 같은 의존 관계가 있습니다 :

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.5.8</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>1.5.8</version>
    </dependency> 
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>0.9.18</version>
    </dependency>
    

    (그리고 제외 목록에 commons-logging을 추가하십시오, 여기를보십시오)

  2. ==============================

    2.log4j에서 SiftingAppender와 비슷한 기능을 찾기 위해 얼마 동안 노력했지만 (일부 종속성으로 인해 logback으로 전환 할 수 없음), MDC를 사용하고 런타임에 로거를 추가하는 프로그래밍 방식의 솔루션으로 끝났습니다.

    log4j에서 SiftingAppender와 비슷한 기능을 찾기 위해 얼마 동안 노력했지만 (일부 종속성으로 인해 logback으로 전환 할 수 없음), MDC를 사용하고 런타임에 로거를 추가하는 프로그래밍 방식의 솔루션으로 끝났습니다.

    //  this can be any thread-specific string
    String processID = request.getProcessID();  
    
    Logger logger = Logger.getRootLogger();
    
    //  append a new file logger if no logger exists for this tag
    if(logger.getAppender(processID) == null){
    
      try{
        String pattern = "%d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n";
        String logfile = "log/"+processID+".log";
    
        FileAppender fileAppender = new FileAppender(
            new PatternLayout(pattern), logfile, true);
        fileAppender.setName(processID);
    
        // add a filter so we can ignore any logs from other threads
        fileAppender.addFilter(new ProcessIDFilter(processID));
    
        logger.addAppender(fileAppender);
      }catch(Exception e){
        throw new RuntimeException(e);
      }
    }
    
    //  tag all child threads with this process-id so we can separate out log output
    MDC.put("process-id", processID);
    
    //whatever you want to do in the thread
    LOG.info("This message will only end up in "+processID+".log!");
    
    MDC.remove("process-id");
    

    위에 추가 된 필터는 특정 프로세스 ID를 확인합니다.

    public class RunIdFilter extends Filter {
    
      private final String runId;
    
      public RunIdFilter(String runId) {
        this.runId = runId;
      }
    
      @Override
      public int decide(LoggingEvent event) {
        Object mdc = event.getMDC("run-id");
    
        if (runId.equals(mdc)) {
          return Filter.ACCEPT;
        }
    
        return Filter.DENY;
      }
    }
    

    희망이 조금 도움이됩니다.

  3. ==============================

    3.Log4j2에서는 이제 RoutingAppender를 사용할 수 있습니다.

    Log4j2에서는 이제 RoutingAppender를 사용할 수 있습니다.

    그들의 FAQ에서 :

  4. ==============================

    4.나는 모든 slf4j facades / re-routers / whateveryoucall을 포함하고 싶습니다. 또한 "제공되는"해킹은 커먼즈 로깅에서 종속성을 유지하지 못하게합니다. 이전에 필자는 버전 99.0이라는 가짜 빈 커먼즈 로깅 라이브러리를 사용하고있었습니다.

    나는 모든 slf4j facades / re-routers / whateveryoucall을 포함하고 싶습니다. 또한 "제공되는"해킹은 커먼즈 로깅에서 종속성을 유지하지 못하게합니다. 이전에 필자는 버전 99.0이라는 가짜 빈 커먼즈 로깅 라이브러리를 사용하고있었습니다.

    http://blog.springsource.com/2009/12/04/logging-dependencies-in-spring/을 참조하십시오.

    <dependencies>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
    
            <!-- use provided scope on real JCL instead -->
            <!-- <version>99.0-does-not-exist</version> -->
    
            <version>1.1.1</version>
    
            <scope>provided</scope>
        </dependency>
    
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging-api</artifactId>
    
            <!-- use provided scope on real JCL instead -->
            <!-- <version>99.0-does-not-exist</version> -->
    
            <version>1.1</version>
    
            <scope>provided</scope>
        </dependency>
    
        <!-- the slf4j commons-logging replacement -->
        <!-- if any package is using jakarta commons logging this will -->
        <!-- re-route it through slf4j. -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
    
            <version>${version.slf4j}</version>
        </dependency>
    
        <!-- the slf4j log4j replacement. -->
        <!-- if any package is using log4j this will re-route -->
        <!-- it through slf4j. -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>log4j-over-slf4j</artifactId>
    
            <version>${version.slf4j}</version>
        </dependency>
    
        <!-- the slf4j java.util.logging replacement. -->
        <!-- if any package is using java.util.logging this will re-route -->
        <!-- it through slf4j. -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jul-to-slf4j</artifactId>
            <version>${version.slf4j}</version>
        </dependency>
    
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
    
            <version>${version.slf4j}</version>
        </dependency>
    
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
    
            <version>${version.logback}</version>
        </dependency>
    </dependencies>
    
    <properties>
        <version.logback>0.9.15</version.logback>
        <version.slf4j>1.5.8</version.slf4j>
    </properties>
    
  5. ==============================

    5.log4j.NDC와 MDC를 보셨습니까? 적어도 로깅에 스레드 특정 데이터를 태그 할 수 있습니다. 정확하게 당신이 요구하는 것은 아니지만 유용 할 수 있습니다. 여기에 토론이 있습니다.

    log4j.NDC와 MDC를 보셨습니까? 적어도 로깅에 스레드 특정 데이터를 태그 할 수 있습니다. 정확하게 당신이 요구하는 것은 아니지만 유용 할 수 있습니다. 여기에 토론이 있습니다.

  6. from https://stackoverflow.com/questions/1929609/log4j-siftingappender-like-functionality by cc-by-sa and MIT license