Compare commits
No commits in common. "master" and "v0.2.0" have entirely different histories.
43
.drone.yml
43
.drone.yml
@ -1,43 +0,0 @@
|
|||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
type: docker
|
|
||||||
name: build
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: lint
|
|
||||||
image: code.pztrn.name/containers/mirror/golangci/golangci-lint:v1.46.2
|
|
||||||
environment:
|
|
||||||
CGO_ENABLED: 0
|
|
||||||
commands:
|
|
||||||
- golangci-lint run
|
|
||||||
|
|
||||||
- name: test
|
|
||||||
image: code.pztrn.name/containers/mirror/golang:1.18.3-alpine
|
|
||||||
environment:
|
|
||||||
CGO_ENABLED: 0
|
|
||||||
commands:
|
|
||||||
- go test ./...
|
|
||||||
|
|
||||||
- name: build master image
|
|
||||||
image: code.pztrn.name/containers/mirror/plugins/docker:20.13.0
|
|
||||||
when:
|
|
||||||
branch: ["master"]
|
|
||||||
settings:
|
|
||||||
registry: code.pztrn.name
|
|
||||||
username: drone
|
|
||||||
password:
|
|
||||||
from_secret: drone_secret
|
|
||||||
repo: code.pztrn.name/apps/metricator
|
|
||||||
auto_tag: true
|
|
||||||
|
|
||||||
- name: build tagged image
|
|
||||||
image: code.pztrn.name/containers/mirror/plugins/docker:20.13.0
|
|
||||||
when:
|
|
||||||
event: ["tag"]
|
|
||||||
settings:
|
|
||||||
registry: code.pztrn.name
|
|
||||||
username: drone
|
|
||||||
password:
|
|
||||||
from_secret: drone_secret
|
|
||||||
repo: code.pztrn.name/apps/metricator
|
|
||||||
auto_tag: true
|
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,3 @@
|
|||||||
._bin
|
._bin
|
||||||
.vscode
|
.vscode
|
||||||
metricator.yaml
|
metricator.yaml
|
||||||
.idea
|
|
||||||
*DS_Store*
|
|
||||||
|
@ -9,15 +9,11 @@ linters:
|
|||||||
- gomnd
|
- gomnd
|
||||||
# Why? WHY? WHY _test???
|
# Why? WHY? WHY _test???
|
||||||
- testpackage
|
- testpackage
|
||||||
# Structs will contain some context.Context.
|
|
||||||
- containedctx
|
|
||||||
# Deprecated
|
|
||||||
- exhaustivestruct
|
|
||||||
linters-settings:
|
linters-settings:
|
||||||
lll:
|
lll:
|
||||||
line-length: 120
|
line-length: 120
|
||||||
cyclop:
|
gocyclo:
|
||||||
max-complexity: 40
|
min-complexity: 40
|
||||||
gocognit:
|
gocognit:
|
||||||
min-complexity: 40
|
min-complexity: 40
|
||||||
funlen:
|
funlen:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
FROM code.pztrn.name/containers/mirror/golang:1.18.3-alpine AS build
|
FROM registry.gitlab.pztrn.name/containers/mirror/golang:1.15.5-alpine AS build
|
||||||
|
|
||||||
WORKDIR /go/src/gitlab.pztrn.name/pztrn/metricator
|
WORKDIR /go/src/gitlab.pztrn.name/pztrn/metricator
|
||||||
COPY . .
|
COPY . .
|
||||||
@ -13,7 +13,7 @@ RUN apk add bash git make
|
|||||||
RUN make metricatord-build
|
RUN make metricatord-build
|
||||||
RUN make metricator-client-build
|
RUN make metricator-client-build
|
||||||
|
|
||||||
FROM code.pztrn.name/containers/mirror/golang:1.18.3-alpine
|
FROM registry.gitlab.pztrn.name/containers/mirror/golang:1.15.5-alpine
|
||||||
LABEL maintainer="Stanislav N. <pztrn@pztrn.name>"
|
LABEL maintainer="Stanislav N. <pztrn@pztrn.name>"
|
||||||
|
|
||||||
COPY --from=build /go/src/gitlab.pztrn.name/pztrn/metricator/._bin/metricatord /usr/local/bin/metricatord
|
COPY --from=build /go/src/gitlab.pztrn.name/pztrn/metricator/._bin/metricatord /usr/local/bin/metricatord
|
||||||
|
@ -25,9 +25,6 @@ var (
|
|||||||
output = flag.String("output", "json", "Output format. Can be 'json' or 'plain-by-line'.")
|
output = flag.String("output", "json", "Output format. Can be 'json' or 'plain-by-line'.")
|
||||||
)
|
)
|
||||||
|
|
||||||
// This function uses fmt.Println to print lines without timestamps to make it easy
|
|
||||||
// to parse output, so:
|
|
||||||
// nolint:forbidigo
|
|
||||||
func main() {
|
func main() {
|
||||||
config := configuration.NewConfig()
|
config := configuration.NewConfig()
|
||||||
|
|
||||||
@ -86,17 +83,17 @@ func main() {
|
|||||||
Timeout: *metricatorTimeout,
|
Timeout: *metricatorTimeout,
|
||||||
}
|
}
|
||||||
|
|
||||||
clnt := client.NewClient(clientConfig, logger)
|
c := client.NewClient(clientConfig, logger)
|
||||||
|
|
||||||
var data interface{}
|
var data interface{}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case *appsList:
|
case *appsList:
|
||||||
data = clnt.GetAppsList()
|
data = c.GetAppsList()
|
||||||
case *metricsList:
|
case *metricsList:
|
||||||
data = clnt.GetMetricsList(*application)
|
data = c.GetMetricsList(*application)
|
||||||
case *metric != "":
|
case *metric != "":
|
||||||
data = clnt.GetMetric(*application, *metric)
|
data = c.GetMetric(*application, *metric)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch *output {
|
switch *output {
|
||||||
|
@ -29,7 +29,8 @@ func main() {
|
|||||||
// Parse configuration.
|
// Parse configuration.
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if err := config.Parse(); err != nil {
|
err := config.Parse()
|
||||||
|
if err != nil {
|
||||||
log.Fatalln("Failed to parse configuration:", err.Error())
|
log.Fatalln("Failed to parse configuration:", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,18 +28,16 @@ type Application struct {
|
|||||||
|
|
||||||
// NewApplication creates new application.
|
// NewApplication creates new application.
|
||||||
func NewApplication(ctx context.Context, name string, config *Config, logger *logger.Logger) *Application {
|
func NewApplication(ctx context.Context, name string, config *Config, logger *logger.Logger) *Application {
|
||||||
// Some variables are initialized in initialize() function.
|
a := &Application{
|
||||||
// nolint:exhaustruct
|
|
||||||
app := &Application{
|
|
||||||
config: config,
|
config: config,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
doneChan: make(chan struct{}),
|
doneChan: make(chan struct{}),
|
||||||
logger: logger,
|
logger: logger,
|
||||||
name: name,
|
name: name,
|
||||||
}
|
}
|
||||||
app.initialize()
|
a.initialize()
|
||||||
|
|
||||||
return app
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDoneChan returns a channel which should be used to block execution until
|
// GetDoneChan returns a channel which should be used to block execution until
|
||||||
|
@ -11,6 +11,5 @@ type Config struct {
|
|||||||
Endpoint string `yaml:"endpoint"`
|
Endpoint string `yaml:"endpoint"`
|
||||||
// TimeBetweenRequests is a minimal amount of time which should pass
|
// TimeBetweenRequests is a minimal amount of time which should pass
|
||||||
// between requests.
|
// between requests.
|
||||||
// nolint:tagliatelle
|
|
||||||
TimeBetweenRequests time.Duration `yaml:"time_between_requests"`
|
TimeBetweenRequests time.Duration `yaml:"time_between_requests"`
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package application
|
package application
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -10,9 +11,6 @@ func (a *Application) fetch() {
|
|||||||
// Do not do anything if fetching is running.
|
// Do not do anything if fetching is running.
|
||||||
// ToDo: maybe another approach?
|
// ToDo: maybe another approach?
|
||||||
a.fetchIsRunningMutex.RLock()
|
a.fetchIsRunningMutex.RLock()
|
||||||
// This is an optimization to avoid excessive waiting when using Lock().
|
|
||||||
// Most of time application will wait between fetches.
|
|
||||||
// nolint:ifshort
|
|
||||||
isFetching := a.fetchIsRunning
|
isFetching := a.fetchIsRunning
|
||||||
a.fetchIsRunningMutex.RUnlock()
|
a.fetchIsRunningMutex.RUnlock()
|
||||||
|
|
||||||
@ -46,13 +44,15 @@ func (a *Application) fetch() {
|
|||||||
|
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
data, err := a.parse(resp.Body)
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.logger.Infoln("Failed to parse response body for", a.name, "metrics:", err.Error())
|
a.logger.Infoln("Failed to read response body for", a.name, "metrics:", err.Error())
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data := a.parse(string(body))
|
||||||
|
|
||||||
a.storage.Put(data)
|
a.storage.Put(data)
|
||||||
|
|
||||||
a.fetchIsRunningMutex.Lock()
|
a.fetchIsRunningMutex.Lock()
|
||||||
@ -64,7 +64,7 @@ func (a *Application) fetch() {
|
|||||||
func (a *Application) startFetcher() {
|
func (a *Application) startFetcher() {
|
||||||
fetchTicker := time.NewTicker(a.config.TimeBetweenRequests)
|
fetchTicker := time.NewTicker(a.config.TimeBetweenRequests)
|
||||||
|
|
||||||
// nolint:exhaustruct
|
// nolint:exhaustivestruct
|
||||||
a.httpClient = &http.Client{
|
a.httpClient = &http.Client{
|
||||||
Timeout: time.Second * 5,
|
Timeout: time.Second * 5,
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,19 @@
|
|||||||
package application
|
package application
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"go.dev.pztrn.name/metricator/pkg/schema"
|
"go.dev.pztrn.name/metricator/pkg/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Parses io.Reader passed and returns a map suitable for pushing into storage.
|
// Parses passed body and returns a map suitable for pushing into storage.
|
||||||
func (a *Application) parse(r io.Reader) (map[string]schema.Metric, error) {
|
func (a *Application) parse(body string) map[string]schema.Metric {
|
||||||
data := make(map[string]schema.Metric)
|
data := make(map[string]schema.Metric)
|
||||||
|
|
||||||
scanner := bufio.NewScanner(r)
|
// ToDo: switch to bytes buffer and maybe do not read body in caller?
|
||||||
for scanner.Scan() {
|
splittedBody := strings.Split(body, "\n")
|
||||||
line := scanner.Text()
|
|
||||||
|
|
||||||
// Skip empty lines.
|
|
||||||
if line == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for _, line := range splittedBody {
|
||||||
// Prometheus line contains metric name and metric parameters defined
|
// Prometheus line contains metric name and metric parameters defined
|
||||||
// in "{}".
|
// in "{}".
|
||||||
var (
|
var (
|
||||||
@ -29,6 +21,11 @@ func (a *Application) parse(r io.Reader) (map[string]schema.Metric, error) {
|
|||||||
params []string
|
params []string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Skip empty lines.
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
a.logger.Debugln("Analyzing line:", line)
|
a.logger.Debugln("Analyzing line:", line)
|
||||||
|
|
||||||
name = a.getMetricName(line)
|
name = a.getMetricName(line)
|
||||||
@ -83,22 +80,19 @@ func (a *Application) parse(r io.Reader) (map[string]schema.Metric, error) {
|
|||||||
newMetric.Params = params
|
newMetric.Params = params
|
||||||
|
|
||||||
metric = newMetric
|
metric = newMetric
|
||||||
|
data[metric.Name] = metric
|
||||||
}
|
}
|
||||||
|
|
||||||
metric.Value = a.getMetricValue(line)
|
metric.Value = a.getMetricValue(line)
|
||||||
|
|
||||||
a.logger.Debugf("Got metric: %+v\n", metric)
|
a.logger.Debugf("Got metric: %+v\n", metric)
|
||||||
|
|
||||||
data[metric.Name] = metric
|
data[name] = metric
|
||||||
}
|
|
||||||
|
|
||||||
if err := scanner.Err(); err != nil {
|
|
||||||
return nil, fmt.Errorf("wasn't able to scan input: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a.logger.Debugf("Data parsed: %+v\n", data)
|
a.logger.Debugf("Data parsed: %+v\n", data)
|
||||||
|
|
||||||
return data, nil
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets metric description from passed line.
|
// Gets metric description from passed line.
|
||||||
@ -143,8 +137,8 @@ func (a *Application) getParametersForPrometheusMetric(line string) []string {
|
|||||||
paramNameFinished, paramValueStarted, paramValueFinished bool
|
paramNameFinished, paramValueStarted, paramValueFinished bool
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, runeChar := range valuesString {
|
for _, r := range valuesString {
|
||||||
if paramValueFinished && string(runeChar) == "," {
|
if paramValueFinished && string(r) == "," {
|
||||||
params = append(params, paramName+":"+paramValue)
|
params = append(params, paramName+":"+paramValue)
|
||||||
paramName, paramValue = "", ""
|
paramName, paramValue = "", ""
|
||||||
paramNameFinished, paramValueStarted, paramValueFinished = false, false, false
|
paramNameFinished, paramValueStarted, paramValueFinished = false, false, false
|
||||||
@ -156,8 +150,8 @@ func (a *Application) getParametersForPrometheusMetric(line string) []string {
|
|||||||
// "deeply nested"? I think not. So:
|
// "deeply nested"? I think not. So:
|
||||||
// nolint:nestif
|
// nolint:nestif
|
||||||
if !paramNameFinished {
|
if !paramNameFinished {
|
||||||
if string(runeChar) != "=" {
|
if string(r) != "=" {
|
||||||
paramName += string(runeChar)
|
paramName += string(r)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
@ -166,19 +160,19 @@ func (a *Application) getParametersForPrometheusMetric(line string) []string {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if string(runeChar) == "\"" && !paramValueStarted {
|
if string(r) == "\"" && !paramValueStarted {
|
||||||
paramValueStarted = true
|
paramValueStarted = true
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if paramValueStarted && string(runeChar) != "\"" {
|
if paramValueStarted && string(r) != "\"" {
|
||||||
paramValue += string(runeChar)
|
paramValue += string(r)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if paramValueStarted && string(runeChar) == "\"" {
|
if paramValueStarted && string(r) == "\"" {
|
||||||
paramValueFinished = true
|
paramValueFinished = true
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
@ -21,18 +21,16 @@ var (
|
|||||||
|
|
||||||
// Config is an application's configuration.
|
// Config is an application's configuration.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
configPath string
|
||||||
// Applications describes configuration for remote application's endpoints.
|
// Applications describes configuration for remote application's endpoints.
|
||||||
// Key is an application's name.
|
// Key is an application's name.
|
||||||
Applications map[string]*application.Config `yaml:"applications"`
|
Applications map[string]*application.Config `yaml:"applications"`
|
||||||
// Logger is a logging configuration.
|
// Logger is a logging configuration.
|
||||||
Logger *logger.Config `yaml:"logger"`
|
Logger *logger.Config `yaml:"logger"`
|
||||||
configPath string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConfig returns new configuration.
|
// NewConfig returns new configuration.
|
||||||
func NewConfig() *Config {
|
func NewConfig() *Config {
|
||||||
// Fields are initialized when parsing YAML file.
|
|
||||||
// nolint:exhaustruct
|
|
||||||
c := &Config{}
|
c := &Config{}
|
||||||
c.initialize()
|
c.initialize()
|
||||||
|
|
||||||
|
@ -48,14 +48,14 @@ func (h *handler) getAppsList() ([]byte, error) {
|
|||||||
|
|
||||||
// Gets request information from URL. Returns a structure with filled request
|
// Gets request information from URL. Returns a structure with filled request
|
||||||
// info and error if it occurs.
|
// info and error if it occurs.
|
||||||
func (h *handler) getRequestInfo(req *http.Request) (*models.RequestInfo, error) {
|
func (h *handler) getRequestInfo(r *http.Request) (*models.RequestInfo, error) {
|
||||||
// Request isn't for API or isn't versioned.
|
// Request isn't for API or isn't versioned.
|
||||||
if !strings.HasPrefix(req.URL.Path, "/api/v") {
|
if !strings.HasPrefix(r.URL.Path, "/api/v") {
|
||||||
return nil, errInvalidPath
|
return nil, errInvalidPath
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: first element will always be empty!
|
// Note: first element will always be empty!
|
||||||
pathSplitted := strings.Split(req.URL.Path, "/")
|
pathSplitted := strings.Split(r.URL.Path, "/")
|
||||||
|
|
||||||
// Request is for API but not enough items in URL was passed.
|
// Request is for API but not enough items in URL was passed.
|
||||||
if len(pathSplitted) < 4 {
|
if len(pathSplitted) < 4 {
|
||||||
@ -119,20 +119,20 @@ func (h *handler) register(appName string, hndl common.HTTPHandlerFunc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ServeHTTP handles every HTTP request.
|
// ServeHTTP handles every HTTP request.
|
||||||
func (h *handler) ServeHTTP(writer http.ResponseWriter, req *http.Request) {
|
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
requestDuration := time.Since(startTime)
|
requestDuration := time.Since(startTime)
|
||||||
|
|
||||||
log.Printf("[HTTP Request] from %s to %s, duration %.4fs\n", req.RemoteAddr, req.URL.Path, requestDuration.Seconds())
|
log.Printf("[HTTP Request] from %s to %s, duration %.4fs\n", r.RemoteAddr, r.URL.Path, requestDuration.Seconds())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Validate request and extract needed info.
|
// Validate request and extract needed info.
|
||||||
rInfo, err := h.getRequestInfo(req)
|
rInfo, err := h.getRequestInfo(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writer.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
_, _ = writer.Write([]byte("400 bad request - " + err.Error()))
|
_, _ = w.Write([]byte("400 bad request - " + err.Error()))
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -144,14 +144,14 @@ func (h *handler) ServeHTTP(writer http.ResponseWriter, req *http.Request) {
|
|||||||
case "apps_list":
|
case "apps_list":
|
||||||
appsList, err := h.getAppsList()
|
appsList, err := h.getAppsList()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writer.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
_, _ = writer.Write([]byte("400 bad request - " + err.Error()))
|
_, _ = w.Write([]byte("400 bad request - " + err.Error()))
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_, _ = writer.Write(appsList)
|
_, _ = w.Write(appsList)
|
||||||
|
|
||||||
return
|
return
|
||||||
case "info":
|
case "info":
|
||||||
@ -167,18 +167,17 @@ func (h *handler) ServeHTTP(writer http.ResponseWriter, req *http.Request) {
|
|||||||
Version: common.Version,
|
Version: common.Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
// nolint:errchkjson
|
|
||||||
infoBytes, _ := json.Marshal(infoData)
|
infoBytes, _ := json.Marshal(infoData)
|
||||||
|
|
||||||
writer.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_, _ = writer.Write(infoBytes)
|
_, _ = w.Write(infoBytes)
|
||||||
|
|
||||||
return
|
return
|
||||||
case "metrics":
|
case "metrics":
|
||||||
handler, found := h.handlers[rInfo.Application]
|
handler, found := h.handlers[rInfo.Application]
|
||||||
if !found {
|
if !found {
|
||||||
writer.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
_, _ = writer.Write([]byte("400 bad request - " + errInvalidApplication.Error()))
|
_, _ = w.Write([]byte("400 bad request - " + errInvalidApplication.Error()))
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -186,16 +185,16 @@ func (h *handler) ServeHTTP(writer http.ResponseWriter, req *http.Request) {
|
|||||||
// Get data from handler.
|
// Get data from handler.
|
||||||
data := handler(rInfo)
|
data := handler(rInfo)
|
||||||
if data == "" {
|
if data == "" {
|
||||||
writer.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
_, _ = writer.Write([]byte("400 bad request - " + errNoData.Error()))
|
_, _ = w.Write([]byte("400 bad request - " + errNoData.Error()))
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_, _ = writer.Write([]byte(data))
|
_, _ = w.Write([]byte(data))
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
_, _ = writer.Write([]byte("400 bad request - " + errInvalidPath.Error()))
|
_, _ = w.Write([]byte("400 bad request - " + errInvalidPath.Error()))
|
||||||
}
|
}
|
||||||
|
@ -25,16 +25,15 @@ type HTTPServer struct {
|
|||||||
// NewHTTPServer creates HTTP server and executes preliminary initialization
|
// NewHTTPServer creates HTTP server and executes preliminary initialization
|
||||||
// (HTTP server structure initialized but it doesn't start).
|
// (HTTP server structure initialized but it doesn't start).
|
||||||
func NewHTTPServer(ctx context.Context, cfg *configuration.Config, logger *logger.Logger) (*HTTPServer, chan struct{}) {
|
func NewHTTPServer(ctx context.Context, cfg *configuration.Config, logger *logger.Logger) (*HTTPServer, chan struct{}) {
|
||||||
// nolint:exhaustruct
|
h := &HTTPServer{
|
||||||
httpServer := &HTTPServer{
|
|
||||||
config: cfg,
|
config: cfg,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
doneChan: make(chan struct{}),
|
doneChan: make(chan struct{}),
|
||||||
logger: logger,
|
logger: logger,
|
||||||
}
|
}
|
||||||
httpServer.initialize()
|
h.initialize()
|
||||||
|
|
||||||
return httpServer, httpServer.doneChan
|
return h, h.doneChan
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns request's context based on main context of application.
|
// Returns request's context based on main context of application.
|
||||||
@ -51,7 +50,7 @@ func (h *HTTPServer) initialize() {
|
|||||||
handlers: make(map[string]common.HTTPHandlerFunc),
|
handlers: make(map[string]common.HTTPHandlerFunc),
|
||||||
}
|
}
|
||||||
// We do not need to specify all possible parameters for HTTP server, so:
|
// We do not need to specify all possible parameters for HTTP server, so:
|
||||||
// nolint:exhaustruct
|
// nolint:exhaustivestruct
|
||||||
h.server = &http.Server{
|
h.server = &http.Server{
|
||||||
// ToDo: make it all configurable.
|
// ToDo: make it all configurable.
|
||||||
Addr: ":34421",
|
Addr: ":34421",
|
||||||
|
@ -9,10 +9,6 @@ type Logger struct {
|
|||||||
|
|
||||||
// NewLogger creates new logging wrapper and returns it to caller.
|
// NewLogger creates new logging wrapper and returns it to caller.
|
||||||
func NewLogger(config *Config) *Logger {
|
func NewLogger(config *Config) *Logger {
|
||||||
if config == nil {
|
|
||||||
config = &Config{Debug: false}
|
|
||||||
}
|
|
||||||
|
|
||||||
l := &Logger{config: config}
|
l := &Logger{config: config}
|
||||||
|
|
||||||
return l
|
return l
|
||||||
|
@ -14,27 +14,25 @@ var ErrMetricNotFound = errors.New("metric not found")
|
|||||||
|
|
||||||
// Storage is an in-memory storage.
|
// Storage is an in-memory storage.
|
||||||
type Storage struct {
|
type Storage struct {
|
||||||
dataMutex sync.RWMutex
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
doneChan chan struct{}
|
doneChan chan struct{}
|
||||||
logger *logger.Logger
|
logger *logger.Logger
|
||||||
data map[string]schema.Metric
|
data map[string]schema.Metric
|
||||||
name string
|
name string
|
||||||
|
dataMutex sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStorage creates new in-memory storage to use.
|
// NewStorage creates new in-memory storage to use.
|
||||||
func NewStorage(ctx context.Context, name string, logger *logger.Logger) (*Storage, chan struct{}) {
|
func NewStorage(ctx context.Context, name string, logger *logger.Logger) (*Storage, chan struct{}) {
|
||||||
// nolint:exhaustruct
|
s := &Storage{
|
||||||
storage := &Storage{
|
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
doneChan: make(chan struct{}),
|
doneChan: make(chan struct{}),
|
||||||
logger: logger,
|
logger: logger,
|
||||||
name: name,
|
name: name,
|
||||||
data: make(map[string]schema.Metric),
|
|
||||||
}
|
}
|
||||||
storage.initialize()
|
s.initialize()
|
||||||
|
|
||||||
return storage, storage.doneChan
|
return s, s.doneChan
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns data from storage by key.
|
// Get returns data from storage by key.
|
||||||
|
@ -23,14 +23,13 @@ type Client struct {
|
|||||||
|
|
||||||
// NewClient creates new Metricator client.
|
// NewClient creates new Metricator client.
|
||||||
func NewClient(config *Config, logger *logger.Logger) *Client {
|
func NewClient(config *Config, logger *logger.Logger) *Client {
|
||||||
// nolint:exhaustruct
|
c := &Client{
|
||||||
client := &Client{
|
|
||||||
config: config,
|
config: config,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
}
|
}
|
||||||
client.initialize()
|
c.initialize()
|
||||||
|
|
||||||
return client
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// Executes request and parses it's contents.
|
// Executes request and parses it's contents.
|
||||||
@ -140,7 +139,7 @@ func (c *Client) GetMetricsList(appName string) schema.Metrics {
|
|||||||
// Initializes internal states and storages.
|
// Initializes internal states and storages.
|
||||||
func (c *Client) initialize() {
|
func (c *Client) initialize() {
|
||||||
// We do not need to set everything for client actually, so:
|
// We do not need to set everything for client actually, so:
|
||||||
// nolint:exhaustruct
|
// nolint:exhaustivestruct
|
||||||
c.httpClient = &http.Client{
|
c.httpClient = &http.Client{
|
||||||
Timeout: time.Second * time.Duration(c.config.Timeout),
|
Timeout: time.Second * time.Duration(c.config.Timeout),
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ type Metric struct {
|
|||||||
|
|
||||||
// NewMetric creates new structure for storing single metric data.
|
// NewMetric creates new structure for storing single metric data.
|
||||||
func NewMetric(name, mType, description string, params []string) Metric {
|
func NewMetric(name, mType, description string, params []string) Metric {
|
||||||
metric := Metric{
|
m := Metric{
|
||||||
BaseName: name,
|
BaseName: name,
|
||||||
Name: name,
|
Name: name,
|
||||||
Description: description,
|
Description: description,
|
||||||
@ -27,7 +27,7 @@ func NewMetric(name, mType, description string, params []string) Metric {
|
|||||||
Value: "",
|
Value: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
return metric
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetValue returns metric's value.
|
// GetValue returns metric's value.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user