Flink 默認日志框架
從 flink 官網(wǎng) 直接下載二進制 Flink tar 包煌张,解壓縮之后膘盖,查看 conf 目錄和 lib 目錄結構。
conf 目錄結構如下:
-rwxr-xr-x@ 1 zhangguanghui staff 2138 12 11 20:39 log4j-cli.properties
-rwxr-xr-x@ 1 zhangguanghui staff 1884 12 11 20:39 log4j-console.properties
-rwxr-xr-x@ 1 zhangguanghui staff 1709 12 11 20:39 log4j-yarn-session.properties
-rwxr-xr-x@ 1 zhangguanghui staff 1939 12 11 20:39 log4j.properties
-rwxr-xr-x@ 1 zhangguanghui staff 2294 12 11 20:39 logback-console.xml
-rwxr-xr-x@ 1 zhangguanghui staff 1550 12 11 20:39 logback-yarn.xml
-rwxr-xr-x@ 1 zhangguanghui staff 2331 12 11 20:39 logback.xml
lib 目錄結構如下:
-rwxr-xr-x@ 1 zhangguanghui staff 93195847 12 15 11:31 flink-dist_2.11-1.7.1.jar
-rwxr-xr-x@ 1 zhangguanghui staff 141914 12 15 11:28 flink-python_2.11-1.7.1.jar
-rwxr-xr-x@ 1 zhangguanghui staff 36059569 12 15 10:58 flink-shaded-hadoop2-uber-1.7.1.jar
-rwxr-xr-x@ 1 zhangguanghui staff 489884 3 1 2018 log4j-1.2.17.jar
-rwxr-xr-x@ 1 zhangguanghui staff 9931 12 13 18:17 slf4j-log4j12-1.7.15.jar
從 conf 中可以看出妇斤,flink 提供了兩種日志框架配置文件茎截,分別是 logback 和 log4j;但是通過 lib 下面的 log4j + slf4j-log4j12 可以看出油狂,flink 默認提供的是 sfl4j + slf4j-log4j12 + log4j 日志框架組合历恐。
slf4j 基礎概念
slf4j 默認提供一組易用的打日志 API,用戶可以通過 slf4j 和 slf4j 橋接器將日志傳遞給具體日志框架专筷,例如 logback, log4j, log4j2弱贼,以下就是多種 slf4j 橋接器。
那么問題就來了磷蛹,如果 JVM classpath 中包含多個橋接器和日志框架的話吮旅,slf4j 該如何選擇?
slf4j 如何選擇橋接器
要想知道 slf4j 選擇了哪個橋接器味咳,第一是要找到 slf4j 的橋接日志庇勃。如果是 flink on yarn 的話,橋接器日志在 taskmanager.err 日志中槽驶。
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/data00/yarn/nmdata/usercache/tiger/appcache/application_1546484418433_5098/filecache/12/device_report_flink-1.0.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/data08/yarn/nmdata/filecache/125/lib/slf4j-log4j12-1.7.7.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/data00/tiger/yarn_deploy/hadoop-2.6.0-cdh5.4.4/share/hadoop/common/lib/slf4j-log4j12-1.7.5.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
從日志中责嚷,我們看到 slf4j 找到了多個橋接器實現(xiàn)類,但是最終選擇了 logback掂铐。一旦 slf4j 確認了橋接器之后罕拂,就會繼續(xù)尋找對應的配置文件來初始化 Logger 框架,即 logback.xml 或者 log4j.properties全陨。
如果 slf4j 選擇的是 logback爆班,而你沒有相應的 logback.xml 配置文件的話,則 logback 將采用默認方式辱姨,將日志輸出到 stdout柿菩。
如果 sfl4j 選擇的是 log4j.properites,而你沒有相應的 log4j.properties 而配置文件的話雨涛,則 log4j 將采用默認方式枢舶,將日志輸出到 stdout 中。
總結镜悉,一般出問題在兩點
- 用戶誤將 logback-classic + logback-core 打進 user jar 中祟辟,使得 flink slf4j 橋接到 logback,但是卻并為提供正確的 logback.xml侣肄。
-用戶自己代碼中的 resources 目錄中旧困,誤將 debug 的 log4j.properties 文件帶入,覆蓋了 conf 下面的 log4j.properties,導致 log4j 初始化不符合預期吼具。
如何徹底解決問題
假如我們使用 slf4j + slf4j-log4j12+log4j 作為 flink 的日志框架僚纷,配置文件采用 conf/log4j.properties。
則用戶 pom.xml 文件中的 maven shard plugin 應該如下配置
<!-- Change the value of <mainClass>...</mainClass> if your program entry point changes. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<executions>
<!-- Run shade goal on package phase -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes>
<exclude>org.slf4j:*</exclude>
<exclude>log4j:*</exclude>
<exclude>ch.qos.logback:*</exclude>
</excludes>
</artifactSet>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>log4j.properties</exclude>
</excludes>
</filter>
</filters>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.bytedance.data.StreamingJob</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
其中
<exclude>ch.qos.logback:*</exclude>
將用戶端 logback 對應 jar 包移除拗盒。
<exclude>log4j.properties</exclude>
將用戶端的 log4j.properties 移除