Java 使用石英工作线程拆分log4j输出
我正在开发一个应用程序,它由一个基于Quartz的调度器和使用CronTriggers运行的“CycledJob”组成。该应用程序的目的是根据来源国处理来自不同电子邮件收件箱的输入 基于它来自的国家(即美国、英国、法国等),应用程序触发一个作业线程来运行每个国家的处理周期,因此将有一个英国工作线程,一个用于美国、法国等。在将输出格式化为log4j时,我使用thread参数,因此它会发出[ApplicationName_Worker-1],[ApplicationName_Worker-2]等等。尽管我可能会尝试,但我找不到命名线程的方法,因为它们是从Quartz的线程池中提取出来的。虽然我可能会扩展Quartz,但我想找到一个不同的解决方案,而不是与标准库混为一谈 问题是:在使用log4j时,我希望将美国线程中的所有日志项输出到一个仅限美国的文件中,对于每个国家的线程也是如此。我不在乎他们是否留在一个统一的控制台中,FileAppender拆分是我在这里要找的。我已经知道如何指定多个文件附加器,我的问题是我无法根据国家进行区分。应用程序中有20多个类可以在执行链上,其中很少有我想通过每个方法传递一个额外的“上下文”参数来增加负担。。。我考虑过一种扩展log4j包装器类的策略模式,但除非我能让链中的每个类都知道它在哪个线程上以参数化记录器调用,否则这似乎是不可能的。无法命名线程也会带来挑战(否则这很容易!) 所以这里有一个问题:建议采用什么方法来允许应用程序中的许多次级类(每个次级类用于每个不同的线程)处理输入,并在登录时知道它们位于特定国家/地区线程的上下文中Java 使用石英工作线程拆分log4j输出,java,multithreading,log4j,quartz-scheduler,scheduler,Java,Multithreading,Log4j,Quartz Scheduler,Scheduler,我正在开发一个应用程序,它由一个基于Quartz的调度器和使用CronTriggers运行的“CycledJob”组成。该应用程序的目的是根据来源国处理来自不同电子邮件收件箱的输入 基于它来自的国家(即美国、英国、法国等),应用程序触发一个作业线程来运行每个国家的处理周期,因此将有一个英国工作线程,一个用于美国、法国等。在将输出格式化为log4j时,我使用thread参数,因此它会发出[ApplicationName_Worker-1],[ApplicationName_Worker-2]等等。
祝你好运理解,并请提出澄清问题!我希望有人能帮我找到一个体面的方法来解决这个问题。欢迎所有建议。我希望我能比这更有帮助,但您可能希望使用一些过滤器进行调查?也许你的日志可以输出国家代码,你可以根据它匹配你的过滤器 StringMatchFilter应该能够为您匹配它 无法使下面的地址作为链接正常工作,但如果您查看它,它有一些关于使用过滤器的单独文件日志记录的内容 (只需删除>前面的空格)
我可能完全不了解您试图实现的目标,但我将尝试解决方案。听起来,您希望为处理电子邮件的每个国家/地区创建一个单独的日志文件。基于这种理解,以下是一种可能的解决方案:
在每个国家的处理线程的顶部,将国家代码放入Log4j的映射诊断上下文(MDC)中。这使用了ThreadLocal变量,因此您不必显式地在调用堆栈上下传递国家/地区。然后创建一个查看MDC的自定义过滤器,并过滤掉不包含当前appender国家代码的任何事件 在您的
作业中
:
...
public static final String MDC_COUNTRY = "com.y.foo.Country";
public void execute(JobExecutionContext context)
/* Just guessing that you have the country in your JobContext. */
MDC.put(MDC_COUNTRY, context.get(MDC_COUNTRY));
try {
/* Perform your job here. */
...
} finally {
MDC.remove(MDC_COUNTRY);
}
}
...
编写一个自定义文件:
在log4j.xml中:
<appender name="fr" class="org.apache.log4j.FileAppender">
<param name="file" value="france.log"/>
...
<filter class="com.y.log4j.ContextFilter">
<param name="key" value="com.y.foo.Country" />
<param name="value" value="fr" />
</filter>
</appender>
...
为什么不在作业开始设置线程名称时调用Thread.setName()?如果存在访问问题,请将quartz配置为使用您自己的线程池。您已接近了解。如果其他方法都不起作用,我可能会求助于这样的方法,但如果我能提供帮助,我会尝试不通过相当通用的方法/类传递特定于域的参数。目前无法根据线程判断您所在的国家/地区。我认为这是log4j.additivity。my us logger=false,至少我们是这样工作的,如果它对其他人有用的话。@FroMage-谢谢。。。延迟复制/粘贴/编辑错误。回答中更正。在您提供的基础上做了一些努力,但我没有根据您提出的解决方案获得它。非常感谢你的帮助!
package com.y.log4j;
import org.apache.log4j.spi.LoggingEvent;
/**
* This is a general purpose filter. If its "value" property is null,
* it requires only that the specified key be set in the MDC. If its
* value is not null, it further requires that the value in the MDC
* is equal.
*/
public final class ContextFilter extends org.apache.log4j.spi.Filter {
public int decide(LoggingEvent event) {
Object ctx = event.getMDC(key);
if (value == null)
return (ctx != null) ? NEUTRAL : DENY;
else
return value.equals(ctx) ? NEUTRAL : DENY;
}
private String key;
private String value;
public void setContextKey(String key) { this.key = key; }
public String getContextKey() { return key; }
public void setValue(String value) { this.value = value; }
public String getValue() { return value; }
}
<appender name="fr" class="org.apache.log4j.FileAppender">
<param name="file" value="france.log"/>
...
<filter class="com.y.log4j.ContextFilter">
<param name="key" value="com.y.foo.Country" />
<param name="value" value="fr" />
</filter>
</appender>