我有以下场景:一个 EAR,带有 3 个 WAR(销售模块、内联网模块和主应用程序 - 一个 lms 系统)。每个 WAR 都有 log4j.properties 来配置单独的日志文件,以组织和更容易地发现每个系统上的问题。
问题是,这 3 场 war 共享一个依赖项 - 一个核心 jar,与我的服务层(实体、存储库、服务等)。该 jar 没有 log4.properties,并且此处进行的所有日志记录都转到 server.log。我想避免它。
当我过去单独部署 war 时,一切都很好 - 因为 jar 在 war 中并且与 log4j.properties 一起。所以:
Request -> Intranet.war -> Core JAR -> all logging here goes to intranet.log
Request -> LMS.war -> Core JAR -> all logging here goes to lms.log
Request -> Sales.war -> Core JAR -> all logging here goes to sales.log
现在我在 EAR 的 lib/文件夹中只有一个核心 jar,由他们共享。
问题是:我怎样才能仍然根据哪个 war 称为核心来组织日志?
我的意思是,如果我在 EAR 中调用 intranet.war,则 core.jar 中的所有日志记录仍然转到 intranet.log。 LMS 和销售也是如此。
我正在考虑为整个 EAR 使用一个唯一的 log4j.properties 文件,但我如何在文件中分离?我可以使用包方法(例如 xxx.lms.yyy 转到 lms.log),但核心 jar 中的包是共享的。
有什么想法吗?
提前致谢!
最佳答案
我找到了一种使其与 CDI 和 ThreadLocal 一起工作的方法。
每个请求都有一个关联的线程,所以我做了一个 CDI Producer 方法,它的逻辑很简单:当前线程本地是否有 Logger?如果是,请返回。如果没有,从 SLF4J LoggerFactory 中获取一个,将其保存在 ThreadLocal 中并返回。
然后,为了获得 wars 和核心 jar 中的记录器,我这样做:
@Inject @MyQualifier private Logger logger;
//I created a specific qualifier because one of the frameworks I use also have a Logger Producer
生产者方法:
@Produces @MyQualifier
public Logger getLogger(InjectionPoint ip){
ThreadLocal<Logger> t = new ThreadLocal<>();
if(t.get() == null) {
Class<?> clazz = ip.getMember().getDeclaringClass();
t.set(org.slf4j.LoggerFactory.getLogger(clazz));
}
return t.get();
}
工作起来很有魅力!我的服务/daos 类都是@requestscoped,所以对于每个请求,我只有一个关联的记录器,它在 WAR 中实例化 - log4j.properties 根据我的需要为该上下文配置。
但是,有一种情况它不起作用:EJB 中的@Schedule 方法。在这种情况下,线程不是在 war 中而是在 jar 上下文中“创建”的。对于这些情况,我在 EAR 的 META-INF 文件夹中创建了另一个 log4j.properties。现在一切正常。
关于jakarta-ee - LOG4J - EAR 中不同 war 的独立日志文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48425008/