【问题标题】:Stop Spring Boot application when logging fails (log4j2)记录失败时停止 Spring Boot 应用程序 (log4j2)
【发布时间】:2020-09-17 09:07:35
【问题描述】:

我有一个标准的 Spring Boot 微服务,它使用 Log4j2 进行所有日志记录。

如果日志记录失败(例如磁盘已满),我想正常关闭 Spring Boot 应用程序。有办法设置吗?

参考资料: How to handle disk full errors while logging in logback? --> 这个问题没有回答这个特定的问题。 https://logging.apache.org/log4j/2.x/manual/appenders.html#FailoverAppender --> 阅读 FailoverAppender 的文档,我不确定这是否符合要求。

【问题讨论】:

    标签: spring-boot security logging log4j2


    【解决方案1】:

    我想您需要做的是通过其他机制检测剩余磁盘,而不是依靠记录器来检测它。 Spring Boot actuator 用于提供许多指标,包括内存和磁盘。它使外部服务能够通过 HTTP 端点从正在运行的实例获取指标。

    在这里查看执行器如何获取磁盘空间:https://github.com/spring-projects/spring-boot/blob/v2.3.3.RELEASE/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/system/DiskSpaceHealthIndicator.java 说明机制很简单:

    @Override
    protected void doHealthCheck(Health.Builder builder) throws Exception {
        long diskFreeInBytes = this.path.getUsableSpace();
        if (diskFreeInBytes >= this.threshold.toBytes()) {
            builder.up();
        }
        else {
            logger.warn(LogMessage.format("Free disk space below threshold. Available: %d bytes (threshold: %s)",
                    diskFreeInBytes, this.threshold));
            builder.down();
        }
        builder.withDetail("total", this.path.getTotalSpace()).withDetail("free", diskFreeInBytes)
                .withDetail("threshold", this.threshold.toBytes()).withDetail("exists", this.path.exists());
    }
    

    在您的主应用程序类中,您可以定期检查磁盘空间并在磁盘空间低于特定阈值时关闭应用程序上下文,使用与上述相同的机制。关闭应用程序可以是这样的:

    int exitCode = SpringApplication.exit(ctx, new ExitCodeGenerator() {
    @Override
    public int getExitCode() {
            // return the error code
            return 0;
        }
    });
    
     
    System.exit(exitCode);
    

    【讨论】:

    • 感谢您的评论。但是,日志记录失败可能不仅仅是因为磁盘错误。我给出的磁盘已满只是一个例子
    【解决方案2】:

    每个 Appender 都由 Log4j 2 中的 AppenderControl 包装。AppenderControl 捕获 Appender 抛出的任何异常。它的默认行为是获取附加到 Appender 的错误处理程序并调用其 error() 方法。当该方法返回时,它将检查属性“ignoreExceptions”是否为假(默认为真),如果是,则重新抛出异常。

    理想情况下,您可以实现自己的错误处理程序,除非编写该代码的人(我)忘记使其可配置。见https://issues.apache.org/jira/browse/LOG4J2-2927

    FailoverAppender 旨在包装一个 appender,然后在发生错误时故障转移到另一个 appender。这需要在目标 appender 上将 ignoreExceptions 设置为 false。您可以复制 FailoverAppender 来创建您自己的自定义 appender,当错误发生时执行关闭。

    【讨论】:

      【解决方案3】:

      Spring boot 附带一个执行器,该执行器具有(默认禁用)shutdown 端点。 基本上,启用此端点时,允许通过 JMX 或 HTTP 关闭 Spring Boot 应用程序。这是迄今为止我所知道的优雅关闭 Spring Boot 应用程序的最佳方式。

      这个端点的源代码是可用的here,你可以很容易地看到它在应用程序上下文中调用了close方法。

      现在回答您的问题,我从未使用过 log4j2,但作为一个想法,您可以创建自己的 appender 来包装分配给记录器的真正 appender,它可以捕获异常并调用 close 方法(在这种情况下,它还必须维护对应用程序上下文的引用)或通过 JMX 调用 shutdown 端点。这可以“补充”@rgoers 提供的答案,他们从 log4j2 的角度解决了这个问题。

      【讨论】:

        猜你喜欢
        • 2015-09-02
        • 1970-01-01
        • 2020-02-21
        • 2017-05-12
        • 2019-02-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多