Spring启动,日志失败健康检查

标签 spring spring-boot kubernetes

我们在 kubernetes 中使用 spring-boot(2.5.6)

我们使用的许多依赖项包括健康检查,例如 RedisHealthIndicator、CouchbaseHealthIndicator 等

当其中一项运行状况检查失败并且整个应用程序运行状况失败时,Kubernetes 会重新启动 Pod。

但是没有任何迹象表明失败的原因,Spring 不会记录运行状况检查失败,而是依靠运行状况检查本身来记录消息。 内置运行状况检查并非如此。

因此从外部来看,kubernetes 似乎“无缘无故”地杀死了这个 pod,我们必须假设这是健康检查

Spring 是否有“运行状况检查更改事件”,以便我可以记录哪个 bean 失败?

或者以其他方式跟踪个人健康状况的“下降”情况

https://github.com/spring-projects/spring-boot/issues/22632 这个问题是类似的,但他们明确声明他们不会记录失败

最佳答案

我自己也曾为此奋斗过一段时间。我不确定他们为什么对记录健康故障采取这种立场,但更糟糕的是当前的实现对于尝试注入(inject)这种功能非常不友好。

最后,我决定解决的问题是包装健康贡献者,以便我可以在他们报告未启动时记录消息。包装器本身非常简单:

public class LoggingHealthIndicator implements HealthIndicator {
    private static final Logger LOG = LoggerFactory.getLogger(LoggingHealthIndicator.class);
    private final String name;
    private final HealthIndicator delegate;

    public LoggingHealthIndicator(final String name, final HealthIndicator delegate) {
        this.name = name;
        this.delegate = delegate;
    }

    @Override
    public Health health() {
        final Health health = delegate.health();

        if (!Status.UP.equals(health.getStatus())) {
            if (health.getDetails() == null || health.getDetails().isEmpty()) {
                LOG.error("Health check '{}' {}", name, health.getStatus());
            }
            else {
                LOG.error("Health check '{}' {}: {}", name, health.getStatus(), health.getDetails());
            }
        }

        return health;
    }
}

你当然可以做任何你想做的事;引发应用程序事件,进一步调整您记录的时间和内容等。随您喜欢。

就实际使用而言,这就是有点烦人的地方。它涉及用我们自己的增强版本替换 HealthContributorRegistry

    /**
     * Replicated from {@link org.springframework.boot.actuate.autoconfigure.health.HealthEndpointConfiguration}.
     *
     * Note that we lose the {@link org.springframework.boot.actuate.autoconfigure.health.HealthEndpointConfiguration.AdaptedReactiveHealthContributors},
     * since it is private. Technically its private to the package-scoped class it's a child of, so we lose twice really.
     */
    @Bean
    @SuppressWarnings("JavadocReference")
    public HealthContributorRegistry healthContributorRegistry(final Map<String, HealthContributor> contributors, final HealthEndpointGroups groups) {
        return new LoggingHealthContributorRegistry(contributors, groups.getNames());
    }    

public class LoggingHealthContributorRegistry extends AutoConfiguredHealthContributorRegistryCopy {

    private static HealthContributor loggingContributor(final Entry<String, HealthContributor> entry) {
        return loggingContributor(entry.getKey(), entry.getValue());
    }

    private static HealthContributor loggingContributor(final String name, final HealthContributor contributor) {
        if (contributor instanceof HealthIndicator){
            return new LoggingHealthIndicator(name, (HealthIndicator)contributor);
        }
        return contributor;
    }

    public LoggingHealthContributorRegistry(Map<String, HealthContributor> contributors, Collection<String> groupNames) {
        // The constructor does not use `registerContributor` on the input map entries
        super(contributors.entrySet().stream().collect(Collectors.toMap(Entry::getKey, LoggingHealthContributorRegistry::loggingContributor)),
              groupNames);
    }

    @Override
    public void registerContributor(String name, HealthContributor contributor) {
        super.registerContributor(name, loggingContributor(name, contributor));
    }
}

关于 AutoConfiguredHealthContributorRegistryCopy 的说明:它实际上只是 AutoConfiguredHealthContributorRegistry 类的副本,恰好是包范围的,因此不可继承(除非您不这样做)介意玩打包游戏)

关于Spring启动,日志失败健康检查,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71306918/

相关文章:

spring - 从 Spring Boot 应用程序访问 SessionFactory

spring - 使用 Spring 的 @Value 注入(inject) Map<String, List<String>>

java - 无论 Spring 数据源 URL 是在哪里指定的,如何读取它的值?

docker - 部署后如何让cron作业一次拉docker镜像?

linux - 使用 ssh 或 kubectl exec 的不同环境变量

Java Spring + Hibernate "Cannot add or update a child row"

java - Spring:为什么要有多个缓存

java - spring hibernate maven 项目出现 nosuchmethod 错误 InjectionMetadata

java - 如何解决自定义存储库 JPA 中的错误 "error in your SQL syntax"

ssl - 如何在 K8S 中配置服务以在 *_SERVICE_HOST 变量中设置主机名而不是 IP 地址