diff --git a/docs/content/zh-cn/docs/contribution-guidelines/runtime/logj42.md b/docs/content/zh-cn/docs/contribution-guidelines/runtime/logj42.md index ac976abe7..01ede6181 100644 --- a/docs/content/zh-cn/docs/contribution-guidelines/runtime/logj42.md +++ b/docs/content/zh-cn/docs/contribution-guidelines/runtime/logj42.md @@ -48,9 +48,55 @@ weight: 1 根据上面判断通过 bundle 的方式配置在多模块里不可行,因为 ResourceBundleLookup 可能只存在于基座中,导致始终只能拿到基座的 application.properties,导致模块的日志配置路径与基座相同,模块日志都打到基座中。所以需要改造成使用 ContextMapLookup。 +## static final修饰的Logger导致三方组件下沉基座后日志打印不能正常隔离 +如: +```java +private static final Logger LOG = LoggerFactory.getLogger(CacheManager.class); +``` +1. static final修饰的变量只会在类加载的时候初始化话一次 +2. 组件依赖下沉基座后,类加载器使用的为基座的类加载器,初始化log实例时使用的是基座的log配置,所以会打印到基座文件中,不能正常隔离 + +具体获取log源码如下: +```java +//org.apache.logging.log4j.spi.AbstractLoggerAdapter +@Override +public L getLogger(final String name) { + //关键是LoggerContext获取是否正确,往下追 + final LoggerContext context = getContext(); + final ConcurrentMap loggers = getLoggersInContext(context); + final L logger = loggers.get(name); + if (logger != null) { + return logger; + } + loggers.putIfAbsent(name, newLogger(name, context)); + return loggers.get(name); +} + +//获取LoggerContext +protected LoggerContext getContext() { + Class anchor = LogManager.getFactory().isClassLoaderDependent() ? StackLocatorUtil.getCallerClass(Log4jLoggerFactory.class, CALLER_PREDICATE) : null; + LOGGER.trace("Log4jLoggerFactory.getContext() found anchor {}", anchor); + return anchor == null ? LogManager.getContext(false) : this.getContext(anchor); +} + +//获取LoggerContext,关键在这里 +protected LoggerContext getContext(final Class callerClass) { + ClassLoader cl = null; + if (callerClass != null) { + //会优先使用当前类相关的类加载器,这里肯定是基座的类加载,所以返回的是基座的LoggerContext + cl = callerClass.getClassLoader(); + } + if (cl == null) { + cl = LoaderUtil.getThreadContextClassLoader(); + } + return LogManager.getContext(cl, false); +} + +``` + ## 预期多模块合并下的日志 基座与模块都能使用独立的日志配置、配置值,完全独立。但由于上述分析中,存在两处可能导致模块无法正常初始化的逻辑,故这里需要多 log4j2 进行适配。 - +static修饰的log在三方组件下沉基座后也会导致相关日志不能正常隔离打印,所以这里也需要做 log4j2 进行适配。 ### 多模块适配点 1. getLoggerContext() 能拿到模块自身的 LoggerContext ![](https://intranetproxy.alipay.com/skylark/lark/0/2023/png/149473/1696938182575-51ce1066-21f0-47bb-8bdb-c3c7d0814ca3.png) @@ -58,7 +104,35 @@ weight: 1 a. 模块启动时将 application.properties 的值设置到 ThreadContext 中 b. 日志配置时,只能使用 ctx:xxx:xxx 的配置方式 - +3. LoggerFactory.getLogger()获取的是org.apache.logging.slf4j.Log4jLogger实例,他是一个包装类,所以有一定操作空间, +针对Log4jLogger进行复写改造,根据当前线程上下文类加载器动态获取底层ExtendedLogger对象 + ```java +public class Log4JLogger implements LocationAwareLogger, Serializable { + private transient final Map loggerMap = new ConcurrentHashMap<>(); + private static final Map LOGGER_CONTEXT_MAP = new ConcurrentHashMap<>(); + + pubblic void info(final String format, final Object o) { + //每次调用都获取对应的ExtendedLogger + getLogger().logIfEnabled(FQCN, Level.INFO, null, format, o); + } + + //根据当前线程类加载器动态获取ExtendedLogger + private ExtendedLogger getLogger() { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + ExtendedLogger extendedLogger = loggerMap.get(classLoader); + if (extendedLogger == null) { + LoggerContext loggerContext = LOGGER_CONTEXT_MAP.get(classLoader); + if (loggerContext == null) { + loggerContext = LogManager.getContext(classLoader, false); + LOGGER_CONTEXT_MAP.put(classLoader, loggerContext); + } + extendedLogger = loggerContext.getLogger(this.name); + loggerMap.put(classLoader, extendedLogger); + } + return extendedLogger; + } + } +``` ## 模块改造方式 [详细查看源码](https://github.com/sofastack/sofa-serverless/tree/master/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/src/main/java/com/alipay/sofa/serverless/log4j2) diff --git a/samples/springboot-samples/logging/imgs/biz1-3-log.png b/samples/springboot-samples/logging/imgs/biz1-3-log.png new file mode 100644 index 000000000..3694c8158 Binary files /dev/null and b/samples/springboot-samples/logging/imgs/biz1-3-log.png differ diff --git a/samples/springboot-samples/logging/imgs/biz2-3-log.png b/samples/springboot-samples/logging/imgs/biz2-3-log.png new file mode 100644 index 000000000..00220cead Binary files /dev/null and b/samples/springboot-samples/logging/imgs/biz2-3-log.png differ diff --git a/samples/springboot-samples/logging/log4j2/README.md b/samples/springboot-samples/logging/log4j2/README.md index d89d37b6a..53bd569d4 100644 --- a/samples/springboot-samples/logging/log4j2/README.md +++ b/samples/springboot-samples/logging/log4j2/README.md @@ -45,6 +45,13 @@ base 为普通 springboot 改造成的基座,改造内容为在 pom 里增加 + + + net.sf.ehcache + ehcache + + + ``` ### biz @@ -58,6 +65,14 @@ biz 包含两个模块,分别为 biz1 和 biz2, 都是普通 springboot,修 provided + + + net.sf.ehcache + ehcache + provided + + + com.alipay.sofa @@ -142,11 +157,17 @@ curl http://localhost:8080/biz2 2. 检查内容2, `./samples/logging/log4j2/logs/` 目录里的日志分布在符合如下情况 ![img_2.png](../imgs/logs-structure.png) -- biz1 的应用日志在 `./samples/logging/log4j2/logs/biz1/` 目录下 -- biz2 的应用日志在 `./samples/logging/log4j2/logs/biz2/` 目录下 -- base 的应用日志在 `./samples/logging/log4j2/logs/base/` 目录下 +3.三方组件(这里如ehcache)依赖下沉基座后日志正常隔离打印 +![img_1.png](../imgs/biz1-3-log.png) +![img.png](../imgs/biz2-3-log.png) + +- biz1 的应用及三方组件(ehcache)日志在 `./samples/logging/log4j2/logs/biz1/` 目录下 +- biz2 的应用及三方组件(ehcache)日志在 `./samples/logging/log4j2/logs/biz2/` 目录下 +- base 的应用及三方组件(ehcache)日志在 `./samples/logging/log4j2/logs/base/` 目录下 - biz1, biz2, base 的框架日志(如 spring sofaArk arklet等),统一合并在同一个目录文件里 ## 注意事项 这里主要使用简单应用做验证,如果复杂应用,需要注意模块做好瘦身,基座有的依赖,模块尽可能设置成 provided,尽可能使用基座的依赖。 + + diff --git a/samples/springboot-samples/logging/log4j2/base/pom.xml b/samples/springboot-samples/logging/log4j2/base/pom.xml index ce3aa4a94..081afe127 100644 --- a/samples/springboot-samples/logging/log4j2/base/pom.xml +++ b/samples/springboot-samples/logging/log4j2/base/pom.xml @@ -30,7 +30,6 @@ com.alipay.sofa web-ark-plugin - org.springframework.boot spring-boot-starter-web @@ -58,6 +57,11 @@ disruptor ${disruptor.version} + + + net.sf.ehcache + ehcache + diff --git a/samples/springboot-samples/logging/log4j2/base/src/main/java/com/alipay/sofa/logging/base/rest/SampleController.java b/samples/springboot-samples/logging/log4j2/base/src/main/java/com/alipay/sofa/logging/base/rest/SampleController.java index bea04773a..37b6d8d8c 100644 --- a/samples/springboot-samples/logging/log4j2/base/src/main/java/com/alipay/sofa/logging/base/rest/SampleController.java +++ b/samples/springboot-samples/logging/log4j2/base/src/main/java/com/alipay/sofa/logging/base/rest/SampleController.java @@ -1,6 +1,7 @@ package com.alipay.sofa.logging.base.rest; import com.alipay.sofa.logging.base.facade.SampleService; +import net.sf.ehcache.CacheManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -26,6 +27,9 @@ public String hello() { sampleService.service(); + CacheManager.create(); + CacheManager.create(); + return String.format("hello to %s deploy", appName); } } diff --git a/samples/springboot-samples/logging/log4j2/base/src/main/resources/application.properties b/samples/springboot-samples/logging/log4j2/base/src/main/resources/application.properties index d3e3ff999..016543415 100644 --- a/samples/springboot-samples/logging/log4j2/base/src/main/resources/application.properties +++ b/samples/springboot-samples/logging/log4j2/base/src/main/resources/application.properties @@ -4,4 +4,5 @@ logging.path=./logging/log4j2/logs/ logging.level.com.alipay.sofa=DEBUG logging.level.root=INFO logging.level.com.alipay.sofa.arklet=INFO +logging.level.net.sf.ehcache=DEBUG logging.config=classpath:log4j2-spring.xml diff --git a/samples/springboot-samples/logging/log4j2/base/src/main/resources/log4j2-spring.xml b/samples/springboot-samples/logging/log4j2/base/src/main/resources/log4j2-spring.xml index 45f80b375..fea3012cb 100644 --- a/samples/springboot-samples/logging/log4j2/base/src/main/resources/log4j2-spring.xml +++ b/samples/springboot-samples/logging/log4j2/base/src/main/resources/log4j2-spring.xml @@ -92,6 +92,14 @@ + + + + + + + diff --git a/samples/springboot-samples/logging/log4j2/biz1/pom.xml b/samples/springboot-samples/logging/log4j2/biz1/pom.xml index 3a64670e5..a00e10ca0 100644 --- a/samples/springboot-samples/logging/log4j2/biz1/pom.xml +++ b/samples/springboot-samples/logging/log4j2/biz1/pom.xml @@ -45,6 +45,12 @@ ${sofa.serverless.runtime.version} provided + + + net.sf.ehcache + ehcache + provided + diff --git a/samples/springboot-samples/logging/log4j2/biz1/src/main/java/com/alipay/sofa/logging/biz1/rest/SampleController.java b/samples/springboot-samples/logging/log4j2/biz1/src/main/java/com/alipay/sofa/logging/biz1/rest/SampleController.java index e28bbc90a..d4c21febf 100644 --- a/samples/springboot-samples/logging/log4j2/biz1/src/main/java/com/alipay/sofa/logging/biz1/rest/SampleController.java +++ b/samples/springboot-samples/logging/log4j2/biz1/src/main/java/com/alipay/sofa/logging/biz1/rest/SampleController.java @@ -1,5 +1,6 @@ package com.alipay.sofa.logging.biz1.rest; +import net.sf.ehcache.CacheManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -12,6 +13,7 @@ public class SampleController { private static final Logger LOGGER = LoggerFactory.getLogger(SampleController.class); + @Autowired private ApplicationContext applicationContext; @@ -19,6 +21,10 @@ public class SampleController { public String hello() { String appName = applicationContext.getApplicationName(); LOGGER.info("{} web test: into sample controller", appName); + + CacheManager.create(); + CacheManager.create(); + return String.format("hello to %s deploy", appName); } } diff --git a/samples/springboot-samples/logging/log4j2/biz1/src/main/resources/application.properties b/samples/springboot-samples/logging/log4j2/biz1/src/main/resources/application.properties index 256534db0..2b076af90 100644 --- a/samples/springboot-samples/logging/log4j2/biz1/src/main/resources/application.properties +++ b/samples/springboot-samples/logging/log4j2/biz1/src/main/resources/application.properties @@ -4,4 +4,5 @@ logging.path=./logging/log4j2/logs/ logging.level.com.alipay.sofa=DEBUG logging.level.root=INFO logging.level.com.alipay.sofa.arklet=INFO +logging.level.net.sf.ehcache=DEBUG logging.config=classpath:log4j2-spring.xml diff --git a/samples/springboot-samples/logging/log4j2/biz1/src/main/resources/log4j2-spring.xml b/samples/springboot-samples/logging/log4j2/biz1/src/main/resources/log4j2-spring.xml index 45f80b375..fea3012cb 100644 --- a/samples/springboot-samples/logging/log4j2/biz1/src/main/resources/log4j2-spring.xml +++ b/samples/springboot-samples/logging/log4j2/biz1/src/main/resources/log4j2-spring.xml @@ -92,6 +92,14 @@ + + + + + + + diff --git a/samples/springboot-samples/logging/log4j2/biz2/pom.xml b/samples/springboot-samples/logging/log4j2/biz2/pom.xml index eb7ba2d66..a121edb16 100644 --- a/samples/springboot-samples/logging/log4j2/biz2/pom.xml +++ b/samples/springboot-samples/logging/log4j2/biz2/pom.xml @@ -45,6 +45,12 @@ ${sofa.serverless.runtime.version} provided + + + net.sf.ehcache + ehcache + provided + diff --git a/samples/springboot-samples/logging/log4j2/biz2/src/main/java/com/alipay/sofa/logging/biz2/rest/SampleController.java b/samples/springboot-samples/logging/log4j2/biz2/src/main/java/com/alipay/sofa/logging/biz2/rest/SampleController.java index 84102a22c..d117e79c8 100644 --- a/samples/springboot-samples/logging/log4j2/biz2/src/main/java/com/alipay/sofa/logging/biz2/rest/SampleController.java +++ b/samples/springboot-samples/logging/log4j2/biz2/src/main/java/com/alipay/sofa/logging/biz2/rest/SampleController.java @@ -1,5 +1,6 @@ package com.alipay.sofa.logging.biz2.rest; +import net.sf.ehcache.CacheManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -19,6 +20,9 @@ public class SampleController { public String hello() { String appName = applicationContext.getApplicationName(); LOGGER.info("{} web test: into sample controller", appName); + + CacheManager.create(); + CacheManager.create(); return String.format("hello to %s deploy", appName); } } diff --git a/samples/springboot-samples/logging/log4j2/biz2/src/main/resources/application.properties b/samples/springboot-samples/logging/log4j2/biz2/src/main/resources/application.properties index 811879704..c24c59a79 100644 --- a/samples/springboot-samples/logging/log4j2/biz2/src/main/resources/application.properties +++ b/samples/springboot-samples/logging/log4j2/biz2/src/main/resources/application.properties @@ -4,4 +4,5 @@ logging.path=./logging/log4j2/logs/ logging.level.com.alipay.sofa=DEBUG logging.level.root=INFO logging.level.com.alipay.sofa.arklet=INFO +logging.level.net.sf.ehcache=DEBUG logging.config=classpath:log4j2-spring.xml diff --git a/samples/springboot-samples/logging/log4j2/biz2/src/main/resources/log4j2-spring.xml b/samples/springboot-samples/logging/log4j2/biz2/src/main/resources/log4j2-spring.xml index 45f80b375..fea3012cb 100644 --- a/samples/springboot-samples/logging/log4j2/biz2/src/main/resources/log4j2-spring.xml +++ b/samples/springboot-samples/logging/log4j2/biz2/src/main/resources/log4j2-spring.xml @@ -92,6 +92,14 @@ + + + + + + + diff --git a/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/pom.xml b/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/pom.xml index ddab63580..ca88c868b 100644 --- a/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/pom.xml +++ b/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/pom.xml @@ -60,6 +60,9 @@ org.springframework.boot.logging.log4j2.Log4J2LoggingSystem + + org.apache.logging.slf4j.Log4jLogger + diff --git a/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/src/main/java/org/apache/logging/slf4j/Log4jLogger.java b/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/src/main/java/org/apache/logging/slf4j/Log4jLogger.java new file mode 100644 index 000000000..3e558ae6c --- /dev/null +++ b/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/src/main/java/org/apache/logging/slf4j/Log4jLogger.java @@ -0,0 +1,465 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.logging.slf4j; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.message.ParameterizedMessage; +import org.apache.logging.log4j.message.SimpleMessage; +import org.apache.logging.log4j.spi.ExtendedLogger; +import org.apache.logging.log4j.spi.LoggerContext; +import org.apache.logging.log4j.util.LoaderUtil; +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; +import org.slf4j.impl.StaticMarkerBinder; +import org.slf4j.spi.LocationAwareLogger; + +/** + * SLF4J logger implementation that uses Log4j. + */ +public class Log4jLogger implements LocationAwareLogger, Serializable { + + public static final String FQCN = Log4jLogger.class + .getName(); + + private static final long serialVersionUID = 7869000638091304316L; + private static final Marker EVENT_MARKER = MarkerFactory + .getMarker("EVENT"); + private static final EventDataConverter CONVERTER = createConverter(); + + private final boolean eventLogger; + private transient final Map loggerMap = new ConcurrentHashMap<>(); + private static final Map LOGGER_CONTEXT_MAP = new ConcurrentHashMap<>(); + private final String name; + + public Log4jLogger(final ExtendedLogger logger, final String name) { + this.eventLogger = "EventLogger".equals(name); + this.name = name; + } + + @Override + public void trace(final String format) { + getLogger().logIfEnabled(FQCN, Level.TRACE, null, format); + } + + @Override + public void trace(final String format, final Object o) { + getLogger().logIfEnabled(FQCN, Level.TRACE, null, format, o); + } + + @Override + public void trace(final String format, final Object arg1, final Object arg2) { + getLogger().logIfEnabled(FQCN, Level.TRACE, null, format, arg1, arg2); + } + + @Override + public void trace(final String format, final Object... args) { + getLogger().logIfEnabled(FQCN, Level.TRACE, null, format, args); + } + + @Override + public void trace(final String format, final Throwable t) { + getLogger().logIfEnabled(FQCN, Level.TRACE, null, format, t); + } + + @Override + public boolean isTraceEnabled() { + return getLogger().isEnabled(Level.TRACE, null, null); + } + + @Override + public boolean isTraceEnabled(final Marker marker) { + return getLogger().isEnabled(Level.TRACE, getMarker(marker), null); + } + + @Override + public void trace(final Marker marker, final String s) { + getLogger().logIfEnabled(FQCN, Level.TRACE, getMarker(marker), s); + } + + @Override + public void trace(final Marker marker, final String s, final Object o) { + getLogger().logIfEnabled(FQCN, Level.TRACE, getMarker(marker), s, o); + } + + @Override + public void trace(final Marker marker, final String s, final Object o, final Object o1) { + getLogger().logIfEnabled(FQCN, Level.TRACE, getMarker(marker), s, o, o1); + } + + @Override + public void trace(final Marker marker, final String s, final Object... objects) { + getLogger().logIfEnabled(FQCN, Level.TRACE, getMarker(marker), s, objects); + } + + @Override + public void trace(final Marker marker, final String s, final Throwable throwable) { + getLogger().logIfEnabled(FQCN, Level.TRACE, getMarker(marker), s, throwable); + } + + @Override + public void debug(final String format) { + getLogger().logIfEnabled(FQCN, Level.DEBUG, null, format); + } + + @Override + public void debug(final String format, final Object o) { + getLogger().logIfEnabled(FQCN, Level.DEBUG, null, format, o); + } + + @Override + public void debug(final String format, final Object arg1, final Object arg2) { + getLogger().logIfEnabled(FQCN, Level.DEBUG, null, format, arg1, arg2); + } + + @Override + public void debug(final String format, final Object... args) { + getLogger().logIfEnabled(FQCN, Level.DEBUG, null, format, args); + } + + @Override + public void debug(final String format, final Throwable t) { + getLogger().logIfEnabled(FQCN, Level.DEBUG, null, format, t); + } + + @Override + public boolean isDebugEnabled() { + return getLogger().isEnabled(Level.DEBUG, null, null); + } + + @Override + public boolean isDebugEnabled(final Marker marker) { + return getLogger().isEnabled(Level.DEBUG, getMarker(marker), null); + } + + @Override + public void debug(final Marker marker, final String s) { + getLogger().logIfEnabled(FQCN, Level.DEBUG, getMarker(marker), s); + } + + @Override + public void debug(final Marker marker, final String s, final Object o) { + getLogger().logIfEnabled(FQCN, Level.DEBUG, getMarker(marker), s, o); + } + + @Override + public void debug(final Marker marker, final String s, final Object o, final Object o1) { + getLogger().logIfEnabled(FQCN, Level.DEBUG, getMarker(marker), s, o, o1); + } + + @Override + public void debug(final Marker marker, final String s, final Object... objects) { + getLogger().logIfEnabled(FQCN, Level.DEBUG, getMarker(marker), s, objects); + } + + @Override + public void debug(final Marker marker, final String s, final Throwable throwable) { + getLogger().logIfEnabled(FQCN, Level.DEBUG, getMarker(marker), s, throwable); + } + + @Override + public void info(final String format) { + getLogger().logIfEnabled(FQCN, Level.INFO, null, format); + } + + @Override + public void info(final String format, final Object o) { + getLogger().logIfEnabled(FQCN, Level.INFO, null, format, o); + } + + @Override + public void info(final String format, final Object arg1, final Object arg2) { + getLogger().logIfEnabled(FQCN, Level.INFO, null, format, arg1, arg2); + } + + @Override + public void info(final String format, final Object... args) { + getLogger().logIfEnabled(FQCN, Level.INFO, null, format, args); + } + + @Override + public void info(final String format, final Throwable t) { + getLogger().logIfEnabled(FQCN, Level.INFO, null, format, t); + } + + @Override + public boolean isInfoEnabled() { + return getLogger().isEnabled(Level.INFO, null, null); + } + + @Override + public boolean isInfoEnabled(final Marker marker) { + return getLogger().isEnabled(Level.INFO, getMarker(marker), null); + } + + @Override + public void info(final Marker marker, final String s) { + getLogger().logIfEnabled(FQCN, Level.INFO, getMarker(marker), s); + } + + @Override + public void info(final Marker marker, final String s, final Object o) { + getLogger().logIfEnabled(FQCN, Level.INFO, getMarker(marker), s, o); + } + + @Override + public void info(final Marker marker, final String s, final Object o, final Object o1) { + getLogger().logIfEnabled(FQCN, Level.INFO, getMarker(marker), s, o, o1); + } + + @Override + public void info(final Marker marker, final String s, final Object... objects) { + getLogger().logIfEnabled(FQCN, Level.INFO, getMarker(marker), s, objects); + } + + @Override + public void info(final Marker marker, final String s, final Throwable throwable) { + getLogger().logIfEnabled(FQCN, Level.INFO, getMarker(marker), s, throwable); + } + + @Override + public void warn(final String format) { + getLogger().logIfEnabled(FQCN, Level.WARN, null, format); + } + + @Override + public void warn(final String format, final Object o) { + getLogger().logIfEnabled(FQCN, Level.WARN, null, format, o); + } + + @Override + public void warn(final String format, final Object arg1, final Object arg2) { + getLogger().logIfEnabled(FQCN, Level.WARN, null, format, arg1, arg2); + } + + @Override + public void warn(final String format, final Object... args) { + getLogger().logIfEnabled(FQCN, Level.WARN, null, format, args); + } + + @Override + public void warn(final String format, final Throwable t) { + getLogger().logIfEnabled(FQCN, Level.WARN, null, format, t); + } + + @Override + public boolean isWarnEnabled() { + return getLogger().isEnabled(Level.WARN, null, null); + } + + @Override + public boolean isWarnEnabled(final Marker marker) { + return getLogger().isEnabled(Level.WARN, getMarker(marker), null); + } + + @Override + public void warn(final Marker marker, final String s) { + getLogger().logIfEnabled(FQCN, Level.WARN, getMarker(marker), s); + } + + @Override + public void warn(final Marker marker, final String s, final Object o) { + getLogger().logIfEnabled(FQCN, Level.WARN, getMarker(marker), s, o); + } + + @Override + public void warn(final Marker marker, final String s, final Object o, final Object o1) { + getLogger().logIfEnabled(FQCN, Level.WARN, getMarker(marker), s, o, o1); + } + + @Override + public void warn(final Marker marker, final String s, final Object... objects) { + getLogger().logIfEnabled(FQCN, Level.WARN, getMarker(marker), s, objects); + } + + @Override + public void warn(final Marker marker, final String s, final Throwable throwable) { + getLogger().logIfEnabled(FQCN, Level.WARN, getMarker(marker), s, throwable); + } + + @Override + public void error(final String format) { + getLogger().logIfEnabled(FQCN, Level.ERROR, null, format); + } + + @Override + public void error(final String format, final Object o) { + getLogger().logIfEnabled(FQCN, Level.ERROR, null, format, o); + } + + @Override + public void error(final String format, final Object arg1, final Object arg2) { + getLogger().logIfEnabled(FQCN, Level.ERROR, null, format, arg1, arg2); + } + + @Override + public void error(final String format, final Object... args) { + getLogger().logIfEnabled(FQCN, Level.ERROR, null, format, args); + } + + @Override + public void error(final String format, final Throwable t) { + getLogger().logIfEnabled(FQCN, Level.ERROR, null, format, t); + } + + @Override + public boolean isErrorEnabled() { + return getLogger().isEnabled(Level.ERROR, null, null); + } + + @Override + public boolean isErrorEnabled(final Marker marker) { + return getLogger().isEnabled(Level.ERROR, getMarker(marker), null); + } + + @Override + public void error(final Marker marker, final String s) { + getLogger().logIfEnabled(FQCN, Level.ERROR, getMarker(marker), s); + } + + @Override + public void error(final Marker marker, final String s, final Object o) { + getLogger().logIfEnabled(FQCN, Level.ERROR, getMarker(marker), s, o); + } + + @Override + public void error(final Marker marker, final String s, final Object o, final Object o1) { + getLogger().logIfEnabled(FQCN, Level.ERROR, getMarker(marker), s, o, o1); + } + + @Override + public void error(final Marker marker, final String s, final Object... objects) { + getLogger().logIfEnabled(FQCN, Level.ERROR, getMarker(marker), s, objects); + } + + @Override + public void error(final Marker marker, final String s, final Throwable throwable) { + getLogger().logIfEnabled(FQCN, Level.ERROR, getMarker(marker), s, throwable); + } + + @Override + public void log(final Marker marker, final String fqcn, final int level, final String message, + final Object[] params, Throwable throwable) { + final Level log4jLevel = getLevel(level); + final org.apache.logging.log4j.Marker log4jMarker = getMarker(marker); + ExtendedLogger logger = getLogger(); + + if (!logger.isEnabled(log4jLevel, log4jMarker, message, params)) { + return; + } + final Message msg; + if (CONVERTER != null && eventLogger && marker != null && marker.contains(EVENT_MARKER)) { + msg = CONVERTER.convertEvent(message, params, throwable); + } else if (params == null) { + msg = new SimpleMessage(message); + } else { + msg = new ParameterizedMessage(message, params, throwable); + if (throwable != null) { + throwable = msg.getThrowable(); + } + } + logger.logMessage(fqcn, log4jLevel, log4jMarker, msg, throwable); + } + + private static org.apache.logging.log4j.Marker getMarker(final Marker marker) { + if (marker == null) { + return null; + } else if (marker instanceof Log4jMarker) { + return ((Log4jMarker) marker).getLog4jMarker(); + } else { + final Log4jMarkerFactory factory = (Log4jMarkerFactory) StaticMarkerBinder.SINGLETON + .getMarkerFactory(); + return ((Log4jMarker) factory.getMarker(marker)).getLog4jMarker(); + } + } + + @Override + public String getName() { + return name; + } + + /** + * Always treat de-serialization as a full-blown constructor, by validating the final state of + * the de-serialized object. + */ + private void readObject(final ObjectInputStream aInputStream) throws ClassNotFoundException, + IOException { + // always perform the default de-serialization first + aInputStream.defaultReadObject(); + } + + /** + * This is the default implementation of writeObject. Customise if necessary. + */ + private void writeObject(final ObjectOutputStream aOutputStream) throws IOException { + // perform the default serialization for all non-transient, non-static fields + aOutputStream.defaultWriteObject(); + } + + private static EventDataConverter createConverter() { + try { + LoaderUtil.loadClass("org.slf4j.ext.EventData"); + return new EventDataConverter(); + } catch (final ClassNotFoundException cnfe) { + return null; + } + } + + private static Level getLevel(final int i) { + switch (i) { + case TRACE_INT: + return Level.TRACE; + case DEBUG_INT: + return Level.DEBUG; + case INFO_INT: + return Level.INFO; + case WARN_INT: + return Level.WARN; + case ERROR_INT: + return Level.ERROR; + } + return Level.ERROR; + } + + /** + * 根据当前线程上下文类加载器获取logger + * + * @return ExtendedLogger + */ + private ExtendedLogger getLogger() { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + ExtendedLogger extendedLogger = loggerMap.get(classLoader); + if (extendedLogger == null) { + LoggerContext loggerContext = LOGGER_CONTEXT_MAP.get(classLoader); + if (loggerContext == null) { + loggerContext = LogManager.getContext(classLoader, false); + LOGGER_CONTEXT_MAP.put(classLoader, loggerContext); + } + extendedLogger = loggerContext.getLogger(this.name); + loggerMap.put(classLoader, extendedLogger); + } + return extendedLogger; + } +}