github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/vvm/metrics/impl.go (about)

     1  /*
     2   * Copyright (c) 2022-present unTill Pro, Ltd.
     3   */
     4  
     5  package metrics
     6  
     7  import (
     8  	"context"
     9  	"errors"
    10  	"fmt"
    11  	"net"
    12  	"net/http"
    13  
    14  	"github.com/voedger/voedger/pkg/goutils/logger"
    15  
    16  	imetrics "github.com/voedger/voedger/pkg/metrics"
    17  	coreutils "github.com/voedger/voedger/pkg/utils"
    18  )
    19  
    20  func (ms *metricsService) Prepare(interface{}) (err error) {
    21  	ms.listener, err = net.Listen("tcp", coreutils.ServerAddress(ms.port))
    22  	return err
    23  }
    24  
    25  func (ms *metricsService) Run(_ context.Context) {
    26  	logger.Info("Starting Metrics Service on", ms.listener.Addr().(*net.TCPAddr).String())
    27  	if err := ms.Serve(ms.listener); !errors.Is(err, http.ErrServerClosed) {
    28  		panic("metrics service failure: " + err.Error())
    29  	}
    30  }
    31  
    32  func (ms *metricsService) Stop() {
    33  	// context here is used to avoid infinite awaiting for all connections close
    34  	// we want to all connections to close, so we provide context which is not cancelled
    35  	if err := ms.Shutdown(context.Background()); err != nil {
    36  		logger.Error("metrics service shutdown failed: ", err)
    37  	}
    38  }
    39  
    40  func (ms *metricsService) GetPort() int {
    41  	return ms.listener.Addr().(*net.TCPAddr).Port
    42  }
    43  
    44  func provideHandler(metrics imetrics.IMetrics) http.HandlerFunc {
    45  	return func(rw http.ResponseWriter, r *http.Request) {
    46  		isCheck := r.URL.Path == "/metrics/check"
    47  
    48  		if (r.URL.Path != "/metrics" && !isCheck) || r.Method != http.MethodGet {
    49  			http.Error(rw, "404 not found", http.StatusNotFound)
    50  			return
    51  		}
    52  
    53  		if isCheck {
    54  			rw.WriteHeader(http.StatusOK)
    55  			if _, err := rw.Write([]byte("ok")); err != nil {
    56  				logger.Error("metrics service: failed to reply check ok: ", err)
    57  			}
    58  			return
    59  		}
    60  
    61  		err := metrics.List(func(metric imetrics.IMetric, metricValue float64) (err error) {
    62  			if _, err = rw.Write(imetrics.ToPrometheus(metric, metricValue)); err != nil {
    63  				return fmt.Errorf("metrics service: failed to write metric %s for app %s on VVM %s: %w", metric.Name(), metric.App(), metric.Vvm(), err)
    64  			}
    65  			return
    66  		})
    67  		if err != nil {
    68  			logger.Error(err)
    69  			rw.WriteHeader(http.StatusInternalServerError)
    70  		}
    71  	}
    72  }