diff --git a/internal/application/application.go b/internal/application/application.go index 26bcf32..297013d 100644 --- a/internal/application/application.go +++ b/internal/application/application.go @@ -14,19 +14,16 @@ import ( // Application is a thing that responsible for all application-related // actions like data fetching, storing, etc. on higher level. type Application struct { - config *Config - ctx context.Context - doneChan chan struct{} - logger *logger.Logger - name string - - storage storage.Metrics - storageDone chan struct{} - - fetchIsRunning bool + ctx context.Context + storage storage.Metrics + config *Config + doneChan chan struct{} + logger *logger.Logger + storageDone chan struct{} + httpClient *http.Client + name string fetchIsRunningMutex sync.RWMutex - - httpClient *http.Client + fetchIsRunning bool } // NewApplication creates new application. diff --git a/internal/application/config.go b/internal/application/config.go index ef3f5d4..3843066 100644 --- a/internal/application/config.go +++ b/internal/application/config.go @@ -4,11 +4,11 @@ import "time" // Config is a generic application configuration. type Config struct { + // Headers is a list of headers that should be added to metrics request. + Headers map[string]string `yaml:"headers"` // Endpoint is a remote application endpoint which should give us metrics // in Prometheus format. Endpoint string `yaml:"endpoint"` - // Headers is a list of headers that should be added to metrics request. - Headers map[string]string `yaml:"headers"` // TimeBetweenRequests is a minimal amount of time which should pass // between requests. TimeBetweenRequests time.Duration `yaml:"time_between_requests"` diff --git a/internal/application/parser.go b/internal/application/parser.go index 61b1002..c2ab3af 100644 --- a/internal/application/parser.go +++ b/internal/application/parser.go @@ -29,6 +29,7 @@ func (a *Application) parse(body string) map[string]models.Metric { a.logger.Debugln("Analyzing line:", line) name = a.getMetricName(line) + metric, found := data[name] if !found { metric = models.NewMetric(name, "", "", nil) @@ -53,9 +54,9 @@ func (a *Application) parse(body string) map[string]models.Metric { data[name] = metric - // According to https://github.com/Showmax/prometheus-docs/blob/master/content/docs/instrumenting/exposition_formats.md - // HELP and TYPE lines should be printed before actual metric. Do not even + // According to docs HELP and TYPE lines should be printed before actual metric. Do not even // report bugs regarding that! + // Docs: https://github.com/Showmax/prometheus-docs/blob/master/content/docs/instrumenting/exposition_formats.md continue } @@ -76,12 +77,12 @@ func (a *Application) parse(body string) map[string]models.Metric { metric.Value = a.getMetricValue(line) - a.logger.Debugln("Got metric: %+v\n", metric) + a.logger.Debugf("Got metric: %+v\n", metric) data[name] = metric } - a.logger.Debugln("Data parsed: %+v\n", data) + a.logger.Debugf("Data parsed: %+v\n", data) return data } @@ -138,7 +139,7 @@ func (a *Application) getParametersForPrometheusMetric(line string) []string { } // Sometimes nestif causes questions, like here. Is code below is - // "deply nested"? I think not. So: + // "deeply nested"? I think not. So: // nolint:nestif if !paramNameFinished { if string(r) != "=" { diff --git a/internal/httpserver/handler.go b/internal/httpserver/handler.go index a54842c..745b1fb 100644 --- a/internal/httpserver/handler.go +++ b/internal/httpserver/handler.go @@ -39,7 +39,6 @@ func (h *handler) getAppsList() ([]byte, error) { appsList, err := json.Marshal(apps) if err != nil { // ToDo: log error - return nil, errNoAppsRegistered } @@ -70,23 +69,41 @@ func (h *handler) getRequestInfo(r *http.Request) (*models.RequestInfo, error) { // Parse API version. apiVersionRaw := strings.TrimLeft(pathSplitted[2], "v") + apiVersion, err := strconv.Atoi(apiVersionRaw) if err != nil { // ToDo: log error return nil, errInvalidAPIVersion } + // Check used API version. + var supportedAPIVersionUsed bool + + for _, version := range supportedAPIVersions { + if apiVersion == version { + supportedAPIVersionUsed = true + + break + } + } + + if !supportedAPIVersionUsed { + return nil, errInvalidAPIVersion + } + // Get request type and key. requestType = pathSplitted[3] + if len(pathSplitted) >= 5 { appName = pathSplitted[4] } + if len(pathSplitted) >= 6 { metricName = strings.Join(pathSplitted[5:], "/") } reqInfo := &models.RequestInfo{ - ApiVersion: apiVersion, + APIVersion: apiVersion, Application: appName, Metric: metricName, RequestType: requestType, @@ -103,8 +120,9 @@ func (h *handler) register(appName string, hndl common.HTTPHandlerFunc) { // ServeHTTP handles every HTTP request. func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { startTime := time.Now() + defer func() { - requestDuration := time.Now().Sub(startTime) + requestDuration := time.Since(startTime) log.Printf("[HTTP Request] from %s to %s, duration %.4fs\n", r.RemoteAddr, r.URL.Path, requestDuration.Seconds()) }() diff --git a/internal/models/metric.go b/internal/models/metric.go index e2598a2..42d45f9 100644 --- a/internal/models/metric.go +++ b/internal/models/metric.go @@ -2,16 +2,16 @@ package models // Metric is a generic metric structure. type Metric struct { - // Metric name. + // Name is a metric name. Name string - // HELP data, if present. + // Description is a metric description from HELP line. Description string - // Additional parameters, data inside "{}". - Params []string - // Type is a metric type. + // Type is a metric type from TYPE line. Type string - // Metric value. + // Value is a metric value. Value string + // Params is an additional params which are placed inside "{}". + Params []string } // NewMetric creates new structure for storing single metric data. @@ -21,6 +21,7 @@ func NewMetric(name, mType, description string, params []string) Metric { Description: description, Type: mType, Params: params, + Value: "", } return m diff --git a/internal/models/request_info.go b/internal/models/request_info.go index b58d8f8..60f796a 100644 --- a/internal/models/request_info.go +++ b/internal/models/request_info.go @@ -2,8 +2,8 @@ package models // RequestInfo is a parsed request information to throw into application's handler. type RequestInfo struct { - ApiVersion int Application string Metric string RequestType string + APIVersion int }