diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..a96ed1c --- /dev/null +++ b/go.sum @@ -0,0 +1,38 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/amitrai48/logger v0.0.0-20190214092904-448001c055ec h1:tDOPo9NAXCjvoK35HgZyzQSNLmb3chZqN2tnO273Bro= +github.com/amitrai48/logger v0.0.0-20190214092904-448001c055ec/go.mod h1:RZEHP3cxXvQlMuMjkpdh6qXA4b0CpjxnUBNxOpR0r30= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME= +github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/previewer.conf b/previewer.conf new file mode 100644 index 0000000..57ceb43 --- /dev/null +++ b/previewer.conf @@ -0,0 +1,11 @@ +[Server] +Address = "localhost" +Port = "80" + +[Cache] +Capasity = 20 + +[Logger] +File = "./previewer.log" +Level = "INFO" +MuteStdout = false \ No newline at end of file diff --git a/previewer/application/application.go b/previewer/application/application.go new file mode 100644 index 0000000..577402e --- /dev/null +++ b/previewer/application/application.go @@ -0,0 +1,11 @@ +package application + + +type App struct { + Server + Log logger.Interface +} + +func New(logger logger.Interface) *App { + return &App{Log: logger} +} diff --git a/previewer/config/config.go b/previewer/config/config.go new file mode 100644 index 0000000..734f587 --- /dev/null +++ b/previewer/config/config.go @@ -0,0 +1,38 @@ +package config + +import ( + "io/ioutil" + "os" + + "github.com/BurntSushi/toml" +) + +type Config struct { + Server struct { + Address string + Port string + } + Cache struct { + Capasity string + } + Log struct { + File string + Level string + MuteStdout bool + } +} + +func NewConfig(configFile string) (Config, error) { + f, err := os.Open(configFile) + if err != nil { + return Config{}, err + } + defer f.Close() + s, err := ioutil.ReadAll(f) + if err != nil { + return Config{}, err + } + var config Config + _, err = toml.Decode(string(s), &config) + return config, err +} diff --git a/previewer/config/config_test.go b/previewer/config/config_test.go new file mode 100644 index 0000000..fe19b8a --- /dev/null +++ b/previewer/config/config_test.go @@ -0,0 +1,58 @@ +package config + +import ( + "github.com/stretchr/testify/require" + "io/ioutil" + oslog "log" + "os" + "testing" +) + +var _ = func() bool { + testing.Init() + return true +}() + +func TestNewConfig(t *testing.T) { + + badfile, err := ioutil.TempFile("", "conf.") + if err != nil { + oslog.Fatal(err) + } + defer os.Remove(badfile.Name()) + badfile.WriteString(`aefSD +sadfg +RFABND FYGUMG +V`) + badfile.Sync() + + goodfile, err := ioutil.TempFile("", "conf.") + if err != nil { + oslog.Fatal(err) + } + defer os.Remove(goodfile.Name()) + goodfile.WriteString(`[Server] +Address = "localhost" +Port = "80"`) + goodfile.Sync() + + t.Run("No such file", func(t *testing.T) { + c, e := NewConfig("adfergdth") + require.Equal(t, Config{}, c) + require.Error(t, e) + }) + + t.Run("Bad file", func(t *testing.T) { + c, e := NewConfig(badfile.Name()) + require.Equal(t, Config{}, c) + require.Error(t, e) + }) + + t.Run("TOML reading", func(t *testing.T) { + c, e := NewConfig(goodfile.Name()) + require.Equal(t, "localhost", c.Server.Address) + require.Equal(t, 80, c.Server.Port) + require.NoError(t, e) + }) + +} diff --git a/previewer/logger/logger.go b/previewer/logger/logger.go new file mode 100644 index 0000000..9b9bd02 --- /dev/null +++ b/previewer/logger/logger.go @@ -0,0 +1,71 @@ +package logger + +import ( + "errors" + "log" + "os" + "strings" + + amitralog "github.com/amitrai48/logger" +) + +type Interface interface { + Debugf(format string, args ...interface{}) + Infof(format string, args ...interface{}) + Warnf(format string, args ...interface{}) + Errorf(format string, args ...interface{}) + Fatalf(format string, args ...interface{}) +} + +type Logger struct { + Logger amitralog.Logger +} +type Config struct { + File string + Level string + MuteStdout bool +} +var validLevel = map[string]bool{"debug": true, "info": true, "warn": true, "error": true, "fatal": true} + +func New(conf Config) (Interface, error) { + if conf.File == "" || !validLevel[strings.ToLower(conf.Level)] { + return nil, errors.New("invalid logger config") + } + + c := amitralog.Configuration{ + EnableConsole: !conf.MuteStdout, + ConsoleLevel: amitralog.Fatal, + ConsoleJSONFormat: false, + EnableFile: true, + FileLevel: strings.ToLower(conf.Level), + FileJSONFormat: true, + FileLocation: conf.File, + } + + if err := amitralog.NewLogger(c, amitralog.InstanceZapLogger); err != nil { + log.Fatalf("Could not instantiate log %s", err.Error()) + } + l := amitralog.WithFields(amitralog.Fields{"hw": "12"}) + return l, nil +} + +func (l *Logger) Debugf(format string, args ...interface{}) { + l.Logger.Debugf(format, args) +} + +func (l *Logger) Infof(format string, args ...interface{}) { + l.Logger.Infof(format, args) +} + +func (l *Logger) Warnf(format string, args ...interface{}) { + l.Logger.Warnf(format, args) +} + +func (l *Logger) Errorf(format string, args ...interface{}) { + l.Logger.Errorf(format, args) +} + +func (l *Logger) Fatalf(format string, args ...interface{}) { + l.Logger.Fatalf(format, args) + os.Exit(2) +} diff --git a/previewer/logger/logger_test.go b/previewer/logger/logger_test.go new file mode 100644 index 0000000..edc4b28 --- /dev/null +++ b/previewer/logger/logger_test.go @@ -0,0 +1,50 @@ +package logger + +import ( + "github.com/stretchr/testify/require" + "io/ioutil" + oslog "log" + "os" + "strings" + "testing" +) + +func TestLoggerLogic(t *testing.T) { + tmpfile, err := ioutil.TempFile("", "log.") + if err != nil { + oslog.Fatal(err) + } + defer os.Remove(tmpfile.Name()) + + conf := Config{File: tmpfile.Name(), Level: "warn", MuteStdout: false} + log, err := New(conf) + if err != nil { + oslog.Fatal(err) + } + + t.Run("Messages arround the level", func(t *testing.T) { + log.Debugf("debug message") + log.Errorf("error message") + + res, err := ioutil.ReadAll(tmpfile) + if err != nil { + oslog.Fatal(err) + } + require.Less(t, strings.Index(string(res), "debug message"), 0) + require.Greater(t, strings.Index(string(res), "error message"), 0) + }) +} + +func TestLoggerNegative(t *testing.T) { + t.Run("Bad file name", func(t *testing.T) { + conf := Config{File: "", Level: "debug", MuteStdout: true} + _, err := New(conf) + require.Error(t, err, "invalid logger config") + }) + + t.Run("Bad level", func(t *testing.T) { + conf := Config{File: "asdafad", Level: "wegretryjt", MuteStdout: true} + _, err := New(conf) + require.Error(t, err, "invalid logger config") + }) +} diff --git a/previewer/main.go b/previewer/main.go new file mode 100644 index 0000000..18350ed --- /dev/null +++ b/previewer/main.go @@ -0,0 +1,19 @@ +package main +import ( + "flag" + oslog "log" + "github/tiburon-777/OTUS_Project/previewer/application" +) + +var ConfigFile = flag.String("config", "/etc/previewer.conf", "Path to configuration file") + +func main() { + flag.Parse() + conf, err := config.NewConfig(*ConfigFile) + if err != nil { + oslog.Fatal("не удалось открыть файл конфигурации:", err.Error()) + } + + app := application.New(&conf) + app.Run() +} \ No newline at end of file diff --git a/previewer/models/models.go b/previewer/models/models.go new file mode 100644 index 0000000..83d43a5 --- /dev/null +++ b/previewer/models/models.go @@ -0,0 +1,5 @@ +package models + +type Config struct { + LruCapasity int +} diff --git a/previewer/webserver/webserver.go b/previewer/webserver/webserver.go new file mode 100644 index 0000000..80c75a2 --- /dev/null +++ b/previewer/webserver/webserver.go @@ -0,0 +1,54 @@ +package webserver + +import ( + "net" + "net/http" + "time" +) + +type Server struct { + *http.Server +} + +func NewServer(address string, port string) http.Server { + return http.Server{Addr: net.JoinHostPort(address, port), Handler: LoggingMiddleware(Handler)} +} + +func Handler(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(200) + _, _ = w.Write([]byte("Hello! I'm calendar app!")) +} + +func LoggingMiddleware(next http.HandlerFunc) http.HandlerFunc { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + defer func() { + var path, useragent string + if r.URL != nil { + path = r.URL.Path + } + if len(r.UserAgent()) > 0 { + useragent = r.UserAgent() + } + latency := time.Since(start) + a.Logger.Infof("receive %s request from IP: %s on path: %s, duration: %s useragent: %s ", r.Method, r.RemoteAddr, path, latency, useragent) + }() + next.ServeHTTP(w, r) + }) +} + +func (s *Server) Start() error { + if err := s.ListenAndServe(); err != nil { + return err + } + s.app.Logger.Infof("Server starting") + return nil +} + +func (s *Server) Stop() error { + if err := s.Close(); err != nil { + return err + } + s.app.Logger.Infof("Server stoped") + return nil +} diff --git a/src/main.go b/src/main.go deleted file mode 100644 index 20be02d..0000000 --- a/src/main.go +++ /dev/null @@ -1,7 +0,0 @@ -package main - -import "log" - -func main() { - log.Println("Начел кончел стоп медвед") -}