diff --git a/back/cmd/openbsrv/httpsrv.go b/back/cmd/openbsrv/httpsrv.go index 0ebad9a..d2e1f00 100644 --- a/back/cmd/openbsrv/httpsrv.go +++ b/back/cmd/openbsrv/httpsrv.go @@ -1,8 +1,9 @@ package main import ( - "github.com/OpenEugene/openboard/back/internal/httpsrv" "github.com/codemodus/hedrs" + + "github.com/OpenEugene/openboard/back/internal/httpsrv" ) type httpSrv struct { diff --git a/back/cmd/openbsrv/main.go b/back/cmd/openbsrv/main.go index 0c623a3..e782370 100644 --- a/back/cmd/openbsrv/main.go +++ b/back/cmd/openbsrv/main.go @@ -7,6 +7,9 @@ import ( "path" "github.com/codemodus/sigmon/v2" + + "github.com/OpenEugene/openboard/back/internal/dbg" + "github.com/OpenEugene/openboard/back/internal/log" ) func main() { @@ -28,6 +31,7 @@ func run() error { migrate bool rollback bool skipsrv bool + debug bool frontDir = "../../../front/public" migTblPfx = "mig_" ) @@ -40,6 +44,7 @@ func run() error { flag.BoolVar(&migrate, "migrate", migrate, "migrate up") flag.BoolVar(&rollback, "rollback", rollback, "migrate dn") flag.BoolVar(&skipsrv, "skipsrv", skipsrv, "skip server run") + flag.BoolVar(&debug, "debug", debug, "debug true or false") flag.StringVar(&frontDir, "frontdir", frontDir, "front public assets directory") flag.Parse() @@ -47,6 +52,23 @@ func run() error { sm.Start() defer sm.Stop() + logCfg := log.Config{ + Err: log.Output{ + Out: os.Stdout, + Prefix: "[ERROR] ", + }, + Inf: log.Output{ + Out: os.Stdout, + Prefix: "[INFO] ", + }, + } + log := log.New(logCfg) + + if debug { + dbg.SetOut(os.Stdout) + } + + dbg.Logf("set up SQL database at %s:%s.", dbaddr, dbport) db, err := newSQLDB(dbdrvr, dbCreds(dbname, dbuser, dbpass, dbaddr, dbport)) if err != nil { return err @@ -67,7 +89,7 @@ func run() error { if mres.HasError() { return mres.ErrsErr() } - fmt.Println(migType+":", mres) + log.Info("%s: %s", migType, mres) } if skipsrv { @@ -93,7 +115,7 @@ func run() error { } }) - fmt.Println("to gracefully stop the application, send signal like TERM (CTRL-C) or HUP") + log.Info("to gracefully stop the application, send signal like TERM (CTRL-C) or HUP") return m.serve() } diff --git a/back/internal/authsvc/authsvc.go b/back/internal/authsvc/authsvc.go index 67fd119..df77355 100644 --- a/back/internal/authsvc/authsvc.go +++ b/back/internal/authsvc/authsvc.go @@ -3,8 +3,9 @@ package authsvc import ( "context" - "github.com/OpenEugene/openboard/back/internal/pb" "google.golang.org/grpc" + + "github.com/OpenEugene/openboard/back/internal/pb" ) var _ pb.AuthServer = &AuthSvc{} @@ -30,7 +31,6 @@ func (s *AuthSvc) RegisterWithGRPCServer(g *grpc.Server) error { // AddAuth implements part of the pb.AuthServer interface. func (s *AuthSvc) AddAuth(ctx context.Context, req *pb.AddAuthReq) (*pb.AuthResp, error) { // TODO: implement AddAuth - return nil, nil } diff --git a/back/internal/dbg/dbg.go b/back/internal/dbg/dbg.go new file mode 100644 index 0000000..61092fc --- /dev/null +++ b/back/internal/dbg/dbg.go @@ -0,0 +1,64 @@ +// Package dbg allows for outputting information that can help with debugging +// the application. +package dbg + +import ( + "io" + "log" + "sync/atomic" +) + +// dbg is thread-safe. +type dbg struct { + atomVal atomic.Value +} + +func new() *dbg { + var d dbg + var logr *log.Logger + d.atomVal.Store(logr) + return &d +} + +func (d *dbg) logln(as ...interface{}) { + logr := d.atomVal.Load().(*log.Logger) + if logr != nil { + logr.Println(as...) + } +} + +func (d *dbg) logf(format string, as ...interface{}) { + logr := d.atomVal.Load().(*log.Logger) + if logr != nil { + logr.Printf(format+"\n", as...) + } +} + +func (d *dbg) setOut(out io.Writer) { + var logr *log.Logger + + if out != nil { + logr = log.New(out, "", 0) + d.atomVal.Store(logr) + return + } + + d.atomVal.Store(logr) +} + +var debug = new() + +// Log outputs information to help with application debugging. +func Log(as ...interface{}) { + debug.logln(as...) +} + +// Logf outputs debugging information and is able to interpret formatting verbs. +func Logf(format string, as ...interface{}) { + debug.logf(format, as...) +} + +// SetDebugOut allows for choosing where debug information will be written to. +func SetOut(out io.Writer) { + debug.setOut(out) +} diff --git a/back/internal/dbg/dbg_test.go b/back/internal/dbg/dbg_test.go new file mode 100644 index 0000000..da2abe1 --- /dev/null +++ b/back/internal/dbg/dbg_test.go @@ -0,0 +1,74 @@ +package dbg + +import ( + "bytes" + "fmt" + "io/ioutil" + "testing" +) + +func BenchmarkDbgUse(b *testing.B) { + SetOut(ioutil.Discard) + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Log("") + } + }) +} +func BenchmarkDbgUseNil(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Log("") + } + }) +} +func BenchmarkDbgSetAndUse(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + SetOut(ioutil.Discard) + Log("") + } + }) +} +func BenchmarkDbgSetAndUseNil(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + SetOut(nil) + Log("") + } + }) +} + +func TestSetOut(t *testing.T) { + Log("debug not set") + + buff := bytes.NewBuffer([]byte{}) + SetOut(buff) + msg := "debug set to bytes buffer" + Log(msg) + got := buff.String() + + want := msg + "\n" + if got != want { + t.Errorf("want: %s, got: %s", want, got) + } + + SetOut(nil) + buff.Reset() + want = "" + Log("debug set to nil") + got = buff.String() + if got != want { + t.Errorf("want: nothing, got: %s", got) + } + + SetOut(buff) + buff.Reset() + msg = "debug set to bytes buffer, %s time" + Logf(msg, "second") + got = buff.String() + want = fmt.Sprintf(msg+"\n", "second") + if got != want { + t.Errorf("want: %s, got: %s", want, got) + } +} diff --git a/back/internal/log/log.go b/back/internal/log/log.go new file mode 100644 index 0000000..64503ff --- /dev/null +++ b/back/internal/log/log.go @@ -0,0 +1,45 @@ +// Package log allows for outputting information regarding application errors +// and events important to know for proper operation. +package log + +import ( + "io" + "log" +) + +// Output is where logger will write to. Prefix is what will precede log text. +type Output struct { + Out io.Writer + Prefix string +} + +// Config allows for configuring the logger outputs for errors and information +// type log messages. +type Config struct { + Err Output + Inf Output +} + +// Log is able to write information to a chosen output. +type Log struct { + err *log.Logger + inf *log.Logger +} + +// New provides a pointer to a new instance of the Log object. +func New(c Config) *Log { + return &Log{ + inf: log.New(c.Inf.Out, c.Inf.Prefix, 0), + err: log.New(c.Err.Out, c.Err.Prefix, 0), + } +} + +// Info outputs information from the application. +func (log *Log) Info(format string, as ...interface{}) { + log.inf.Printf(format+"\n", as...) +} + +// Error outputs error information from the application. +func (log *Log) Error(format string, as ...interface{}) { + log.err.Printf(format+"\n", as...) +} diff --git a/back/internal/postsvc/postsvc.go b/back/internal/postsvc/postsvc.go index be1a297..67f4fbc 100644 --- a/back/internal/postsvc/postsvc.go +++ b/back/internal/postsvc/postsvc.go @@ -4,10 +4,11 @@ import ( "context" "database/sql" + "google.golang.org/grpc" + "github.com/OpenEugene/openboard/back/internal/pb" "github.com/OpenEugene/openboard/back/internal/postsvc/internal/postdb" "github.com/OpenEugene/openboard/back/internal/postsvc/internal/postdb/mysqlmig" - "google.golang.org/grpc" ) var _ pb.PostServer = &PostSvc{}