metricator/pkg/client/client.go

148 lines
3.4 KiB
Go

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),
}
}