我们在Spring XD v1.0.0.RELEASE上运行了几个流和作业 相应的流和作业模块将消息记录到Spring XD的全局日志文件中,位于 $ XD_HOME / logs 下 我们需要分辨每个作业和流创建的日志消息。使用 $ {xd.job.name} 或 $ {xd.stream.name} 的值标记每个日志行应该对我们有用。例如,
1)在配置文件(Spring XD配置,XML上下文文件,Java类......等等)中,设置Java上下文(?)变量:
if(moduleType == "job") {
name = ${xd.job.name};
} else if(moduleType == "stream") {
name = ${xd.stream.name};
} else {
name = "XD";
}
2)相应地在 $ XD_HOME / config 下配置log4j属性文件:
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %t %c{2} [${name}] - %m%n
3)运行作业的Spring XD的日志输出(xd.job.name =“ fooJob ”)和流(xd.stream.name =“ barStream “):
...
13:07:41,169 DEBUG task-scheduler-1 myjobimpl.TransactionManager [fooJob] - Initiating transaction commit
...
13:08:43,215 INFO task-scheduler-15 mystreamimpl.JsonDecoder [barStream] - Decoding JSON: {...}
...
14:08:42,569 INFO DeploymentsPathChildrenCache-0 monitor.IntegrationMBeanExporter [XD] - Summary on shutdown: MessageChannelMonitor: [name=input, sends=0]
4)其他库记录的任何消息(例如Spring Data,Apache Commons等)应该有[ fooJob ],[ barStream ]或[ XD ],与调用库的作业或流的值相同。
到目前为止我们提出的唯一半成品解决方案是在log4j的MDC or NDC中设置 $ name ,但我们不知道如何设置它基于每个流或每个作业(MDC和NDC基于每个线程工作)。
有没有办法将作业或流名称添加到相应的日志行?
答案 0 :(得分:0)
在看到你的other question后,我们在内部讨论这个问题。
我们还讨论了MDC,我们可以在总线实现中设置它,但它只适用于处理器和接收器。我们需要Spring Integration / Spring Batch中的代码才能使其适用于源和作业。
这也是许多人不想要的开销,所以它必须是可选的。
底线是我们还没有解决方案(但是),但随时可以打开新功能JIRA Issue。
编辑:回复您的评论......
嗯...对于处理器和接收器,您可以向ChannelInterceptor
频道添加input
,然后在preSend()
中推送该名称并将其弹出postSend()
。对于来源,您可以在output
频道上执行相同操作。
唯一的问题是,如果在postSend()
之后抛出异常,则不会调用preSend()
。 Spring Integration 4.1(应该在下周发布;目前以release candidate提供)adds support用于调用interceptor.afterSendCompletion()
,无论是否发生异常,都会调用它。
注意:获取对通道的引用时,要添加拦截器,必须使用ChannelInterceptorAware
来执行此操作,因为bean可能已被代理。
如果这样有效,并且您希望contribute it我们很乐意考虑它。
答案 1 :(得分:0)
我最终创建了自定义Logback formatting converter。
public class SpringPropertyConverter extends ClassicConverter {
private String key;
private String defaultValue = "";
@Override
public void start() {
String[] keyInfo = extractDefaultReplacement(getFirstOption());
key = keyInfo[0];
if (keyInfo[1] != null) {
defaultValue = keyInfo[1];
}
super.start();
}
@Override
public void stop() {
key = null;
super.stop();
}
@Override
public String convert(ILoggingEvent event) {
SpringLogbackPropertyResolver resolver = SpringLogbackPropertyResolver.getInstance();
if (resolver == null) {
return defaultValue;
}
return resolver.getProperty(key, defaultValue);
}
}
由持有Environment
实例的bean支持:
@Service
public class SpringLogbackPropertyResolver {
private static volatile SpringLogbackPropertyResolver instance;
private final Environment env;
private final Map<String, String> map;
public SpringLogbackPropertyResolver(@Autowired Environment env) {
this.env = env;
this.map = new ConcurrentHashMap<>();
this.instance = this;
}
public String getProperty(String key, String defaultValue){
return map.computeIfAbsent(key, k -> env.getProperty(key, defaultValue));
}
public static SpringLogbackPropertyResolver getInstance() {
return instance;
}
}
然后在xd-container-logback.groovy
中注册转换器:
conversionRule("spring", SpringPropertyConverter)
然后可以使用spring
前缀%spring{xd.stream.name:-bar}