我正在开发一个应用程序,它包含一个基于Quartz的整体调度程序和使用CronTriggers运行的"CycledJob".该应用程序的目的是根据源国家处理来自不同电子邮件收件箱的输入.
根据它所来自的国家(即美国,英国,法国国家联盟等),该应用程序触发一个作业线程来运行每个国家的处理周期,因此将有一个英国工人线程,一个用于美国,法国等.将输出格式化为log4j时,我正在使用thread参数,因此它会发出[ApplicationName_Worker-1],[ApplicationName_Worker-2]等.尽可能尝试,我找不到一种方法来命名线程,因为它们'重新退出Quartz的Thread Pools.虽然我可能会扩展Quartz,但我想制定一个不同的解决方案,而不是搞乱标准库.
问题在于:当使用log4j时,我希望将来自US线程输出的所有日志项输出到仅限US的文件,同样适用于每个国家/地区线程.我不在乎他们是否留在一个统一的ConsoleAppender中,FileAppender拆分就是我在这里所说的.我已经知道如何指定多个文件追加器等等,我的问题是我无法根据国家区分.应用程序中有20多个类可以在执行链上,其中很少我想通过每个方法传递额外的"上下文"参数的知识负担...我已经考虑了扩展一个策略模式log4j包装类,但除非我能让链中的每个类都知道它所在的哪个线程参数化记录器调用,这似乎是不可能的.
所以这里有一个问题:在一个应用程序中允许许多从属类的建议方法是什么,每个用于每个不同的线程来处理输入,知道它们在记录时是否在特定国家线程的上下文中?
祝你好运,请提出澄清问题!我希望有人能够帮助我找到解决这个问题的好方法.欢迎所有建议.
在每个国家/地区的处理线程的顶部,将国家/地区代码放入Log4j的映射诊断上下文(MDC).这使用ThreadLocal变量,这样您就不必显式地在调用堆栈中上下传递国家/地区.然后创建一个查看MDC的自定义过滤器,并过滤掉任何不包含当前appender国家/地区代码的事件.
在你的Job
:
... 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); } } ...
编写自定义过滤器:
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; } }
在你的log4j.xml中:
...