作者 | 王海林,Apache PPMC
01
背景
02
目标
03
整体设计
01
解决连接器之间的日志冲突
02
解决执行引擎之间的日志冲突
seatunnel-core/**-starter
,这里是解决不同引擎日志框架差异的最佳位置。我们根据不同执行引擎的自身内置的日志框架不同 ,提供不同的日志桥接包在提交任务时跟随 Connector 一起提交到引擎中去,使得 Connector 及其依赖包中使用其他日志框架输出的日志全部通过桥接包转接到 slf4j-api 上,之后就由每个引擎内置的日志框架承接 slf4j-api 去做日志输出。03
Maven管理日志依赖
pom.xml
中定义所有日志相关包的缺省 Scope,对所有继承的子模块生效。pom.xml
中定义 maven-shade-plugin
规则,在 Starter、Connector 等模块打包阶段 exclude 日志相关 jar 包,当然子模块可以更新需求重新定义(例如 Starter 根据引擎决定 include 的桥接包)。pom.xml
中定义 maven-surefire-plugin
规则,在 mvn test 单元测试阶段 exclude 日志相关 jar 包。04
SeaTunnel Zeta日志增强
ChildFirstClassLoader
,还需要更改此类加载规则使日志相关的包优先从 Parent ClassLoader
加载,以保证每次提交任务运行时 Connector 代码中的日志正确的链接到 SeaTunnel-Zeta 配置的日志输出中。pattern
即可在每一行日志都带上任务相关信息:[%X{ZT-JID, ZT-TID, ZT-PID}] [%p] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c:%L - %m%n
04
实施方法
01
pom.xml
定义 dependencyManagement & dependencies,被所有子模块继承此 Maven Scope 设置<dependencyManagement>
<!-- ***************** slf4j & provider & bridges start ***************** -->
<!-- Declare slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- Declare slf4j-api provider: log4j2.x -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j2.version}</version>
</dependency>
<!-- Declare log4j2 asynchronous loggers provider: disruptor -->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>${log4j2-disruptor.version}</version>
</dependency>
<!-- Include the logging bridges -->
<!-- commons-logging bridge to slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- jdk-logging bridge to slf4j -->
<!-- low performance, see: https://www.slf4j.org/legacy.html#jul-to-slf4j
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
-->
<!-- log4j1.x bridge to log4j2.x -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId>
<version>${log4j2.version}</version>
</dependency>
<!-- Exclude the logging bridges via provided scope -->
<!-- log4j1.x bridge to slf4j
Use of the SLF4J adapter (log4j-over-slf4j) together with the SLF4J bridge (slf4j-log4j12) should never be attempted as it will cause events to endlessly be routed between SLF4J and Log4j 1
-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>${slf4j.version}</version>
<scope>provided</scope>
</dependency>
<!-- slf4j binding to log4j1.x -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
<scope>provided</scope>
</dependency>
<!-- log4j2.x binding to slf4j.
Use of the SLF4J adapter (log4j-to-slf4j-2.x.jar) together with the SLF4J bridge (log4j-slf4j-impl-2.x.jar) should never be attempted as it will cause events to endlessly be routed between SLF4J and Log4j 2
-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>${log4j2.version}</version>
<scope>provided</scope>
</dependency>
<!-- slf4j binding to jdk-logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>${slf4j.version}</version>
<scope>provided</scope>
</dependency>
<!-- slf4j binding to commons-logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jcl</artifactId>
<version>${slf4j.version}</version>
<scope>provided</scope>
</dependency>
<!-- slf4j binding to nop -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>${slf4j.version}</version>
<scope>provided</scope>
</dependency>
<!-- slf4j binding to simple -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
<scope>provided</scope>
</dependency>
<!-- Exclude other logging provider via provided scope -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>${commons-logging.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
<scope>provided</scope>
</dependency>
<!-- ***************** slf4j & provider & bridges end ***************** -->
</dependencyManagement>
<dependencies>
<!-- ***************** slf4j & provider & bridges start ***************** -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId>
</dependency>
<!-- ***************** slf4j & provider & bridges end ***************** -->
</dependencies>
02
pom.xml
定义 maven-shade-plugin 规则,所有子模块做 shade 包时继承使用<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>${maven-shade-plugin.version}</version>
<configuration>
<artifactSet>
<excludes>
<exclude>org.slf4j:*</exclude>
<exclude>ch.qos.logback:*</exclude>
<exclude>log4j:*</exclude>
<exclude>org.apache.logging.log4j:*</exclude>
<exclude>commons-logging:*</exclude>
</excludes>
</artifactSet>
</configuration>
</plugin>
03
pom.xml
定义 maven-surefire-plugin 规则用于各个模块单元测试使用<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<classpathDependencyExcludes>
<!--
The logger provider & bridges declared under 'provided' scope should be explicitly excluded from testing as below.
-->
<classpathDependencyExclude>org.slf4j:slf4j-jdk14</classpathDependencyExclude>
<classpathDependencyExclude>org.slf4j:slf4j-jcl</classpathDependencyExclude>
<classpathDependencyExclude>org.slf4j:slf4j-nop</classpathDependencyExclude>
<classpathDependencyExclude>org.slf4j:slf4j-simple</classpathDependencyExclude>
<classpathDependencyExclude>org.slf4j:slf4j-reload4j</classpathDependencyExclude>
<classpathDependencyExclude>org.slf4j:slf4j-log4j12</classpathDependencyExclude>
<classpathDependencyExclude>org.slf4j:log4j-over-slf4j</classpathDependencyExclude>
<classpathDependencyExclude>commons-logging:commons-logging</classpathDependencyExclude>
<classpathDependencyExclude>log4j:log4j</classpathDependencyExclude>
<classpathDependencyExclude>ch.qos.logback:logback-classic</classpathDependencyExclude>
<classpathDependencyExclude>ch.qos.logback:logback-core</classpathDependencyExclude>
<classpathDependencyExclude>org.apache.logging.log4j:log4j-to-slf4j</classpathDependencyExclude>
</classpathDependencyExcludes>
</configuration>
</plugin>
04
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<configuration>
<artifactSet>
<excludes>
<!--
Spark(2.x) server lib already include:
slf4j-api
log4j
slf4j-log4j12
jul-to-slf4j
jcl-over-slf4j
Spark(3.x) server lib already include:
slf4j-api
log4j-api
log4j-core
log4j-slf4j-impl
log4j-1.2-api
jul-to-slf4j
jcl-over-slf4j
-->
<exclude>org.slf4j:slf4j-api</exclude>
<exclude>org.slf4j:slf4j-jdk14</exclude>
<exclude>org.slf4j:slf4j-jcl</exclude>
<exclude>org.slf4j:slf4j-nop</exclude>
<exclude>org.slf4j:slf4j-simple</exclude>
<exclude>org.slf4j:slf4j-reload4j</exclude>
<exclude>org.slf4j:slf4j-log4j12</exclude>
<exclude>org.slf4j:jcl-over-slf4j</exclude>
<exclude>org.slf4j:jul-to-slf4j</exclude>
<!-- spark2.x use slf4j + log4j1.x -->
<exclude>org.slf4j:log4j-over-slf4j</exclude>
<exclude>log4j:*</exclude>
<exclude>commons-logging:*</exclude>
<exclude>ch.qos.logback:*</exclude>
<exclude>org.apache.logging.log4j:log4j-api</exclude>
<exclude>org.apache.logging.log4j:log4j-core</exclude>
<exclude>org.apache.logging.log4j:log4j-slf4j-impl</exclude>
<!-- spark3.x use slf4j + log4j2.x -->
<exclude>org.apache.logging.log4j:log4j-to-slf4j</exclude>
</excludes>
</artifactSet>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<configuration>
<artifactSet>
<excludes>
<!--
not excluded:
jcl-over-slf4j(commons-logging to slf4j bridge)
Flink server lib already include:
slf4j-api
log4j-api
log4j-core
log4j-slf4j-impl
log4j-1.2-api
-->
<exclude>org.slf4j:slf4j-api</exclude>
<exclude>org.slf4j:slf4j-jdk14</exclude>
<exclude>org.slf4j:slf4j-jcl</exclude>
<exclude>org.slf4j:slf4j-nop</exclude>
<exclude>org.slf4j:slf4j-simple</exclude>
<exclude>org.slf4j:slf4j-reload4j</exclude>
<exclude>org.slf4j:slf4j-log4j12</exclude>
<exclude>org.slf4j:log4j-over-slf4j</exclude>
<exclude>log4j:*</exclude>
<exclude>commons-logging:*</exclude>
<exclude>ch.qos.logback:*</exclude>
<exclude>org.apache.logging.log4j:log4j-api</exclude>
<exclude>org.apache.logging.log4j:log4j-core</exclude>
<exclude>org.apache.logging.log4j:log4j-slf4j-impl</exclude>
<exclude>org.apache.logging.log4j:log4j-1.2-api</exclude>
<exclude>org.apache.logging.log4j:log4j-to-slf4j</exclude>
</excludes>
</artifactSet>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<configuration>
<artifactSet>
<excludes>
<!--
not excluded:
slf4j-api
log4j2-api
log4j2-core
log4j-slf4j-impl
log4j-1.2-api(log4j1.x to log4j2.x bridge)
jcl-over-slf4j(commons-logging to slf4j bridge)
-->
<exclude>org.slf4j:slf4j-jdk14</exclude>
<exclude>org.slf4j:slf4j-jcl</exclude>
<exclude>org.slf4j:slf4j-nop</exclude>
<exclude>org.slf4j:slf4j-simple</exclude>
<exclude>org.slf4j:slf4j-reload4j</exclude>
<exclude>org.slf4j:slf4j-log4j12</exclude>
<exclude>org.slf4j:log4j-over-slf4j</exclude>
<exclude>log4j:*</exclude>
<exclude>commons-logging:*</exclude>
<exclude>ch.qos.logback:*</exclude>
<exclude>org.apache.logging.log4j:log4j-to-slf4j</exclude>
</excludes>
</artifactSet>
</configuration>
</plugin>
05
完整的功能issue&PR
06
参考