HW12 config & logger is completed
parent
34aba1ad22
commit
47e7d8847e
|
@ -1,14 +0,0 @@
|
|||
package main
|
||||
|
||||
// При желании конфигурацию можно вынести в internal/config.
|
||||
// Организация конфига в main принуждает нас сужать API компонентов, использовать
|
||||
// при их конструировании только необходимые параметры, а также уменьшает вероятность циклической зависимости.
|
||||
type Config struct {
|
||||
// TODO
|
||||
}
|
||||
|
||||
func NewConfig() Config {
|
||||
return Config{}
|
||||
}
|
||||
|
||||
// TODO
|
|
@ -2,27 +2,32 @@ package main
|
|||
|
||||
import (
|
||||
"flag"
|
||||
oslog "log"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"github.com/fixme_my_friend/hw12_13_14_15_calendar/internal/app"
|
||||
"github.com/fixme_my_friend/hw12_13_14_15_calendar/internal/logger"
|
||||
internalhttp "github.com/fixme_my_friend/hw12_13_14_15_calendar/internal/server/http"
|
||||
memorystorage "github.com/fixme_my_friend/hw12_13_14_15_calendar/internal/storage/memory"
|
||||
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/internal/config"
|
||||
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/internal/app"
|
||||
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/internal/logger"
|
||||
internalhttp "github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/internal/server/http"
|
||||
memorystorage "github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/internal/storage/memory"
|
||||
)
|
||||
|
||||
var configFile string
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&configFile, "config", "/etc/calendar/config.toml", "Path to configuration file")
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func main() {
|
||||
config := NewConfig()
|
||||
logg := logger.New(config.Logger.Level)
|
||||
conf, err := config.NewConfig(configFile)
|
||||
if err != nil { oslog.Fatal("не удалось открыть файл конфигурации:", err.Error())}
|
||||
|
||||
log, err := logger.New(conf)
|
||||
if err != nil { oslog.Fatal("не удалось запустить логер:", err.Error())}
|
||||
|
||||
storage := memorystorage.New()
|
||||
calendar := app.New(logg, storage)
|
||||
calendar := app.New(log, storage)
|
||||
|
||||
server := internalhttp.NewServer(calendar)
|
||||
|
||||
|
@ -34,12 +39,12 @@ func main() {
|
|||
signal.Stop(signals)
|
||||
|
||||
if err := server.Stop(); err != nil {
|
||||
logger.Error("failed to stop http server: " + err.String())
|
||||
log.Error("failed to stop http server: " + err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
if err := server.Start(); err != nil {
|
||||
logger.Error("failed to start http server: " + err.String())
|
||||
log.Error("failed to start http server: " + err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
[logger]
|
||||
file = "./calendar.log"
|
||||
level = "INFO"
|
||||
|
||||
# TODO
|
||||
# ...
|
||||
[storage]
|
||||
in_memory = false
|
||||
sql_host = "localhost"
|
||||
sql_port = "5432"
|
||||
sql_dbase = "calendar"
|
||||
sql_user = "calendar"
|
||||
sql_pass = "12345678"
|
|
@ -1,3 +1,12 @@
|
|||
module github.com/fixme_my_friend/hw12_13_14_15_calendar
|
||||
module github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/amitrai48/logger v0.0.0-20190214092904-448001c055ec
|
||||
github.com/stretchr/testify v1.4.0
|
||||
go.uber.org/zap v1.15.0
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5
|
||||
gopkg.in/yaml.v2 v2.3.0 // indirect
|
||||
)
|
||||
|
|
|
@ -2,8 +2,6 @@ package app
|
|||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/fixme_my_friend/hw12_13_14_15_calendar/internal/storage"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
|
@ -22,8 +20,9 @@ func New(logger Logger, storage Storage) *App {
|
|||
return &App{}
|
||||
}
|
||||
|
||||
func (a *App) CreateEvent(ctx context.Context, id string, title string) error {
|
||||
return a.storage.CreateEvent(storage.Event{ID: id, Title: title})
|
||||
func (a *App) CreateEvent(ctx context.Context, id string, title string) (err error) {
|
||||
//err = a.storage.CreateEvent(storage.Event{ID: id, Title: title})
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"github.com/BurntSushi/toml"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Logger struct{
|
||||
File string
|
||||
Level string
|
||||
MuteStdout bool
|
||||
}
|
||||
Storage struct {
|
||||
In_memory bool
|
||||
Sql_host string
|
||||
Sql_port string
|
||||
Sql_dbase string
|
||||
Sql_user string
|
||||
Sql_pass string
|
||||
}
|
||||
}
|
||||
|
||||
// Confita может быти и хороша, но она не возвращает ошибки, если не может распарсить файл в структуру. Мне не нравится такая "молчаливость"
|
||||
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
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
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(`[storage]
|
||||
in_memory = true
|
||||
sql_host = "localhost"`)
|
||||
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,true,c.Storage.In_memory)
|
||||
require.Equal(t,"localhost",c.Storage.Sql_host)
|
||||
require.NoError(t,e)
|
||||
})
|
||||
|
||||
}
|
|
@ -1,11 +1,76 @@
|
|||
package logger
|
||||
|
||||
type Logger struct {
|
||||
// TODO
|
||||
import (
|
||||
"errors"
|
||||
amitralog "github.com/amitrai48/logger"
|
||||
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/internal/config"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Logger interface {
|
||||
Debug(msg string)
|
||||
Info(msg string)
|
||||
Warn(msg string)
|
||||
Error(msg string)
|
||||
Fatal(msg string)
|
||||
}
|
||||
|
||||
func New(level string) *Logger {
|
||||
return &Logger{}
|
||||
type Log struct {
|
||||
Logger amitralog.Logger
|
||||
}
|
||||
|
||||
// TODO
|
||||
func New(conf config.Config) (Log, error) {
|
||||
|
||||
if conf.Logger.File=="" || !validLevel(conf.Logger.Level) {
|
||||
return Log{}, errors.New("invalid logger config")
|
||||
}
|
||||
|
||||
c := amitralog.Configuration{
|
||||
EnableConsole: !conf.Logger.MuteStdout,
|
||||
ConsoleLevel: amitralog.Fatal,
|
||||
ConsoleJSONFormat: false,
|
||||
EnableFile: true,
|
||||
FileLevel: strings.ToLower(conf.Logger.Level),
|
||||
FileJSONFormat: true,
|
||||
FileLocation: conf.Logger.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 Log{Logger: l}, nil
|
||||
}
|
||||
|
||||
func (l Log) Debug(format string, args ...interface{}) {
|
||||
l.Logger.Debugf(format, args)
|
||||
}
|
||||
|
||||
func (l *Log) Info(format string, args ...interface{}) {
|
||||
l.Logger.Infof(format, args)
|
||||
}
|
||||
|
||||
func (l *Log) Warn(format string, args ...interface{}) {
|
||||
l.Logger.Warnf(format, args)
|
||||
}
|
||||
|
||||
func (l *Log) Error(format string, args ...interface{}) {
|
||||
l.Logger.Errorf(format, args)
|
||||
}
|
||||
|
||||
func (l *Log) Fatal(format string, args ...interface{}) {
|
||||
l.Logger.Fatalf(format, args)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
func validLevel(level string) bool {
|
||||
l := []string{"debug","info","warn","error","fatal"}
|
||||
for _,v:=range l {
|
||||
if strings.ToLower(level)==v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -1,7 +1,57 @@
|
|||
package logger
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/internal/config"
|
||||
"io/ioutil"
|
||||
oslog "log"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLogger(t *testing.T) {
|
||||
// TODO
|
||||
func TestLoggerLogic(t *testing.T) {
|
||||
tmpfile, err := ioutil.TempFile("", "log.")
|
||||
if err != nil { oslog.Fatal(err) }
|
||||
defer os.Remove(tmpfile.Name())
|
||||
|
||||
conf := config.Config{Logger: struct {
|
||||
File string
|
||||
Level string
|
||||
MuteStdout bool
|
||||
}{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.Debug("debug message")
|
||||
log.Error("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.Config{Logger: struct {
|
||||
File string
|
||||
Level string
|
||||
MuteStdout bool
|
||||
}{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.Config{Logger: struct {
|
||||
File string
|
||||
Level string
|
||||
MuteStdout bool
|
||||
}{File: "asdafad", Level: "wegretryjt", MuteStdout: true}}
|
||||
_, err := New(conf)
|
||||
require.Error(t,err,"invalid logger config")
|
||||
})
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
package internalhttp
|
||||
|
||||
import "context"
|
||||
|
||||
type Server struct {
|
||||
// TODO
|
||||
}
|
||||
|
@ -16,11 +14,13 @@ func NewServer(app Application) *Server {
|
|||
|
||||
func (s *Server) Start() error {
|
||||
// TODO
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) Stop() error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
|
||||
//ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
|
||||
// TODO
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
|
|
@ -12,8 +12,10 @@ func New() *Storage {
|
|||
|
||||
func (s *Storage) Connect(ctx context.Context) error {
|
||||
// TODO
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Storage) Close(ctx context.Context) error {
|
||||
// TODO
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue