From 95c8181d2aefc24266dd32266aaa59cf356fc128 Mon Sep 17 00:00:00 2001 From: "Stanislav N. aka pztrn" Date: Wed, 23 Dec 2020 16:28:57 +0500 Subject: [PATCH] Add simple debug logging. --- cmd/metricatord/main.go | 8 +++--- internal/application/application.go | 12 +++++---- internal/application/fetcher.go | 11 ++++---- internal/application/parser.go | 6 ++--- internal/configuration/config.go | 3 +++ internal/httpserver/httpserver.go | 17 +++++++----- internal/logger/config.go | 6 +++++ internal/logger/logger.go | 41 +++++++++++++++++++++++++++++ internal/storage/memory/memory.go | 18 ++++++++++--- metricator.example.yaml | 5 ++++ 10 files changed, 100 insertions(+), 27 deletions(-) create mode 100644 internal/logger/config.go create mode 100644 internal/logger/logger.go diff --git a/cmd/metricatord/main.go b/cmd/metricatord/main.go index 5770e10..1a493ab 100644 --- a/cmd/metricatord/main.go +++ b/cmd/metricatord/main.go @@ -12,6 +12,7 @@ import ( "go.dev.pztrn.name/metricator/internal/common" "go.dev.pztrn.name/metricator/internal/configuration" "go.dev.pztrn.name/metricator/internal/httpserver" + "go.dev.pztrn.name/metricator/internal/logger" ) func main() { @@ -25,8 +26,6 @@ func main() { mainCtx, cancelFunc := context.WithCancel(context.Background()) config := configuration.NewConfig() - httpSrv, httpStopped := httpserver.NewHTTPServer(mainCtx, config) - // Parse configuration. flag.Parse() @@ -40,8 +39,11 @@ func main() { // Create applications. apps := make([]*application.Application, 0, len(config.Applications)) + logger := logger.NewLogger(config.Logger) + httpSrv, httpStopped := httpserver.NewHTTPServer(mainCtx, config, logger) + for appName, appConfig := range config.Applications { - app := application.NewApplication(mainCtx, appName, appConfig) + app := application.NewApplication(mainCtx, appName, appConfig, logger) app.Start() httpSrv.RegisterHandlerForApplication(appName, app.GetHandler()) diff --git a/internal/application/application.go b/internal/application/application.go index 4c1dbbd..26bcf32 100644 --- a/internal/application/application.go +++ b/internal/application/application.go @@ -2,11 +2,11 @@ package application import ( "context" - "log" "net/http" "sync" "go.dev.pztrn.name/metricator/internal/common" + "go.dev.pztrn.name/metricator/internal/logger" "go.dev.pztrn.name/metricator/internal/storage" "go.dev.pztrn.name/metricator/internal/storage/memory" ) @@ -17,6 +17,7 @@ type Application struct { config *Config ctx context.Context doneChan chan struct{} + logger *logger.Logger name string storage storage.Metrics @@ -29,11 +30,12 @@ type Application struct { } // NewApplication creates new application. -func NewApplication(ctx context.Context, name string, config *Config) *Application { +func NewApplication(ctx context.Context, name string, config *Config, logger *logger.Logger) *Application { a := &Application{ config: config, ctx: ctx, doneChan: make(chan struct{}), + logger: logger, name: name, } a.initialize() @@ -54,9 +56,9 @@ func (a *Application) GetHandler() common.HTTPHandlerFunc { // Initializes internal things like storage, HTTP client, etc. func (a *Application) initialize() { - a.storage, a.storageDone = memory.NewStorage(a.ctx, a.name+" storage") + a.storage, a.storageDone = memory.NewStorage(a.ctx, a.name+" storage", a.logger) - log.Printf("Application '%s' initialized with configuration: %+v\n", a.name, a.config) + a.logger.Debugf("Application '%s' initialized with configuration: %+v\n", a.name, a.config) } // Start starts asynchronous things like data fetching, storage cleanup, etc. @@ -71,7 +73,7 @@ func (a *Application) Start() { // We should wait until storage routines are also stopped. <-a.storage.GetDoneChan() - log.Println("Application", a.name, "stopped") + a.logger.Infoln("Application", a.name, "stopped") a.doneChan <- struct{}{} }() diff --git a/internal/application/fetcher.go b/internal/application/fetcher.go index 2f8efcd..207c2c8 100644 --- a/internal/application/fetcher.go +++ b/internal/application/fetcher.go @@ -2,7 +2,6 @@ package application import ( "io/ioutil" - "log" "net/http" "time" ) @@ -23,11 +22,11 @@ func (a *Application) fetch() { a.fetchIsRunning = true a.fetchIsRunningMutex.Unlock() - log.Println("Fetching data for", a.name) + a.logger.Infoln("Fetching data for", a.name) req, err := http.NewRequestWithContext(a.ctx, "GET", a.config.Endpoint, nil) if err != nil { - log.Println("Failed to create request for", a.name, "metrics:", err.Error()) + a.logger.Infoln("Failed to create request for", a.name, "metrics:", err.Error()) return } @@ -38,7 +37,7 @@ func (a *Application) fetch() { resp, err := a.httpClient.Do(req) if err != nil { - log.Println("Failed to execute request for", a.name, "metrics:", err.Error()) + a.logger.Infoln("Failed to execute request for", a.name, "metrics:", err.Error()) return } @@ -47,7 +46,7 @@ func (a *Application) fetch() { body, err := ioutil.ReadAll(resp.Body) if err != nil { - log.Println("Failed to read response body for", a.name, "metrics:", err.Error()) + a.logger.Infoln("Failed to read response body for", a.name, "metrics:", err.Error()) return } @@ -70,7 +69,7 @@ func (a *Application) startFetcher() { Timeout: time.Second * 5, } - defer log.Println("Fetcher for", a.name, "completed") + defer a.logger.Debugln("Fetcher for", a.name, "completed") // First fetch should be executed ASAP. a.fetch() diff --git a/internal/application/parser.go b/internal/application/parser.go index 631d69f..61b1002 100644 --- a/internal/application/parser.go +++ b/internal/application/parser.go @@ -26,7 +26,7 @@ func (a *Application) parse(body string) map[string]models.Metric { continue } - // log.Println("Analyzing line:", line) + a.logger.Debugln("Analyzing line:", line) name = a.getMetricName(line) metric, found := data[name] @@ -76,12 +76,12 @@ func (a *Application) parse(body string) map[string]models.Metric { metric.Value = a.getMetricValue(line) - // log.Printf("Got metric: %+v\n", metric) + a.logger.Debugln("Got metric: %+v\n", metric) data[name] = metric } - // log.Printf("Data parsed: %+v\n", data) + a.logger.Debugln("Data parsed: %+v\n", data) return data } diff --git a/internal/configuration/config.go b/internal/configuration/config.go index 61a8f16..0c25e47 100644 --- a/internal/configuration/config.go +++ b/internal/configuration/config.go @@ -10,6 +10,7 @@ import ( "strings" "go.dev.pztrn.name/metricator/internal/application" + "go.dev.pztrn.name/metricator/internal/logger" "gopkg.in/yaml.v2" ) @@ -24,6 +25,8 @@ type Config struct { // Applications describes configuration for remote application's endpoints. // Key is an application's name. Applications map[string]*application.Config `yaml:"applications"` + // Logger is a logging configuration. + Logger *logger.Config `yaml:"logger"` } // NewConfig returns new configuration. diff --git a/internal/httpserver/httpserver.go b/internal/httpserver/httpserver.go index d7fc7aa..a689aa5 100644 --- a/internal/httpserver/httpserver.go +++ b/internal/httpserver/httpserver.go @@ -2,7 +2,6 @@ package httpserver import ( "context" - "log" "net" "net/http" "strings" @@ -10,6 +9,7 @@ import ( "go.dev.pztrn.name/metricator/internal/common" "go.dev.pztrn.name/metricator/internal/configuration" + "go.dev.pztrn.name/metricator/internal/logger" ) // HTTPServer is a controlling structure for HTTP server. @@ -17,15 +17,17 @@ type HTTPServer struct { config *configuration.Config ctx context.Context doneChan chan struct{} + logger *logger.Logger handler *handler server *http.Server } -func NewHTTPServer(ctx context.Context, cfg *configuration.Config) (*HTTPServer, chan struct{}) { +func NewHTTPServer(ctx context.Context, cfg *configuration.Config, logger *logger.Logger) (*HTTPServer, chan struct{}) { h := &HTTPServer{ config: cfg, ctx: ctx, doneChan: make(chan struct{}), + logger: logger, } h.initialize() @@ -40,6 +42,8 @@ func (h *HTTPServer) getRequestContext(_ net.Listener) context.Context { // Initializes handler and HTTP server structure. func (h *HTTPServer) initialize() { + h.logger.Debugln("Initializing HTTP server...") + h.handler = &handler{ handlers: make(map[string]common.HTTPHandlerFunc), } @@ -58,6 +62,7 @@ func (h *HTTPServer) initialize() { // RegisterHandlerForApplication registers HTTP handler for application. func (h *HTTPServer) RegisterHandlerForApplication(name string, handler common.HTTPHandlerFunc) { + h.logger.Debugln("Registering handler for application", name) h.handler.register(name, handler) } @@ -68,21 +73,21 @@ func (h *HTTPServer) Start() { err := h.server.ListenAndServe() if err != nil { if !strings.Contains(err.Error(), "Server closed") { - log.Println("HTTP server failed to listen:", err.Error()) + h.logger.Infoln("HTTP server failed to listen:", err.Error()) } } }() go func() { <-h.ctx.Done() - log.Println("Shutting down HTTP server") + h.logger.Infoln("Shutting down HTTP server") err := h.server.Shutdown(h.ctx) if err != nil && !strings.Contains(err.Error(), "context canceled") { - log.Println("Failed to stop HTTP server:", err.Error()) + h.logger.Infoln("Failed to stop HTTP server:", err.Error()) } - log.Println("HTTP server stopped") + h.logger.Infoln("HTTP server stopped") h.doneChan <- struct{}{} }() diff --git a/internal/logger/config.go b/internal/logger/config.go new file mode 100644 index 0000000..7091b6f --- /dev/null +++ b/internal/logger/config.go @@ -0,0 +1,6 @@ +package logger + +// Config represents logging configuration. +type Config struct { + Debug bool `yaml:"debug"` +} diff --git a/internal/logger/logger.go b/internal/logger/logger.go new file mode 100644 index 0000000..a12306e --- /dev/null +++ b/internal/logger/logger.go @@ -0,0 +1,41 @@ +package logger + +import "log" + +// Logger responsible for all logging actions. +type Logger struct { + config *Config +} + +// NewLogger creates new logging wrapper and returns it to caller. +func NewLogger(config *Config) *Logger { + l := &Logger{config: config} + + return l +} + +// Debugf is a wrapper around log.Printf which will work only when debug mode +// is enabled. +func (l *Logger) Debugf(template string, params ...interface{}) { + if l.config.Debug { + log.Printf(template, params...) + } +} + +// Debugln is a wrapper around log.Println which will work only when debug mode +// is enabled. +func (l *Logger) Debugln(params ...interface{}) { + if l.config.Debug { + log.Println(params...) + } +} + +// Infof is a wrapper around log.Printf. +func (l *Logger) Infof(template string, params ...interface{}) { + log.Printf(template, params...) +} + +// Infoln is a wrapper around log.Println. +func (l *Logger) Infoln(params ...interface{}) { + log.Println(params...) +} diff --git a/internal/storage/memory/memory.go b/internal/storage/memory/memory.go index c9f9d38..742e453 100644 --- a/internal/storage/memory/memory.go +++ b/internal/storage/memory/memory.go @@ -3,9 +3,9 @@ package memory import ( "context" "errors" - "log" "sync" + "go.dev.pztrn.name/metricator/internal/logger" "go.dev.pztrn.name/metricator/internal/models" ) @@ -15,6 +15,7 @@ var ErrMetricNotFound = errors.New("metric not found") type Storage struct { ctx context.Context doneChan chan struct{} + logger *logger.Logger name string data map[string]models.Metric @@ -22,10 +23,11 @@ type Storage struct { } // NewStorage creates new in-memory storage to use. -func NewStorage(ctx context.Context, name string) (*Storage, chan struct{}) { +func NewStorage(ctx context.Context, name string, logger *logger.Logger) (*Storage, chan struct{}) { s := &Storage{ ctx: ctx, doneChan: make(chan struct{}), + logger: logger, name: name, } s.initialize() @@ -35,19 +37,27 @@ func NewStorage(ctx context.Context, name string) (*Storage, chan struct{}) { // Get returns data from storage by key. func (s *Storage) Get(key string) (models.Metric, error) { + s.logger.Debugln("Retrieving data for", key, "key from storage...") + s.dataMutex.RLock() defer s.dataMutex.RUnlock() data, found := s.data[key] if !found { + s.logger.Infoln("Key", key, "not found in storage!") + return models.NewMetric("", "", "", nil), ErrMetricNotFound } + s.logger.Debugf("Key %s found: %+v\n", key, data) + return data, nil } // GetAsSlice returns all data from storage as slice. func (s *Storage) GetAsSlice() []models.Metric { + s.logger.Debugln("Returning all stored metrics as slice...") + metrics := make([]models.Metric, 0, len(s.data)) for _, metric := range s.data { @@ -80,7 +90,7 @@ func (s *Storage) Put(data map[string]models.Metric) { } } - log.Println("Put", len(data), "items in", s.name) + s.logger.Debugln("Put", len(data), "items in", s.name) } // Start starts asynchronous things if needed. @@ -89,7 +99,7 @@ func (s *Storage) Start() { go func() { <-s.ctx.Done() - log.Println("In-memory storage", s.name, "done") + s.logger.Infoln("In-memory storage", s.name, "done") s.doneChan <- struct{}{} }() diff --git a/metricator.example.yaml b/metricator.example.yaml index 36c2c78..057040c 100644 --- a/metricator.example.yaml +++ b/metricator.example.yaml @@ -10,3 +10,8 @@ applications: # Timeout between requests. Not neccessarily be exact and requests might # be sent in 60 or more seconds (in this example). time_between_requests: 60s + +# Logger's configuration. +logger: + # Print debug output or not? + debug: false