elasticsearch 在将完整日志发送到logstash/elasticsearch之前将一半日志发送到RabbitMQ的方法,elasticsearch,rabbitmq,logstash,apache-kafka,logstash-forwarder,elasticsearch,Rabbitmq,Logstash,Apache Kafka,Logstash Forwarder" /> elasticsearch 在将完整日志发送到logstash/elasticsearch之前将一半日志发送到RabbitMQ的方法,elasticsearch,rabbitmq,logstash,apache-kafka,logstash-forwarder,elasticsearch,Rabbitmq,Logstash,Apache Kafka,Logstash Forwarder" />

elasticsearch 在将完整日志发送到logstash/elasticsearch之前将一半日志发送到RabbitMQ的方法

elasticsearch 在将完整日志发送到logstash/elasticsearch之前将一半日志发送到RabbitMQ的方法,elasticsearch,rabbitmq,logstash,apache-kafka,logstash-forwarder,elasticsearch,Rabbitmq,Logstash,Apache Kafka,Logstash Forwarder,我有两个函数,每个函数都创建特定于一个事务的日志;它是一个多线程应用程序,因此func1的函数项对于所做的事务可以是随机的,但对于单个事务,它将仅通过func1、func2和func3顺序 func1(transactionId) { log("%d Now in func1", transactionId); } func2(transactionId) { log("%d Now in func2", transactionId); } func3(transacti

我有两个函数,每个函数都创建特定于一个事务的日志;它是一个多线程应用程序,因此func1的函数项对于所做的事务可以是随机的,但对于单个事务,它将仅通过func1、func2和func3顺序

func1(transactionId) {
     log("%d Now in func1", transactionId);
}

func2(transactionId) {
     log("%d Now in func2", transactionId);
}

func3(transactionId) {
     log("%d Now in func3", transactionId);
}
现在,我想一次只为每笔交易写一次logstash;就是

 1 Now in func1 Now in func2 Now in fun3
最后,这需要转到elasticsearch

我正在考虑将半个事务日志写入RabbitMQ临时队列,然后在完成事务后,将其提交给RabbitMQ生产者队列,以将消息发送到logstash

commit2RMQ执行logstash的时间应收到特定于要写入elasticsearch的事务的完整消息

问题:

  • 解决此问题的正确解决方案是将特定于事务的数据立即发送到elasticsearch
  • 我们可以用RabbitMQ解决这个问题吗?如果是这样,我需要使用什么样的API来实现这一点
  • 没有RabbitMQ,但只使用logstash和elasticsearch,有没有办法实现同样的效果
  • 我不想使用elasticsearch更新API,因为它可能会为特定于某个事务的每个日志消息消耗大量搜索操作
    尝试聚合与单个事务相关的不同日志行并不是一个简单的问题,特别是如果您将消息队列系统添加到混合中,作为要聚合的日志的中间存储。我会走另一条路,不涉及其他子系统,比如RabbitMQ

    此外,如果试图将多个日志行连接成一个日志行,则会丢失每个日志行可以提供的详细信息,例如每个函数执行所需的时间。如果
    func2
    分别
    func3
    引发异常,会发生什么情况?您是否应该存储仅由
    func1
    组成的部分日志,分别只存储
    func1
    func2

    我将要写的内容可能可以转换为任何语言和任何日志解决方案,但为了便于说明,我假设您的程序是用Java编写的,您使用的是Log4J

    因此,我将利用(MDC)在每个日志行中存储事务ID(以及可能的其他数据,如用户名等)。这样,您就可以轻松地检索与单个事务相关的所有日志行。这样做的好处是,您不必聚合任何内容,只需提供足够的上下文信息,以便Kibana稍后可以为您完成

    在伪代码中,您将事务ID直接添加到消息中。使用MDC而不是将ID记录到消息中的优点是,它可以避免在Logstash中解析所有消息,从而重新发现创建日志行时已经知道的事务ID

    因此,在您的代码中,只要您有一个事务ID,就可以将其添加到当前的每线程日志上下文中,如下所示:

    import org.apache.log4j.MDC;
    
    ...
    func1(transactionId) {
         // add the transaction ID to the logging context
         MDC.put("transactionID", transactionId);
         log("Now in func1");
    }
    
    func2(transactionId) {
         log("Now in func2");
    }
    
    func3(transactionId) {
         log("Now in func3");
    }
    
    然后在Log4J配置文件中,您可以使用
    %X{transactionID}
    模式指定appender来存储它,在本例中,我将在线程名称之后添加它,但您可以将它放在任何您喜欢的地方:

    log4j.appender.consoleAppender.layout.ConversionPattern = %d [%t] [%X{transactionID}] %5p %c - %m%n
    
    您的日志将类似于以下内容:

    2015-09-28T05:07:28.425Z [http-8084-2] [625562271762]  INFO YourClass - Now in func1
    2015-09-28T05:07:29.776Z [http-8084-2] [625562271762]  INFO YourClass - Now in func2
    2015-09-28T05:07:30.652Z [http-8084-2] [625562271762]  INFO YourClass - Now in func3
                                                  ^
                                                  |
                                      the transaction ID is here
    
    当您有这样的日志行时,通过Logstash
    grok
    过滤器检索事务ID并将其存储在日志存储索引中自己的
    transactionID
    字段中就很容易了。在Kibana中,您可以搜索事务ID并按时间戳desc排序,这样就可以显示该事务的所有上下文


    试试看

    尝试聚合与单个事务相关的不同日志行不是一个简单的问题,特别是如果您将消息队列系统添加到混合中,作为要聚合的日志的中间存储。我会走另一条路,不涉及其他子系统,比如RabbitMQ

    此外,如果试图将多个日志行连接成一个日志行,则会丢失每个日志行可以提供的详细信息,例如每个函数执行所需的时间。如果
    func2
    分别
    func3
    引发异常,会发生什么情况?您是否应该存储仅由
    func1
    组成的部分日志,分别只存储
    func1
    func2

    我将要写的内容可能可以转换为任何语言和任何日志解决方案,但为了便于说明,我假设您的程序是用Java编写的,您使用的是Log4J

    因此,我将利用(MDC)在每个日志行中存储事务ID(以及可能的其他数据,如用户名等)。这样,您就可以轻松地检索与单个事务相关的所有日志行。这样做的好处是,您不必聚合任何内容,只需提供足够的上下文信息,以便Kibana稍后可以为您完成

    在伪代码中,您将事务ID直接添加到消息中。使用MDC而不是将ID记录到消息中的优点是,它可以避免在Logstash中解析所有消息,从而重新发现创建日志行时已经知道的事务ID

    因此,在您的代码中,只要您有一个事务ID,就可以将其添加到当前的每线程日志上下文中,如下所示:

    import org.apache.log4j.MDC;
    
    ...
    func1(transactionId) {
         // add the transaction ID to the logging context
         MDC.put("transactionID", transactionId);
         log("Now in func1");
    }
    
    func2(transactionId) {
         log("Now in func2");
    }
    
    func3(transactionId) {
         log("Now in func3");
    }
    
    然后在Log4J配置文件中,您可以使用
    %X{transactionID}
    模式指定appender来存储它,在本例中,我将在线程名称之后添加它,但您可以将它放在任何您喜欢的地方:

    log4j.appender.consoleAppender.layout.ConversionPattern = %d [%t] [%X{transactionID}] %5p %c - %m%n
    
    您的日志将类似于以下内容:

    2015-09-28T05:07:28.425Z [http-8084-2] [625562271762]  INFO YourClass - Now in func1
    2015-09-28T05:07:29.776Z [http-8084-2] [625562271762]  INFO YourClass - Now in func2
    2015-09-28T05:07:30.652Z [http-8084-2] [625562271762]  INFO YourClass - Now in func3
                                                  ^
                                                  |
                                      the transaction ID is here
    
    当你有日志行李