package client import ( "context" "encoding/json" "fmt" "io/ioutil" "net/http" "time" "go.dev.pztrn.name/metricator/internal/logger" "go.dev.pztrn.name/metricator/pkg/schema" ) // Client is a Metricator client that is ready to be used in other applications // or libraries. type Client struct { config *Config logger *logger.Logger httpClient *http.Client } // NewClient creates new Metricator client. func NewClient(config *Config, logger *logger.Logger) *Client { // nolint:exhaustivestruct client := &Client{ config: config, logger: logger, } client.initialize() return client } // Executes request and parses it's contents. func (c *Client) executeAndParse(req *http.Request, dest interface{}) error { c.logger.Debugf("Executing HTTP request to %s%s", c.config.Host, req.URL.RequestURI()) ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*time.Duration(c.config.Timeout)) defer cancelFunc() req = req.WithContext(ctx) response, err := c.httpClient.Do(req) if err != nil { c.logger.Infoln("Failed to execute request to Metricator:", err.Error()) return fmt.Errorf("metricator client: %w", err) } defer response.Body.Close() respData, err := ioutil.ReadAll(response.Body) if err != nil { c.logger.Infoln("Failed to read response body:", err.Error()) return fmt.Errorf("metricator client: %w", err) } err = json.Unmarshal(respData, dest) if err != nil { c.logger.Infoln("Failed to parse response:", err.Error()) return fmt.Errorf("metricator client: %w", err) } return nil } // GetAppsList returns a slice with applications that was registered at Metricator. func (c *Client) GetAppsList() schema.AppsList { address := fmt.Sprintf("%s/api/v1/apps_list", c.config.Host) // Request's context sets in c.executeAndParse, so: // nolint:noctx req, err := http.NewRequest("GET", address, nil) if err != nil { c.logger.Infoln("Failed to create HTTP request:", err.Error()) return nil } appsList := make(schema.AppsList, 0) err = c.executeAndParse(req, &appsList) if err != nil { return nil } return appsList } // GetMetric returns value for metric. func (c *Client) GetMetric(appName, metricName string) interface{} { address := fmt.Sprintf("%s/api/v1/metrics/%s/%s", c.config.Host, appName, metricName) // Request's context sets in c.executeAndParse, so: // nolint:noctx req, err := http.NewRequest("GET", address, nil) if err != nil { c.logger.Infoln("Failed to create HTTP request:", err.Error()) return "" } var data interface{} err = c.executeAndParse(req, &data) if err != nil { return "" } return data } // GetMetricsList returns a slice with metrics names for passed application. func (c *Client) GetMetricsList(appName string) schema.Metrics { address := fmt.Sprintf("%s/api/v1/metrics/%s", c.config.Host, appName) // Request's context sets in c.executeAndParse, so: // nolint:noctx req, err := http.NewRequest("GET", address, nil) if err != nil { c.logger.Infoln("Failed to create HTTP request:", err.Error()) return nil } data := make(schema.Metrics, 0) err = c.executeAndParse(req, &data) if err != nil { return nil } return data } // Initializes internal states and storages. func (c *Client) initialize() { // We do not need to set everything for client actually, so: // nolint:exhaustivestruct c.httpClient = &http.Client{ Timeout: time.Second * time.Duration(c.config.Timeout), } }