2014-12-03 1 views
5

우리는 우리 제품에 로그인하기 위해 log4j 1.2.x를 사용하며 가까운 장래에 log4j 2.x로 마이그레이션하려고합니다. 구현 한 기능 중 하나는 생성 된 모든 새로운 롤오버 로그 파일에 시스템 정보와 기타 중요한 매개 변수를 기록하는 것입니다. 우리의 log4j 1.2.x를 구현하는 방법은 우리의 log4j의 RollingFileAppender 클래스를 확장 한과 rollOver() 방법을 대체 한 것으로, 아래 우리는 우리가 log4j2로 마이그레이션 할로 이제 구현log4j2 RollingFileAppender를 사용자 정의하는 방법은 무엇입니까?

@Override 
public void rollOver() { 

    super.rollOver(); //We are not modifying it's default functionality but as soon as rollOver happens we apply our logic 

    // 
    // Logic to log required system properties and important parameters. 
    // 

} 

의 일부 조각입니다 동일한 기능을 달성하기위한 새로운 솔루션을 모색합니다. 그러나 log4j2의 소스 코드는 이전 소스 코드와 매우 다릅니다. RollingFileAppender 클래스는 RollingManagerhelper으로 이동되었으므로 rollover() 메서드를 포함하지 않으며 private으로 설정되었습니다.

완전한 새 패키지를 개발하고 log4j2에서 추상/도우미 클래스를 확장/구현하는 것은 가능한 해결책이지만 우리가 필요로하는 것보다 RollingFileAppender을 수정하지 않으면 많은 코딩/복사가 필요합니다. 작은 확장. 거기에 간단한 해결책이 있습니까?

UPDATE

나는 답변의 제안에 따라 사용자 정의 조회를 만든 다음 그것을 생성하는 방법이다;

@Plugin(name = "property", category = StrLookup.CATEGORY) 
public class CustomLookup extends AbstractLookup { 

private static AtomicLong aLong = new AtomicLong(0); 

@Override 
public String lookup(LogEvent event, String key) { 

    if (aLong.getAndIncrement() == 0) { 
     return "this was first call"; 
    } 
    if (key.equalsIgnoreCase("customKey")) { 
     return getCustomHeader(); 
    } else { 
     return "non existing key"; 
    } 
} 

private static String getCustomHeader() { 

    // Implementation of custom header 
    return "custom header string"; 

}} 

그러나 이것은 언급 한대로 작동하지 않았습니다. 이것은 항상 this was first call을 헤더에 인쇄합니다. 나는 또한 첫 번째 if 조건에 브레이크 포인트를 두어 보았습니다. 그리고 주목할 것은 한 번만 호출된다는 것입니다. 그래서 두려운 것은 log4j2가 xml config에서 속성을 초기화 할 때 customLookup 클래스가 시작시에만 초기화된다는 것입니다. 나는이 사용자 정의 룩업 클래스를 어떻게 구현할 수 있을지 모르겠다.

UPDATE 2

후 I로 다음과 약간 다른 방법을 시도 상기 구현;

private static AtomicLong aLong = new AtomicLong(0); 

@Override 
public String lookup(LogEvent event, String key) { 
    return getCustomHeader(key); 
} 

private static String getCustomHeader(final String key) { 

    if (aLong.getAndIncrement() == 0) { 
     return "this was first call"; 
    } 
    if (key.equalsIgnoreCase("customKey")) { 
     // Implementation for customKey 
     return "This is custom header"; 
    } else { 
     return "non existing key"; 
    } 
} 

그러나 이것은 같은 것입니다. log4j2는 xml 구성 파일에서 초기화하는 동안 헤더를 만든 다음 메모리의 헤더를 사용합니다. 오버라이드 된 lookup() 메서드의 return 값은 초기화하는 동안에 만 호출되므로 동적으로 변경할 수 없습니다. 더 이상의 도움을 주시면 감사하겠습니다.

+0

런타임 변수 대체를 사용하려면 log4j2 등록 정보 파일에서 변수 키를 지정할 때 double $$를 사용하십시오. – TrueCurry

답변

5

기본 제공 조회를 사용하는 대신 맞춤 검색을 만들 수 있습니다. 이 작업은 log4j2 플러그인을 사용하여 몇 줄의 코드로 수행 할 수 있습니다. 사용자 정의 조회는 각 롤오버에서 파일 헤더에 표시 할 정확한 값을 제공합니다.

package com.mycompany; 
import org.apache.logging.log4j.core.LogEvent; 
import org.apache.logging.log4j.core.config.plugins.Plugin; 
import org.apache.logging.log4j.core.lookup.AbstractLookup; 
import org.apache.logging.log4j.core.lookup.StrLookup; 

/** 
* Looks up keys from a class SomeClass which has access to all 
* information you want to provide in the log file header at rollover. 
*/ 
@Plugin(name = "setu", category = StrLookup.CATEGORY) 
public class SetuLookup extends AbstractLookup { 

    /** 
    * Looks up the value of the specified key by invoking a 
    * static method on SomeClass. 
    * 
    * @param event The current LogEvent (ignored by this StrLookup). 
    * @param key the key to be looked up, may be null 
    * @return The value of the specified key. 
    */ 
    @Override 
    public String lookup(final LogEvent event, final String key) { 
     return com.mycompany.SomeClass.getValue(key); 
    } 
} 

그런 다음 모든 롤오버에 출력이에 패턴 레이아웃의 헤더를 사용하여 구성 :

<RollingFile name="RollingFile" fileName="logs/app.log" 
      filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}.log.gz"> 

    <!-- use custom lookups to access arbitrary internal system info --> 
    <PatternLayout header="${setu:key1} ${setu:key2}"> 
    <Pattern>%d %m%n</Pattern> 
    </PatternLayout> 
    <Policies> 
    <TimeBasedTriggeringPolicy /> 
    </Policies> 
</RollingFile> 

log4j2

플러그인 코드는 다음과 같을 것 설명서에는 custom plugins 건물/배치에 대한 세부 정보가 있습니다. 간단한 요약 :

가장 쉬운 방법은 Maven을 사용하여 항아리를 만드는 것입니다. 이렇게하면 log4j2 주석 처리기가 jar 파일의 바이너리 색인 파일을 생성하여 log4j2에서 신속하게 플러그인을 찾을 수 있습니다.

대안은 log4j2.xml 구성의 packages 속성에 플러그인 클래스의 패키지 이름을 지정하는 것입니다 :

<Configuration status="warn" packages="com.mycompany"> 
    ... 

UPDATE : 당신 조회 구현에 당신이 필요한만큼 창조적 얻을 수 있습니다 . 예 :

package com.mycompany; 

public class SomeClass { 
    private static AtomicLong count = new AtomicLong(0); 

    public static String getValue(final String key) { 
     if (count.getAndIncrement() == 0) { // is this the first call? 
      return ""; // don't output a value at system startup 
     } 
     if ("FULL".equals(key)) { 
      // returns info to shown on rollover, nicely formatted 
      return fullyFormattedHeader(); 
     } 
     return singleValue(key); 
    } 
    .... 
} 
+0

물론'setu'와는 다른 플러그인 이름을 사용하십시오. :-) –

+0

는 유망 해 보인다. 그것을 시도해 줄 것이다 – Setu

+0

나는 그것을 시도했다. 그러나 두 가지 문제 중 하나는 헤더 속성의 키가 로깅되어야하는 것처럼 완전히 포맷되어야한다는 것이다. 헤더에 둘 이상의 키를 사용하는 경우 다른 행으로 구분할 수 없습니다. 두 번째로 큰 문제는 프로그램 실행 시작시가 아닌 새로운 롤오버 파일의 시작 부분에 시스템 속성을 인쇄해야한다는 것입니다. 헤더는 각 실행의 시작과 롤오버에서 단순히 의미가없는 롤오버에 기록됩니다. – Setu

2

구성을 통해 수행 할 수 있습니다. 패턴 레이아웃의 헤더를 사용하여 정보를 출력 할 수 있습니다. 이것은 모든 롤오버에 포함됩니다.

<RollingFile name="RollingFile" fileName="logs/app.log" 
      filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}.log.gz"> 

    <!-- use built-in lookups for system info or system properties --> 
    <PatternLayout header="${java:runtime} - ${java:vm} - ${java:os}"> 
    <Pattern>%d %m%n</Pattern> 
    </PatternLayout> 
    <Policies> 
    <TimeBasedTriggeringPolicy /> 
    </Policies> 
</RollingFile> 
+0

@Remko하지만 한 가지 질문에 답해 주셔서 감사합니다. 우리가 가지고있는 제품은 거대하고 우리는 런타임에 여러 시스템 속성을 설정했습니다. 기본적으로 서버에서 계속 실행되고 백엔드에서 웹 서비스, GUI 도구 및 DB와 상호 작용하는 엔진입니다. 이 접근법을 사용하여 헤더에 모든 속성 이름을 정확하게 써야합니다. 어떤 종류의 루프를 사용하여 헤더의 모든 시스템 속성을 포함하는 방법이 있습니까? – Setu

+0

헤더의 단일 시스템 속성을 구성하고 원하는 모든 다른 시스템 속성 값을 추가하여 프로그래밍 방식으로 해당 속성 값을 업데이트 할 수 있습니다. –

+0

제안 해 주셔서 감사합니다. 시도해보아야하지만, 코드에서 시스템 속성을 설정하면 시스템 속성에 추가해야합니다. 그것이 작동 할 것 같은 소리지만 나는 이것이 실제 해결책이 아닌 관리에 의한 해결 방법으로 간주 될 것이라고 생각한다. 어쨌든 당신의 제안에 감사드립니다. – Setu