program tip

7 월-SLF4J 브리지

radiobox 2020. 11. 27. 07:57
반응형

7 월-SLF4J 브리지


현재 타사 라이브러리 (즉 restfb)가 java.util.logging을 사용하고 있으며 logback.xml에 SLF4J 콘솔 어 펜더가 구성되어 있지 않더라도 해당 로그가 STDOUT으로 끝나는 것을 확인하고 있습니다. 또한 클래스 경로에 jul-to-slf4j 브리지가 있습니다. jul-to-slf4j 브릿지는 브릿지가 설치 될 때 logback에 의해 구성된 어 펜더에만 로깅합니까 아니면 stdout에도 로깅합니까?


으로 전화해야합니다 SLF4JBridgeHandler.install(). 또한 java.util.logging의 루트 로거 (아래에서 발췌 한 이유)에서 모든 로그 수준을 활성화하고 기본 콘솔 어 펜더를 제거해야합니다.

이 핸들러는 jul 로깅을 SLF4J로 리디렉션합니다. 그러나 jul에서 활성화 된 로그 만 리디렉션됩니다. 예를 들어, jul 로거를 호출하는 로그 문이 해당 문을 비활성화하면 정의에 따라 SLF4JBridgeHandler 인스턴스에 도달하지 않고 리디렉션 할 수 없습니다.

전체 과정은 이렇게 완료 될 수 있습니다

import java.util.logging.Logger;
import org.slf4j.bridge.SLF4JBridgeHandler;

SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
Logger.getLogger("").setLevel(Level.FINEST); // Root logger, for example.

성능상의 이유로 최고 수준보다 높은 수준으로 설정할 수 있지만 java.util.logging먼저 활성화하지 않고는 해당 로그를 켤 수 없습니다 (위에서 발췌 한 이유 때문에).


SLF4JBridgeHandler 에 대한 javadocs에서 언급했듯이 다음을 호출하여 프로그래밍 방식으로 SLF4JBridgeHandler를 설치합니다.

 // Optionally remove existing handlers attached to j.u.l root logger
 SLF4JBridgeHandler.removeHandlersForRootLogger();  // (since SLF4J 1.6.5)

 // add SLF4JBridgeHandler to j.u.l's root logger, should be done once during
 // the initialization phase of your application
 SLF4JBridgeHandler.install();

또는 logging.properties를 통해

 // register SLF4JBridgeHandler as handler for the j.u.l. root logger
 handlers = org.slf4j.bridge.SLF4JBridgeHandler

성능에 관해서는 jul-to-slf4j 브리지 섹션 에서이 문제에 대해 설명합니다. 본질적으로 이미 로그 백을 사용하고 있으므로 LevelChangePropagator를 활성화 하면 부하에 관계없이 좋은 성능을 얻을 수 있습니다.


SLF4J와 새로운 Postgres 드라이버 42.0.0을 사용합니다.

changelog 에 따르면 java.util.logging을 사용합니다.

드라이버 로그를 가지려면 충분합니다.

  1. jul-to-slf4j 브리지 추가 :

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jul-to-slf4j</artifactId>
        <version>${slf4j.version}</version>
        <scope>runtime</scope>
    </dependency>
    
  2. logback.xml (logback-test.xml)에 추가

    <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
        <resetJUL>true</resetJUL>
    </contextListener>
    
    <appender ...
    
    <logger name="org.postgresql" level="trace"/>`
    
  3. 코드에 추가

    static {
        SLF4JBridgeHandler.install();
    }
    

내 솔루션 :

SLF4JBridgeHandler.install();
java.util.logging.LogManager.getLogManager().getLogger("").setLevel( Level.INFO);

앱 라이브러리 또는 glassfish 라이브러리에 jul-to-slf4j를 배치하면 JUL을 SLF4J로 리디렉션합니다 (따라서 제 경우에는 LOG4J로).

그런 다음 Jersey의 경우 다음과 같이 할 수 있습니다.

<logger name="com.sun.jersey" additivity="false">
    <level value="WARN" />
    <appender-ref ref="JVM" />
    <appender-ref ref="CONSOLE" />
</logger>   

<logger name="com.sun.common.util.logging" additivity="false">
    <level value="ERROR" />
    <appender-ref ref="JVM" />
    <appender-ref ref="CONSOLE" />
</logger>

마지막 구성은 다른 로거에 의해 오염되지 않도록하는 것입니다.


logback.groovy 파일에 모든 것을 작성 하면되므로 (JUL 브리징의 상황을 고려할 때) 멋져 보이고 저에게 효과적입니다 .

  1. ( 당신이 사용하지 않는 경우 logback.groovy의 구성 또는 logback을 전혀 물론 당신이해야 할의, (일부 클래스로 로직 부분을 넣어 예를 들어 같은 class MyApp { static { /* log init code here */ } ... }) .)

  2. src / logback.groovy :

    import org.slf4j.bridge.SLF4JBridgeHandler
    import ch.qos.logback.classic.jul.LevelChangePropagator
    
    // for debug: just to see it in case something is logging/initialized before
    System.out.println( 'my myapp logback.groovy is loading' )
    
    // see also: http://logback.qos.ch/manual/configuration.html#LevelChangePropagator
    // performance speedup for redirected JUL loggers
    def lcp = new LevelChangePropagator()
    lcp.context = context
    lcp.resetJUL = true
    context.addListener(lcp)
    
    // needed only for the JUL bridge: http://stackoverflow.com/a/9117188/1915920
    java.util.logging.LogManager.getLogManager().reset()
    SLF4JBridgeHandler.removeHandlersForRootLogger()
    SLF4JBridgeHandler.install()
    java.util.logging.Logger.getLogger( "global" ).setLevel( java.util.logging.Level.FINEST )
    
    def logPattern = "%date |%.-1level| [%thread] %20.20logger{10}|  %msg%n"
    
    appender("STDOUT", ConsoleAppender) {
        encoder(PatternLayoutEncoder) {
            pattern = logPattern
        }
    }
    
    /*// outcommenting in dev will not create dummy empty file
    appender("ROLLING", RollingFileAppender) {  // prod
        encoder(PatternLayoutEncoder) {
            Pattern = "%date %.-1level [%thread] %20.20logger{10}  %msg%n"
        }
        rollingPolicy(TimeBasedRollingPolicy) {
            FileNamePattern = "${WEBAPP_DIR}/log/orgv-fst-gwt-%d{yyyy-MM-dd}.zip"
        }
    }
    */
    
    appender("FILE", FileAppender) {  // dev
    
        // log to myapp/tmp (independent of running in dev/prod or junit mode:
    
        //System.out.println( 'DEBUG: WEBAPP_DIR env prop:  "."='+new File('.').absolutePath+',  \${WEBAPP_DIR}=${WEBAPP_DIR},  env=' + System.getProperty( "WEBAPP_DIR" ))
        String webappDirName = "war"
        if ( new File( "./../"+webappDirName ).exists() )  // we are not running within a junit test
            file = "../tmp/myapp.log"
        else  // junit test
            file = "tmp/myapp-junit-tests.log"
    
        encoder(PatternLayoutEncoder) { pattern = logPattern }
    }
    
    // without JUL bridge:
    //root(WARN, ["STDOUT", "ROLLING"])  // prod
    //root(DEBUG, ["STDOUT", "FILE"])  // dev
    
    // with JUL bridge: (workaround: see links above)
    def rootLvl = WARN
    root(TRACE, [/*"STDOUT",*/ "FILE"])
    // I manually added all "root package dirs" I know my libs are based on to apply
    // the root level to the second "package dir level" at least
    // depending on your libs used you could remove entries, but I would recommend
    // to add common entries instead (feel free to edit this post if you like to
    // enhance it anywhere)
    logger( "antlr", rootLvl )
    logger( "de", rootLvl )
    logger( "ch", rootLvl )
    logger( "com", rootLvl )
    logger( "java", rootLvl )
    logger( "javassist", rootLvl )
    logger( "javax", rootLvl )
    logger( "junit", rootLvl )
    logger( "groovy", rootLvl )
    logger( "net", rootLvl )
    logger( "org", rootLvl )
    logger( "sun", rootLvl )
    
    
    // my logger setup
    
    logger( "myapp", DEBUG )
    
    
    //logger( "org.hibernate.SQL", DEBUG )  // debug: log SQL statements in DEBUG mode
    //logger( "org.hibernate.type", TRACE )  // debug: log JDBC parameters in TRACE mode
    logger( "org.hibernate.type.BasicTypeRegistry", WARN )  // uninteresting
    
    scan("30 seconds")  // reload/apply-on-change config every x sec
    

(예를 들어 SLF4JBridgeHandler 또는 webappDirName 에 관한 로그 디렉토리와 같이 여기에서 볼 수 있듯이 Java 코드 변수 / 함수로 반응 할 수 있으므로 저에게 사용하는 것이 좋습니다. )

(모든 것이 어떻게 설정 될 수 있는지 또는 응시하는 템플릿으로 더 좋은 인상을주기 때문에 파일을 완성 된 상태로 두십시오)

(may be relevant to somebody - my env: slf4j 1.7.5, logback 1.1.2, groovy 2.1.9)

참고URL : https://stackoverflow.com/questions/9117030/jul-to-slf4j-bridge

반응형