我在我们的环境中偶然发现了丢失的日志消息。
我们在 Java 应用程序中使用 ELK 堆栈和 logback 和 logstash-logback-encoder。为了进行结构化查询,我们使用 LogstashMarkers 将结构化参数附加到日志中。在丢失日志消息的情况下,它是一个包含 JSON 的字符串。
一些日志消息完全丢失。不仅没有保存标记,还保存了完整的日志消息。它们在 Kibana 中不可见。我们的应用程序或 logstash 服务器的日志中没有错误。
我可以用最少的代码创建一个示例存储库并将其发布在 GitHub 上:https ://github.com/seism0saurus/logging-issue
要运行它,您需要一个 logstash 服务器和 netcat。该项目中的记录器配置为使用控制台附加程序,因此我们有一个参考,即真正记录了哪些消息。此外,还有一个用于 localhost:8081 上的 netcat 服务器的附加程序和一个用于 logstash 服务器的附加程序。两者具有相同的配置。只是地址不同。所以我很确定消息会发送到logstash服务器,如果它是发送到netcat的话。
下面是主类的代码:
@SpringBootApplication
public class LoggingIssueApplication {
private static final Logger LOGGER = getLogger("customLogger");
private static final String MESSAGE = "{ \"ordernumber\": \"Test1\", \"shippingmethod\": \"homeDelivery\", \"customer\": { \"id\": \"1337\", \"salutation\": \"Mr\", \"name\": \"seism0saurus\", \"birthdate\": \"1900-05-01\", \"email\": \"test@seism0saurus.de\", \"phone\": \"\" }, \"billingAddress\": { \"name\": \"seism0saurus\", \"address\": \"Teststreet 5\", \"address2\": \"\", \"postcode\": \"90451\", \"city\": \"Nürnberg\", \"country\": \"Deutschland\", \"countrycode\": \"DEU\" }, \"shippingAddress\": { \"name\": \"seism0saurus\", \"address\": \"Teststreet 5\", \"address2\": \"\", \"postcode\": \"90451\", \"city\": \"Nürnberg\", \"country\": \"Deutschland\", \"countrycode\": \"DEU\" }, \"totalItems\": 1, \"items\": [ { \"position\": 53, \"bundlenumber\": 53, \"itemnumber\": \"900508\", \"itemdescription\": \"Dinosaur Cookies\", \"quantity\": 4, \"saleType\": \"KL\", \"saleItemType\": \"\", \"grossAmount\": 40.0, \"discounts\": [ ] } ]}";
public static void main(String[] args) {
SpringApplication.run(LoggingIssueApplication.class, args);
}
@EventListener(ApplicationReadyEvent.class)
public void testAppender() throws InterruptedException {
LOGGER.warn("1 - Log without marker and message as parameter: {}", MESSAGE);
LogstashMarker payloadMarker = Markers.append("payload", MESSAGE);
LOGGER.warn(payloadMarker, "2 - Log with payload marker without parameter");
LOGGER.warn(payloadMarker, "3 - Log with payload marker and message as parameter: {}", MESSAGE);
LogstashMarker rawMarker = Markers.appendRaw("raw", MESSAGE);
LOGGER.warn(rawMarker, "4 - Log with raw marker without parameter");
//Needed, so the loggers can finish their job before the application is shut down.
Thread.sleep(5000);
}
}
这是 logstash 附加程序:
<appender name="nc" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>localhost:8081</destination>
<keepAliveDuration>5 minutes</keepAliveDuration>
<listener class="net.logstash.logback.appender.listener.FailureSummaryLoggingAppenderListener"/>
<encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<mdc/>
<context/>
<version/>
<logLevel/>
<logLevelValue/>
<loggerName/>
<pattern>
<pattern>
{
"serviceName": "logging-issue",
"environment": "dev",
"errorMessage": "%ex{0}"
}
</pattern>
</pattern>
<threadName/>
<message/>
<logstashMarkers/>
<arguments/>
<stackTrace/>
</providers>
</encoder>
</appender>
当我运行应用程序时,我收到了预期的 4 条日志消息。所有 4 都出现在控制台和 netcat 服务器中。但只有数字 1 和 4 出现在 kibana 中。因此,我假设处理Markers.append
和Markers.appendRaw
. MESSAGE
是一个包含 JSON 的字符串。但我希望,我不必检查字符串的内容来决定调用哪个方法。
logstash 服务器的日志中没有错误消息。它似乎不是连接错误、未知或不可访问的主机或完整的缓冲区。我重现了所有这些案例,它们在日志中留下了有意义的错误消息。
你知道吗,这里会发生什么?我是否必须检查要放入标记的字符串的内容以防止丢失完整的日志消息?
编辑:我得到了关于这个问题的更多信息。我本地机器上 docker 内的 logstash 实例确实接收所有日志并将它们写入具有以下管道的文件。
input {
tcp {
port => 9000
codec => json_lines
}
}
output {
file {
path => "/mounted_dir/logstash.out"
codec => line {
format => "%{message}"
}
}
}
编辑 2:基于https://jaxenter.de/elastic-stack-containern-docker-86374我构建了一个完整的 ELK 堆栈进行比较。它不会丢失任何日志消息。因此,我们的管理员构建了 ELK 堆栈的问题所在。你有什么想法?