Springboot Actuator之五:Springboot中的HealthAggregator、新增自定義Status

springboot的actuator內置了/health的endpoint,很方便地規範了每一個服務的健康情況的api,並且HealthIndicator能夠本身去擴展,增長相關依賴服務的健康狀態,很是靈活方便並且可擴展。php

/health實例

{
  "status": "UP",
  "custom": {
    "status": "UNKNOWN",
    "custom": {
      "status": "UNKNOWN",
      "msg": "mock down to test aggregator"
    }
  },
  "diskSpace": {
    "status": "UP",
    "total": 249779191808,
    "free": 57925111808,
    "threshold": 10485760
  }
}

health的Status枚舉

org.springframework.boot.actuate.health.Status.javajava

@JsonInclude(Include.NON_EMPTY)
public final class Status {

    /**
     * {@link Status} indicating that the component or subsystem is in an unknown state.
     */
    public static final Status UNKNOWN = new Status("UNKNOWN");

    /**
     * {@link Status} indicating that the component or subsystem is functioning as
     * expected.
     */
    public static final Status UP = new Status("UP");

    /**
     * {@link Status} indicating that the component or subsystem has suffered an
     * unexpected failure.
     */
    public static final Status DOWN = new Status("DOWN");

    /**
     * {@link Status} indicating that the component or subsystem has been taken out of
     * service and should not be used.
     */
    public static final Status OUT_OF_SERVICE = new Status("OUT_OF_SERVICE");

 

對多個Status的聚合

對於多個HealthIndicator的status,spring boot默認對其進行aggregrate,而後計算最頂層的status字段的值,並且對於status是DOWN或者是OUT_OF_SERVICE的,返回的http的狀態碼是503,這對於應用監控系統來講真是大大的貼心啊,再總結一下:git

  • 自動聚合多個HealthIndicator的status
  • 對於status是DOWN或者是OUT_OF_SERVICE的,返回503

這樣應用監控系統一來就無需去解析返回結果,直接根據http的狀態碼就能夠判斷了,很是方便,太省心了有沒有。spring

看看AbstractHealthAggregator.java的抽象類,其中對狀態的聚合是abstract的。api

public abstract class AbstractHealthAggregator implements HealthAggregator {

    @Override
    public final Health aggregate(Map<String, Health> healths) {
        List<Status> statusCandidates = new ArrayList<Status>();
        for (Map.Entry<String, Health> entry : healths.entrySet()) {
            statusCandidates.add(entry.getValue().getStatus());
        }
        Status status = aggregateStatus(statusCandidates);
        Map<String, Object> details = aggregateDetails(healths);
        return new Health.Builder(status, details).build();
    }

    /**
     * Return the single 'aggregate' status that should be used from the specified
     * candidates.
     * @param candidates the candidates
     * @return a single status
     */
    protected abstract Status aggregateStatus(List<Status> candidates);

    /**
     * Return the map of 'aggregate' details that should be used from the specified
     * healths.
     * @param healths the health instances to aggregate
     * @return a map of details
     * @since 1.3.1
     */
    protected Map<String, Object> aggregateDetails(Map<String, Health> healths) {
        return new LinkedHashMap<String, Object>(healths);
    }

} 

自定義Status,以及對Status聚合邏輯的調整

重寫參考了OrderedHealthAggregator類,增長了 GIT_WARNING
public class OrderedHealthAggregator extends AbstractHealthAggregator {

    private List<String> statusOrder;
    
    public static final Status GIT_WARNING = new Status("GIT_WARNING", "警告:config-server連不上gitlab,請及時處理.");

    /**
     * Create a new {@link OrderedHealthAggregator} instance.
     */
    public OrderedHealthAggregator() {
        setStatusOrder(Status.DOWN, Status.OUT_OF_SERVICE, GIT_WARNING,  Status.UP, Status.UNKNOWN);
    }

    /**
     * Set the ordering of the status.
     * @param statusOrder an ordered list of the status
     */
    public void setStatusOrder(Status... statusOrder) {
        String[] order = new String[statusOrder.length];
        for (int i = 0; i < statusOrder.length; i++) {
            order[i] = statusOrder[i].getCode();
        }
        setStatusOrder(Arrays.asList(order));
    }

    /**
     * Set the ordering of the status.
     * @param statusOrder an ordered list of the status codes
     */
    public void setStatusOrder(List<String> statusOrder) {
        Assert.notNull(statusOrder, "StatusOrder must not be null");
        this.statusOrder = statusOrder;
    }

    @Override
    protected Status aggregateStatus(List<Status> candidates) {
        // Only sort those status instances that we know about
        List<Status> filteredCandidates = new ArrayList<Status>();
        for (Status candidate : candidates) {
            //只識別Status.DOWN, Status.OUT_OF_SERVICE, GIT_WARNING,  Status.UP, Status.UNKNOWN幾種狀態
            if (this.statusOrder.contains(candidate.getCode())) {
                filteredCandidates.add(candidate);
            }
        }
        // If no status is given return UNKNOWN
        if (filteredCandidates.isEmpty()) {
            return Status.UNKNOWN;
        }
        //對多個結果狀態的排序,按照各個狀態在statusOrder集合中的位置排序
        Collections.sort(filteredCandidates, new StatusComparator(this.statusOrder));
        
        //返回排在最上面的那個狀態值
        return filteredCandidates.get(0);
    }

    /**
     * {@link Comparator} used to order {@link Status}.
     */
    private class StatusComparator implements Comparator<Status> {

        private final List<String> statusOrder;

        StatusComparator(List<String> statusOrder) {
            this.statusOrder = statusOrder;
        }

        @Override
        public int compare(Status s1, Status s2) {
            //對多個結果狀態的排序,按照各個狀態在statusOrder集合中的位置排序
            int i1 = this.statusOrder.indexOf(s1.getCode());
            int i2 = this.statusOrder.indexOf(s2.getCode());
            return (i1 < i2 ? -1 : (i1 == i2 ? s1.getCode().compareTo(s2.getCode()) : 1));
        }

    }

}

 即Status.DOWN, Status.OUT_OF_SERVICE, GIT_WARNING, Status.UP, Status.UNKNOWN優先級依次遞減。status中一旦有出現DOWN的狀況,總體的status就是DOWN,依次類推。springboot

相關文章
相關標籤/搜索