Add simple debug logging.

This commit is contained in:
Stanislav Nikitin 2020-12-23 16:28:57 +05:00
parent 935d5d8109
commit 95c8181d2a
Signed by: pztrn
GPG Key ID: 1E944A0F0568B550
10 changed files with 100 additions and 27 deletions

View File

@ -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())

View File

@ -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{}{}
}()

View File

@ -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()

View File

@ -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
}

View File

@ -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.

View File

@ -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{}{}
}()

View File

@ -0,0 +1,6 @@
package logger
// Config represents logging configuration.
type Config struct {
Debug bool `yaml:"debug"`
}

41
internal/logger/logger.go Normal file
View File

@ -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...)
}

View File

@ -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{}{}
}()

View File

@ -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