github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/healthz/health.go (about)

     1  package healthz
     2  
     3  import (
     4  	"context"
     5  	"net/http"
     6  
     7  	"github.com/kyma-incubator/compass/components/director/pkg/log"
     8  	"github.com/pkg/errors"
     9  )
    10  
    11  const (
    12  	// UP missing godoc
    13  	UP = "UP"
    14  	// DOWN missing godoc
    15  	DOWN = "DOWN"
    16  )
    17  
    18  // Health missing godoc
    19  type Health struct {
    20  	ctx        context.Context
    21  	indicators []Indicator
    22  	config     map[string]IndicatorConfig
    23  }
    24  
    25  // New returns new health with the given context
    26  func New(ctx context.Context, healthCfg Config) (*Health, error) {
    27  	if err := healthCfg.Validate(); err != nil {
    28  		return nil, errors.Wrap(err, "An error has occurred while validating indicator config")
    29  	}
    30  
    31  	cfg := make(map[string]IndicatorConfig)
    32  	for _, i := range healthCfg.Indicators {
    33  		cfg[i.Name] = i
    34  	}
    35  
    36  	return &Health{
    37  		ctx:        ctx,
    38  		config:     cfg,
    39  		indicators: make([]Indicator, 0),
    40  	}, nil
    41  }
    42  
    43  // RegisterIndicator registers the provided indicator - if configuration for indicator with the same name is present,
    44  // it is used, otherwise a default indicator configuration is used
    45  func (h *Health) RegisterIndicator(ind Indicator) *Health {
    46  	cfg, ok := h.config[ind.Name()]
    47  	if !ok {
    48  		cfg = NewDefaultConfig()
    49  	}
    50  	ind.Configure(cfg)
    51  
    52  	h.indicators = append(h.indicators, ind)
    53  	return h
    54  }
    55  
    56  // Start will start all of the defined indicators.
    57  // Each of the indicators run in their own goroutines
    58  func (h *Health) Start() *Health {
    59  	for _, ind := range h.indicators {
    60  		ind.Run(h.ctx)
    61  	}
    62  	return h
    63  }
    64  
    65  // ReportStatus reports the status of all the indicators
    66  func (h *Health) ReportStatus() string {
    67  	state := UP
    68  	for _, ind := range h.indicators {
    69  		status := ind.Status()
    70  		if status.Error() != nil {
    71  			state = DOWN
    72  			log.C(h.ctx).Errorf("Reporting status DOWN for indicator: %s, error: %s, details: %s", ind.Name(), status.Error(), status.Details())
    73  		}
    74  	}
    75  
    76  	return state
    77  }
    78  
    79  // NewHealthHandler returns new health handler func with the provided health instance
    80  func NewHealthHandler(h *Health) func(writer http.ResponseWriter, request *http.Request) {
    81  	return func(writer http.ResponseWriter, request *http.Request) {
    82  		responseCode := http.StatusOK
    83  
    84  		state := h.ReportStatus()
    85  		if state == DOWN {
    86  			responseCode = http.StatusInternalServerError
    87  		}
    88  
    89  		writer.WriteHeader(responseCode)
    90  		if _, err := writer.Write([]byte(state)); err != nil {
    91  			log.C(request.Context()).WithError(err).Errorf("An error has occurred while writing to response body: %v", err)
    92  		}
    93  	}
    94  }