Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sprint 7, increment 18 #20

Merged
merged 8 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/mertricstest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:

metricstest:
runs-on: ubuntu-latest
container: golang:1.20
container: golang:1.21
needs: branchtest

services:
Expand All @@ -38,10 +38,10 @@ jobs:
uses: actions/checkout@v2

- name: Download autotests binaries
uses: robinraju/release-downloader@v1.7
uses: robinraju/release-downloader@v1.8
with:
repository: Yandex-Practicum/go-autotests
tag: refactor
latest: true
fileName: "*"
out-file-path: .tools
token: ${{ secrets.GITHUB_TOKEN }}
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/statictest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ on:
jobs:
statictest:
runs-on: ubuntu-latest
container: golang:1.20
container: golang:1.21
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Download statictest binary
uses: robinraju/release-downloader@v1.7
uses: robinraju/release-downloader@v1.8
with:
repository: Yandex-Practicum/go-autotests
tag: refactor
latest: true
fileName: statictest
out-file-path: .tools
token: ${{ secrets.GITHUB_TOKEN }}
Expand Down
9 changes: 9 additions & 0 deletions cmd/agent/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// Package main is the entry point for the monitoring agent application.
// It initializes and orchestrates various components like logging, configuration,
// data reporting, and polling. The application handles periodic data collection
// and reporting to a central server.
package main

import (
Expand All @@ -16,6 +20,8 @@ import (
"github.com/matthiasBT/monitoring/internal/infra/utils"
)

// setupRetrier configures and returns a Retrier based on the provided agent configuration.
// It sets up retry attempts, intervals, and logging for handling network-related retries.
func setupRetrier(conf *agent.Config, logger logging.ILogger) utils.Retrier {
return utils.Retrier{
Attempts: conf.RetryAttempts,
Expand All @@ -25,6 +31,9 @@ func setupRetrier(conf *agent.Config, logger logging.ILogger) utils.Retrier {
}
}

// main is the entry function of the application. It sets up logging, configuration,
// data reporting, and polling mechanisms. It orchestrates the agent's lifecycle,
// including handling graceful shutdowns.
func main() {
logger := logging.SetupLogger()
conf, err := agent.InitConfig()
Expand Down
23 changes: 19 additions & 4 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Package main is the entry point for the server application in the monitoring system.
// It sets up and runs the HTTP server, handling configuration, logging, and graceful shutdowns.
// The package integrates various internal components like routing, data storage, and middleware.
package main

import (
Expand All @@ -10,18 +13,19 @@ import (
"syscall"
"time"

"github.com/matthiasBT/monitoring/internal/infra/hashcheck"
"github.com/matthiasBT/monitoring/internal/infra/utils"
"github.com/matthiasBT/monitoring/internal/server/entities"

"github.com/go-chi/chi/v5"
"github.com/matthiasBT/monitoring/internal/infra/compression"
"github.com/matthiasBT/monitoring/internal/infra/config/server"
"github.com/matthiasBT/monitoring/internal/infra/hashcheck"
"github.com/matthiasBT/monitoring/internal/infra/logging"
"github.com/matthiasBT/monitoring/internal/infra/utils"
"github.com/matthiasBT/monitoring/internal/server/adapters"
"github.com/matthiasBT/monitoring/internal/server/entities"
"github.com/matthiasBT/monitoring/internal/server/usecases"
)

// setupServer configures and returns a new HTTP router with middleware and routes.
// It includes logging, compression, optional HMAC checking, and controller routes.
func setupServer(logger logging.ILogger, controller *usecases.BaseController, hmacKey string) *chi.Mux {
r := chi.NewRouter()
r.Use(logging.Middleware(logger))
Expand All @@ -33,6 +37,8 @@ func setupServer(logger logging.ILogger, controller *usecases.BaseController, hm
return r
}

// gracefulShutdown handles the graceful shutdown of the server.
// It listens for system signals and shuts down the server after processing ongoing requests.
func gracefulShutdown(srv *http.Server, done chan struct{}, logger logging.ILogger) {
quitChannel := make(chan os.Signal, 1)
signal.Notify(quitChannel, syscall.SIGINT, syscall.SIGTERM)
Expand All @@ -46,6 +52,8 @@ func gracefulShutdown(srv *http.Server, done chan struct{}, logger logging.ILogg
}
}

// setupRetrier configures and returns a Retrier based on the provided server configuration.
// It sets up retry attempts, intervals, and logging for handling network-related retries.
func setupRetrier(conf *server.Config, logger logging.ILogger) utils.Retrier {
return utils.Retrier{
Attempts: conf.RetryAttempts,
Expand All @@ -55,6 +63,8 @@ func setupRetrier(conf *server.Config, logger logging.ILogger) utils.Retrier {
}
}

// setupKeeper initializes and returns the appropriate Keeper (database or file) based on configuration.
// It configures the storage mechanism for the server, handling data persistence.
func setupKeeper(conf *server.Config, logger logging.ILogger, retrier utils.Retrier) entities.Keeper {
if conf.Flushes() {
if conf.DatabaseDSN != "" {
Expand All @@ -66,6 +76,8 @@ func setupKeeper(conf *server.Config, logger logging.ILogger, retrier utils.Retr
return nil
}

// setupTicker creates and returns a ticker channel based on the configuration.
// It's used for periodic operations like data flushing.
func setupTicker(conf *server.Config) <-chan time.Time {
if conf.FlushesSync() {
return make(chan time.Time) // will never be used
Expand All @@ -75,6 +87,9 @@ func setupTicker(conf *server.Config) <-chan time.Time {
}
}

// main is the entry function of the application. It sets up and starts the HTTP server,
// including configuration, logging, storage, and routing. It also manages the application's lifecycle,
// handling initialization and graceful shutdown.
func main() {
logger := logging.SetupLogger()
conf, err := server.InitConfig()
Expand Down
95 changes: 95 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package monitoring_test

import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"

common "github.com/matthiasBT/monitoring/internal/infra/entities"
"github.com/matthiasBT/monitoring/internal/infra/logging"
"github.com/matthiasBT/monitoring/internal/server/adapters"
"github.com/matthiasBT/monitoring/internal/server/usecases"
"github.com/sirupsen/logrus"
)

func Example() {
logger := logging.SetupLogger()
logger.SetLevel(logrus.FatalLevel) // to avoid printing unnecessary logs
storage := adapters.NewMemStorage(nil, nil, logger, nil)
controller := usecases.NewBaseController(logger, storage, "/")

updateCounter(100500, controller)
updateGauge(5.5, controller)
getCounter(controller)
getGauge(controller)
updateCounter(11, controller)
updateGauge(1.5, controller)
getCounter(controller)
getGauge(controller)

// Output:
// {"id":"FooBar","type":"counter","delta":100500}
// {"id":"BarFoo","type":"gauge","value":5.5}
// {"id":"FooBar","type":"counter","delta":100511}
// {"id":"BarFoo","type":"gauge","value":1.5}
}

func updateCounter(value int64, controller *usecases.BaseController) {
w := httptest.NewRecorder()
newCounter := common.Metrics{
ID: "FooBar",
MType: "counter",
Delta: &value,
Value: nil,
}
body, _ := json.Marshal(newCounter)
addCounterReq := httptest.NewRequest(http.MethodPost, "/update/", bytes.NewReader(body))
addCounterReq.Header.Set("Content-Type", "application/json")
controller.UpdateMetric(w, addCounterReq)
}

func updateGauge(value float64, controller *usecases.BaseController) {
w := httptest.NewRecorder()
newGauge := common.Metrics{
ID: "BarFoo",
MType: "gauge",
Delta: nil,
Value: &value,
}
body, _ := json.Marshal(newGauge)
addGaugeReq := httptest.NewRequest(http.MethodPost, "/update/", bytes.NewReader(body))
addGaugeReq.Header.Set("Content-Type", "application/json")
controller.UpdateMetric(w, addGaugeReq)
}

func getCounter(controller *usecases.BaseController) {
w := httptest.NewRecorder()
newCounter := common.Metrics{
ID: "FooBar",
MType: "counter",
Delta: nil,
Value: nil,
}
body, _ := json.Marshal(newCounter)
getCounterReq := httptest.NewRequest(http.MethodGet, "/value/", bytes.NewReader(body))
getCounterReq.Header.Set("Content-Type", "application/json")
controller.GetMetric(w, getCounterReq)
fmt.Printf("%v\n", w.Body)
}

func getGauge(controller *usecases.BaseController) {
w := httptest.NewRecorder()
newGauge := common.Metrics{
ID: "BarFoo",
MType: "gauge",
Delta: nil,
Value: nil,
}
body, _ := json.Marshal(newGauge)
getGaugeReq := httptest.NewRequest(http.MethodGet, "/value/", bytes.NewReader(body))
getGaugeReq.Header.Set("Content-Type", "application/json")
controller.GetMetric(w, getGaugeReq)
fmt.Printf("%v\n", w.Body)
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ require (
github.com/shirou/gopsutil/v3 v3.23.8
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.8.4
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63
)

require (
Expand All @@ -24,6 +23,7 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDN
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE=
github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
Expand Down
36 changes: 31 additions & 5 deletions internal/agent/adapters/http.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// Package adapters provides functionalities to handle HTTP communication,
// specifically for reporting metrics. It includes structures and methods
// for sending reports, handling retries, and ensuring data integrity.

package adapters

import (
Expand All @@ -17,17 +21,35 @@ import (
"github.com/matthiasBT/monitoring/internal/infra/utils"
)

// HTTPReportAdapter is responsible for sending metrics over HTTP. It handles
// the creation and sending of HTTP requests, including retries and HMAC authentication.
// It uses a channel to queue payloads for asynchronous processing.
type HTTPReportAdapter struct {
Logger logging.ILogger
// Logger is used for logging messages related to HTTP reporting activities.
Logger logging.ILogger

// ServerAddr specifies the HTTP server address where reports are sent.
ServerAddr string
UpdateURL string
Retrier utils.Retrier
HMACKey []byte
jobs chan []byte

// UpdateURL is the endpoint for updating or sending reports.
UpdateURL string

// Retrier is used to handle retries for HTTP requests in case of failures.
Retrier utils.Retrier

// HMACKey is the key used for HMAC-SHA256 hashing to ensure data integrity.
HMACKey []byte

// jobs is an internal channel used to queue payloads for reporting.
jobs chan []byte
}

// ErrResponseNotOK is an error indicating that the HTTP response status is not OK (200).
var ErrResponseNotOK = errors.New("response not OK")

// NewHTTPReportAdapter creates and returns a new HTTPReportAdapter. It initializes
// the adapter with the provided logger, server address, update URL, retrier, HMAC key,
// and sets up worker goroutines based on the provided workerNum.
func NewHTTPReportAdapter(
logger logging.ILogger,
serverAddr string,
Expand Down Expand Up @@ -57,6 +79,8 @@ func NewHTTPReportAdapter(
return &adapter
}

// Report sends a single metric over HTTP. It marshals the metric, logs any errors
// in marshaling, and queues the payload for processing.
func (r *HTTPReportAdapter) Report(metrics *common.Metrics) error {
payload, err := json.Marshal(metrics)
if err != nil {
Expand All @@ -67,6 +91,8 @@ func (r *HTTPReportAdapter) Report(metrics *common.Metrics) error {
return nil
}

// ReportBatch sends a batch of metrics over HTTP. It marshals the batch of metrics,
// logs any errors in marshaling, and queues the payload for processing.
func (r *HTTPReportAdapter) ReportBatch(batch []*common.Metrics) error {
payload, err := json.Marshal(batch)
if err != nil {
Expand Down
22 changes: 21 additions & 1 deletion internal/agent/entities/snapshot.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,37 @@
// Package entities defines data structures and interfaces used for representing
// and reporting monitoring data in the monitoring system.

package entities

import "github.com/matthiasBT/monitoring/internal/infra/entities"

// Snapshot represents a snapshot of monitoring data at a specific point in time.
// It includes gauges and counters, where gauges represent measurements at a particular
// moment and counters represent cumulative values over time.
type Snapshot struct {
Gauges map[string]float64
// Gauges is a map where keys are gauge names and values are the gauge measurements.
Gauges map[string]float64

// Counters is a map where keys are counter names and values are the accumulated counter values.
Counters map[string]int64
}

// SnapshotWrapper encapsulates a Snapshot. It is used for passing snapshots
// around in the system, potentially adding more metadata or context in the future.
type SnapshotWrapper struct {
// CurrSnapshot is a pointer to the current Snapshot being encapsulated.
CurrSnapshot *Snapshot
}

// IReporter is an interface defining methods for reporting monitoring metrics.
// Implementations of this interface are responsible for handling the actual
// reporting of metric data.
type IReporter interface {
// Report sends a single metrics object. This method is typically used for
// reporting individual metrics or data points.
Report(metrics *entities.Metrics) error

// ReportBatch sends a batch of metrics. This method is useful for reporting
// multiple metrics at once, potentially reducing overhead or network calls.
ReportBatch(batch []*entities.Metrics) error
}
Loading
Loading