使用log4j2的Spring Boot写入日志太慢

时间:2019-07-12 04:28:13

标签: spring-boot log4j2

我正在Spring Boot应用程序中使用log4j2进行异步日志记录。 这是我的配置log4j2-dev.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="30">
<Properties>
    <Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight{%5p}--[%T-%-15.15t] [%-20X{serviceMessageId}]%-40.40c{1.} :%m%n%ex</Property>
</Properties>
<Appenders>
    <Console name="ConsoleAppender" target="SYSTEM_OUT"
        follow="true">
        <PatternLayout pattern="${LOG_PATTERN}" />
    </Console>
    <!-- Rolling File Appender -->
    <RollingFile name="FileAppender" fileName="logs/app.log"
        filePattern="logs/app-%d{yyyy-MM-dd}-%i.log">
        <PatternLayout>
            <Pattern>${LOG_PATTERN}</Pattern>
        </PatternLayout>
        <Policies>
            <SizeBasedTriggeringPolicy size="100MB" />
        </Policies>
        <DefaultRolloverStrategy max="10" />
    </RollingFile>
    <Kafka name="KafkaAppender" topic="ServiceCentrallog">
        <Property name="bootstrap.servers">10.2.16.2:9092,10.2.16.3:9092,10.2.16.4:9092</Property>
        <JSONLayout compact="true" properties="true">
            <KeyValuePair key="application"
                value="${bundle:application-dev:spring.application.name}" />
        </JSONLayout>
    </Kafka>
</Appenders>
<Loggers>
    <AsyncRoot level="info">
        <AppenderRef ref="ConsoleAppender" />
        <AppenderRef ref="FileAppender" />
        <AppenderRef ref="KafkaAppender" />
    </AsyncRoot>
</Loggers>

我在Project中的BaseClass

public abstract class BaseObject {
protected final org.apache.logging.log4j.Logger logger = LogManager.getLogger(getClass());

@Override
public String toString() {
    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
    String jsonString = "";
    try {
        jsonString = mapper.writeValueAsString(this);
    } catch (JsonProcessingException e) {
        logger.error("BaseObject: ", e);
        jsonString = "Can't build json from object";
    }
    return jsonString;
}
}

这是我写日志的方法:

logger.info("Input: " + input.toString());
....
logger.info("output: " + Utils.toJson(restRes));

在正常情况下可以正常工作。 但是,如果我使用Jmetter发送大量请求(总计:7996,AVG:98消息/秒) 我发现日志记录速度太慢,在停止发送请求大约1.5分钟后,日志记录仍然继续并且日志文件的容量仍在增加。

我进行了很多搜索,但是仍然不知道如何加快日志记录速度,或者发现配置不合理的地方。

1 个答案:

答案 0 :(得分:2)

  

但是,如果我使用Jmetter发送大量请求(总计:7996,AVG:   98条消息)停止发送后,我发现日志记录太慢   请求大约1.5分钟,日志记录仍然继续并记录   文件的容量仍在增加。

您正在使用Log4J2的异步日志记录。其目的是在记录操作期间不阻塞正在执行的线程。因此,如果您的应用程序在几分钟之内记录了很多事情(7996 * 98条消息),那么这种行为是完全可以理解的:消息越来越多地排在队列中,直到最后一条消息都要花一些时间。

  

我进行了很多搜索,但仍然不知道如何加快记录速度,   或找出我的配置不合理的地方。

1)使用同步日志记录将使用阻塞方法来加快您的日志记录速度:只有在将消息有效地记录在附加程序中时,日志记录调用才会返回,但也会影响处理速度。

2)在这种情况下(即记录请求/响应),请勿使用 3个附加器

<AsyncRoot level="info">
    <AppenderRef ref="ConsoleAppender" />
    <AppenderRef ref="FileAppender" />
    <AppenderRef ref="KafkaAppender" />
 </AsyncRoot>

它执行三次日志。好多
如果您确实需要记录这些信息,请将它们记录在一个附加程序中。您可以使用过滤器功能轻松实现这一目标(MarkerFilter应该没问题)。
例如,在您登录时添加标记JSON_REQUEST_RESPONSE,并指定只有一个附加程序(如果存在)记录它,而其他任何情况下都不记录:

<RollingFile name="FileAppender" fileName="logs/app.log"
    filePattern="logs/app-%d{yyyy-MM-dd}-%i.log">
  <!-- ACCEPT Marker-->
  <MarkerFilter marker="JSON_REQUEST_RESPONSE" onMatch="ACCEPT" />
  <...>
</RollingFile>

<Console name="ConsoleAppender" target="SYSTEM_OUT"
    follow="true">
  <!-- DENY Marker-->
  <MarkerFilter marker="JSON_REQUEST_RESPONSE" onMatch="DENY" />
  <...>
</Console>

3)不要在info()中记录太多:

logger.info("Input: " + input.toString());
....
logger.info("output: " + Utils.toJson(restRes));

请注意,请勿使用串联进行记录,因为如果记录器级别不匹配且未记录任何内容,那么这样做代价不菲。
在这种情况下,采用Supplier的{​​{3}}更好:

logger.info("Input: {}", () -> input.toString());
....
logger.info("output: {}", () -> Utils.toJson(restRes));