簡體   English   中英

7 月到 SLF4J 橋接器

[英]JUL to SLF4J Bridge

我目前正在觀察一個 3rd 方庫(即 restfb)正在使用 java.util.logging 並且我看到這些日志最終出現在 STDOUT 中,即使我沒有在我的 logback.xml 中配置 SLF4J 控制台附加程序。 我的類路徑中也有jul-to-slf4j橋。 jul-to-slf4j 網橋是否僅在安裝網橋時記錄到由 logback 配置的附加程序,還是也記錄到標准輸出?

您需要調用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橋接部分討論了這個問題。 本質上,由於您已經在使用 logback,因此無論負載如何,啟用LevelChangePropagator都應該產生良好的性能。

我使用 SLF4J 和新的 Postgres 驅動程序 42.0.0

根據更改日志它使用 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);

將 jul-to-slf4j 放在您的應用程序庫或 glassfish 庫上,這些將 JUL 重定向到 SLF4J(因此在我的情況下為 LOG4J)

那么對於澤西島,您可以執行以下操作:

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

最后一個配置是為了避免被其他記錄器污染

看起來不錯的解決方案(考慮到 JUL 橋接的情況)並且對我有用,因為我只需要在logback.groovy文件中寫入所有內容

  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

(推薦由我使用,因為您可以對 Java 代碼變量/函數做出反應,如您在此處看到的,例如SLF4JBridgeHandler或有關webappDirName的日志目錄)

(保持文件完整,因為它給人更好的印象如何設置一切或作為起始模板)

(可能與某人有關 - 我的 env: slf4j 1.7.5, logback 1.1.2, groovy 2.1.9

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM