All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.netflix.genie.web.aspects.HealthCheckMetricsAspect Maven / Gradle / Ivy

There is a newer version: 4.3.20
Show newest version
/*
 *
 *  Copyright 2017 Netflix, Inc.
 *
 *     Licensed under the Apache License, Version 2.0 (the "License");
 *     you may not use this file except in compliance with the License.
 *     You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *     Unless required by applicable law or agreed to in writing, software
 *     distributed under the License is distributed on an "AS IS" BASIS,
 *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *     See the License for the specific language governing permissions and
 *     limitations under the License.
 *
 */
package com.netflix.genie.web.aspects;

import com.google.common.collect.ImmutableSet;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.Status;

import java.util.Arrays;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Aspect around Spring Boot 'HealthIndicator' to publish metrics for status of individual indicator, as well as their
 * turnaround time.
 *
 * @author mprimi
 * @since 3.2.4
 */
@Aspect
@Slf4j
public class HealthCheckMetricsAspect {

    static final String HEALTH_INDICATOR_TIMER_METRIC_NAME = "genie.health.indicator.timer";
    private static final String HEALTH_INDICATOR_CLASS_TAG_NAME = "healthIndicatorClass";
    private static final String HEALTH_INDICATOR_STATUS_TAG_NAME = "healthIndicatorStatus";

    private final MeterRegistry registry;

    /**
     * Autowired constructor.
     *
     * @param registry metrics registry
     */
    public HealthCheckMetricsAspect(final MeterRegistry registry) {
        this.registry = registry;
    }

    /**
     * Pointcut that matches invocations of {@code HealthIndicator::getHealth(..)}.
     */
    @Pointcut(""
        + "target(org.springframework.boot.actuate.health.HealthIndicator+) && "
        + "execution(org.springframework.boot.actuate.health.Health getHealth(..))"
    )
    public void healthIndicatorGetHealth() {
    }

    /**
     * Aspect around join point for {@code HealthIndicator::getHealth(..)}.
     * Measures the turnaround time for the indicator call and publishes it as metric, tagged with indicator class
     * and the status reported.
     *
     * @param joinPoint the join point
     * @return health as reported by the indicator
     * @throws Throwable in case of exception in the join point
     */
    @Around("healthIndicatorGetHealth()")
    @SuppressWarnings("checkstyle:IllegalThrows") // For propagating Throwable from joinPoint.proceed()
    public Health aroundHealthIndicatorGetHealth(final ProceedingJoinPoint joinPoint) throws Throwable {
        final String healthIndicatorClass = joinPoint.getTarget().getClass().getSimpleName();
        log.debug(
            "Intercepted: {}::{}({})",
            healthIndicatorClass,
            joinPoint.getSignature().getName(),
            Arrays.toString(joinPoint.getArgs())
        );

        final long start = System.nanoTime();
        Health h = null;
        try {
            h = (Health) joinPoint.proceed(joinPoint.getArgs());
        } finally {
            final long turnaround = System.nanoTime() - start;
            final String healthStatus = (h != null) ? h.getStatus().getCode() : Status.UNKNOWN.getCode();

            log.debug("Indicator {} status: {} (took {}ns)", healthIndicatorClass, healthStatus, turnaround);

            final Set tags = ImmutableSet.of(
                Tag.of(HEALTH_INDICATOR_CLASS_TAG_NAME, healthIndicatorClass),
                Tag.of(HEALTH_INDICATOR_STATUS_TAG_NAME, healthStatus)
            );
            this.registry
                .timer(HEALTH_INDICATOR_TIMER_METRIC_NAME, tags)
                .record(turnaround, TimeUnit.NANOSECONDS);
        }
        return h;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy