根据manual:
Logback在
StatusManager
对象中收集其内部状态数据, 可通过LoggerContext
访问。给定
StatusManager
,您可以访问所有关联的状态数据 带有登录上下文。为了将内存使用率保持在合理水平, 默认的StatusManager
实现将状态消息存储在两个 分开的部分:标题部分和尾部。标头部分存储 前H个状态消息,而尾部则存储最后T个消息。目前,H = T = 150,尽管这些值在将来的版本中可能会更改。
目的似乎是允许侦听传入的日志消息,也可以通过servlet对其进行查看。
在本例中,我们使用logstash-logback-encoder并将Logback消息发送到控制台,以便fluentd / Filebeat等可以传送到远程Logstash-因此我们的微服务不需要检查或聆听它们。
所以问题是:我们是否可以/应该重写默认的BasicStatusManager(使用NOOP实现)以禁止这些消息的内部存储,或者有人知道Logstash编码器是依赖还是依赖于此地位机制本身?
我们的logback.xml
很简单:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="lsAppender" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>
<logger name="a.b.c" level="debug"/>
<root level="debug">
<appender-ref ref="lsAppender"/>
</root>
</configuration>
我第二发问的原因是,我们最近发现自己从具有120 MB堆的微服务中获取了OOME。当然,这些单独的日志消息太大了,但这仅是由Logback自身保留而不是被发送并遗忘的问题。这将是一个较少的可扩展性问题。
YourKit输出的屏幕截图:
答案 0 :(得分:0)
我最近又注意到了这一点。问题实际上与日志大小或日志吞吐量无关,并且无需以任何方式控制 StatusManager
的大小。
实际原因是 Logstash Logback Encoder(6.4 版)由于 Marker
无法编码而“无声地”失败:
import net.logstash.logback.marker.Markers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import java.util.HashMap;
@ControllerAdvice
public class MyExceptionHandler {
private static final Logger LOG = LoggerFactory.getLogger(MyExceptionHandler.class);
public void logException(Throwable e, WebRequest request) {
var fields = new HashMap<>();
fields.put("Request", request);
LOG.error(Markers.appendEntries(fields), "Error occurred", e);
}
}
WebRequest
是 org.springframework.web.context.request.ServletWebRequest
的一个实例,当编码器使用 jackson-databind 将其序列化为 JSON 时,会抛出一个 StackOverflowError
,该Coffee
会被所述编码器捕获并忽略.原始日志请求不会从内部 Logback 缓存中刷新。
考虑到足够多的此类错误,我们最终耗尽了内存。