zotregistry.dev/zot@v1.4.4-0.20240314164342-eec277e14d20/pkg/extensions/monitoring/minimal_client.go (about)

     1  //go:build !metrics
     2  // +build !metrics
     3  
     4  package monitoring
     5  
     6  import (
     7  	"context"
     8  	"crypto/tls"
     9  	"encoding/json"
    10  	"fmt"
    11  	"net/http"
    12  	"time"
    13  
    14  	"zotregistry.dev/zot/pkg/log"
    15  )
    16  
    17  const (
    18  	httpTimeout = 1 * time.Minute
    19  )
    20  
    21  // MetricsConfig is used to configure the creation of a Node Exporter http client
    22  // that will connect to a particular zot instance.
    23  type MetricsConfig struct {
    24  	// Address of the zot http server
    25  	Address string
    26  
    27  	// Transport to use for the http client.
    28  	Transport *http.Transport
    29  
    30  	// HTTPClient is the client to use.
    31  	HTTPClient *http.Client
    32  }
    33  
    34  type MetricsClient struct {
    35  	headers http.Header
    36  	config  MetricsConfig
    37  	log     log.Logger
    38  }
    39  
    40  func newHTTPMetricsClient() *http.Client {
    41  	defaultTransport := http.DefaultTransport.(*http.Transport).Clone()      //nolint: forcetypeassert
    42  	defaultTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} //nolint: gosec
    43  
    44  	return &http.Client{
    45  		Timeout:   httpTimeout,
    46  		Transport: defaultTransport,
    47  	}
    48  }
    49  
    50  // Creates a MetricsClient that can be used to retrieve in memory metrics
    51  // The new MetricsClient retrieved must be cached  and reused by the Node Exporter
    52  // in order to prevent concurrent memory leaks.
    53  func NewMetricsClient(config *MetricsConfig, logger log.Logger) *MetricsClient {
    54  	if config.HTTPClient == nil {
    55  		config.HTTPClient = newHTTPMetricsClient()
    56  	}
    57  
    58  	return &MetricsClient{config: *config, headers: make(http.Header), log: logger}
    59  }
    60  
    61  func (mc *MetricsClient) GetMetrics() (*MetricsInfo, error) {
    62  	metrics := &MetricsInfo{}
    63  	if _, err := mc.makeGETRequest(mc.config.Address+"/metrics", metrics); err != nil {
    64  		return nil, err
    65  	}
    66  
    67  	return metrics, nil
    68  }
    69  
    70  func (mc *MetricsClient) makeGETRequest(url string, resultsPtr interface{}) (http.Header, error) {
    71  	req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, url, nil)
    72  	if err != nil {
    73  		return nil, fmt.Errorf("metric scraping failed: %w", err)
    74  	}
    75  
    76  	resp, err := mc.config.HTTPClient.Do(req)
    77  	if err != nil {
    78  		return nil, fmt.Errorf("metric scraping failed: %w", err)
    79  	}
    80  
    81  	defer resp.Body.Close()
    82  
    83  	if err := json.NewDecoder(resp.Body).Decode(resultsPtr); err != nil {
    84  		return nil, fmt.Errorf("metric scraping failed: %w", err)
    85  	}
    86  
    87  	return resp.Header, nil
    88  }