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

Logging 将${xd.job.name}和${xd.stream.name}添加到Spring xd日志中,logging,spring-batch,spring-integration,spring-xd,Logging,Spring Batch,Spring Integration,Spring Xd,我们正在SpringXDV1.0.0.0版本上运行几个流和作业。 相应的流和作业模块将消息记录到SpringXD的全局日志文件中,$XD_HOME/logs下 我们需要区分每个作业和流创建的日志消息。用${xd.job.name}或${xd.stream.name}值标记每个日志行应该对我们有用。比如说, 1在配置文件Spring XD config、XML上下文文件、Java类中。。。无论如何,设置一个Java上下文变量: if(moduleType == "job") { name =

我们正在SpringXDV1.0.0.0版本上运行几个流和作业。 相应的流和作业模块将消息记录到SpringXD的全局日志文件中,$XD_HOME/logs下 我们需要区分每个作业和流创建的日志消息。用${xd.job.name}或${xd.stream.name}值标记每个日志行应该对我们有用。比如说,

1在配置文件Spring XD config、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运行作业XD.job.name=fooJob和流XD.stream.name=barStream的Spring XD的日志输出:

4其他库(例如Spring Data、Apache Commons)记录的任何消息,无论是什么,都应该具有[fooJob]、[barStream]或[XD]中的一个,与调用库的作业或流的值相同

到目前为止,我们提出的唯一不成熟的解决方案是在log4j中设置$name,但我们不知道如何在每个流或每个作业的基础上设置它,而在每个线程的基础上设置MDC和NDC


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

我们在看到您的

我们还讨论了MDC,我们可以在总线实现中设置它,但它只适用于处理器和接收器。我们需要SpringIntegration/SpringBatch中的代码,以使其也适用于源代码和作业

这也是许多人不希望的开销,因此它必须是可选的

底线是我们还没有一个解决方案,但请随意打开一个新功能

编辑:回应你下面的评论

嗯。。。对于处理器和接收器,您可以向输入通道添加一个ChannelInterceptor,并在preSend中推送名称,在postSend中弹出名称。对于源,您可以在输出通道上执行相同的操作

唯一的问题是,如果在preSend之后抛出异常,则不会调用postSend。SpringIntegration4.1应该在下周发布;当前可用作调用interceptor.AfterEndCompletion的函数,无论是否发生异常,都会调用该函数

注意:当获取对通道的引用时,要添加拦截器,必须使用ChannelInterceptorAware,因为bean可能被代理


如果这是可行的,你会愿意的,我们会很乐意考虑的。 我最终创建了一个自定义的Logback

由保存环境实例的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;
    }
}

然后可以在日志模式中使用它,其spring前缀为%spring{xd.stream.name:-bar}

谢谢您的帮助。我在考虑创建一个XD插件来修改AOP?模块上下文流或作业的每个bean,通过向每个bean的每个方法添加before和after通知。它们应该分别执行NDC.push$name和NDC.pop。在运行流或作业时,每次bean方法开始或结束时,其线程都会被标记或取消标记,相应的日志消息也会被标记或取消标记。我不知道这是否可能,在我看来,这是一个丑陋的黑客。你能提供一些帮助吗?再次感谢你,你的看起来是一个更好的解决方案流,也许沿着这些路线的东西也可以工作-嗯。。。。当你进入基于反应器的流处理器时,这会变得更加棘手——基本上是由任何东西包装的。代码在单独的线程中运行,因此MDC/NDC可能无法工作。我们也在试图找到解决办法。。。
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);
    }
}
@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;
    }
}
conversionRule("spring", SpringPropertyConverter)