将$ {xd.job.name}和$ {xd.stream.name}添加到Spring XD日志中

时间:2014-11-03 15:01:24

标签: logging spring-batch spring-integration spring-xd

我们在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基于每个线程工作)。

有没有办法将作业或流名称添加到相应的日志行?

2 个答案:

答案 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}

在日志模式中使用它