diff --git a/go.mod b/go.mod index 8ae35e3..c13c698 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,8 @@ require ( github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 github.com/pkg/errors v0.9.1 - github.com/tkw1536/goprogram v0.2.1 + github.com/rs/zerolog v1.28.0 + github.com/tkw1536/goprogram v0.2.2 golang.org/x/crypto v0.3.0 golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9 golang.org/x/sync v0.1.0 @@ -27,6 +28,7 @@ require ( github.com/jessevdk/go-flags v1.5.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.16 // indirect golang.org/x/sys v0.2.0 // indirect ) diff --git a/go.sum b/go.sum index 6dd52eb..505dfc3 100644 --- a/go.sum +++ b/go.sum @@ -6,12 +6,14 @@ github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVK github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/feiin/sqlstring v0.3.0 h1:iyPEFijI2BxpY2M+AuhIvdNManzXa2OwGzuPaEMLUgo= github.com/feiin/sqlstring v0.3.0/go.mod h1:xpZTjVUw1nD3hMgF9SMRdPiooKSikLf4PS5j2NTn3RI= github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= @@ -25,12 +27,19 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/tkw1536/goprogram v0.2.1 h1:7HtFn52iqVWtv7VQUgyU3apH30b0k3b4jAtwz0O9KOU= -github.com/tkw1536/goprogram v0.2.1/go.mod h1:Jqs0sTMzhrAGCX3JQrlEwQ0WRWQACCvuQQkaBDp65pE= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY= +github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= +github.com/tkw1536/goprogram v0.2.2 h1:ivlySfJb154WsVOp5zxREQjBledxVEUOL0sBIkznOOI= +github.com/tkw1536/goprogram v0.2.2/go.mod h1:Jqs0sTMzhrAGCX3JQrlEwQ0WRWQACCvuQQkaBDp65pE= golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= @@ -44,6 +53,8 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/internal/cli/flags.go b/internal/cli/flags.go index 9a85009..ebf6812 100644 --- a/internal/cli/flags.go +++ b/internal/cli/flags.go @@ -1,8 +1,21 @@ package cli +import "github.com/rs/zerolog" + // Flags are global flags for the wdcli executable type Flags struct { - ConfigPath string `short:"c" long:"config" description:"Path to distillery configuration file"` + LogLevel LogLevelString `short:"l" long:"loglevel" description:"Log level to use for logger" default:"info" choice:"trace" choice:"debug" choice:"info" choice:"warn" choice:"error" choice:"fatal" choice:"panic"` + ConfigPath string `short:"c" long:"config" description:"Path to distillery configuration file"` InternalInDocker bool `long:"internal-in-docker" description:"Internal Flag to signal the shell that it is running inside a docker stack belonging to the distillery"` } + +type LogLevelString string + +func (ls LogLevelString) Level() zerolog.Level { + level, err := zerolog.ParseLevel(string(ls)) + if err != nil { + return zerolog.InfoLevel + } + return level +} diff --git a/internal/dis/component/sql/connect.go b/internal/dis/component/sql/connect.go index 84e7fe4..02974b7 100644 --- a/internal/dis/component/sql/connect.go +++ b/internal/dis/component/sql/connect.go @@ -52,9 +52,13 @@ func (sql *SQL) QueryTable(ctx context.Context, silent bool, table string) (*gor } // gorm configuration - config := &gorm.Config{} + config := &gorm.Config{ + Logger: newGormLogger(), + } if silent { - config.Logger = logger.Default.LogMode(logger.Silent) + config.Logger = config.Logger.LogMode(logger.Silent) + } else { + config.Logger = config.Logger.LogMode(logger.Info) } // mysql connection diff --git a/internal/dis/component/sql/logger.go b/internal/dis/component/sql/logger.go new file mode 100644 index 0000000..304b9c2 --- /dev/null +++ b/internal/dis/component/sql/logger.go @@ -0,0 +1,74 @@ +package sql + +import ( + "context" + "errors" + "time" + + "github.com/rs/zerolog" + "gorm.io/gorm/logger" + "gorm.io/gorm/utils" +) + +// logger implements "gorm/logger.Interface" +type gormLogger struct { + Level logger.LogLevel + SlowThreshold time.Duration + IgnoreRecordNotFoundError bool +} + +func newGormLogger() logger.Interface { + return &gormLogger{ + Level: logger.Info, + SlowThreshold: 200 * time.Millisecond, + IgnoreRecordNotFoundError: false, + } +} + +func (gl *gormLogger) LogMode(level logger.LogLevel) logger.Interface { + new := *gl + new.Level = level + return &new +} + +func (gl *gormLogger) Info(ctx context.Context, format string, v ...interface{}) { + if gl.Level < logger.Info { + return + } + zerolog.Ctx(ctx).Info().Msgf(format, v...) +} +func (gl *gormLogger) Warn(ctx context.Context, format string, v ...interface{}) { + if gl.Level < logger.Warn { + return + } + zerolog.Ctx(ctx).Warn().Msgf(format, v...) +} +func (gl *gormLogger) Error(ctx context.Context, format string, v ...interface{}) { + if gl.Level < logger.Error { + return + } + zerolog.Ctx(ctx).Error().Msgf(format, v...) +} +func (gl *gormLogger) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) { + if gl.Level < logger.Silent { + return + } + + elapsed := time.Since(begin) + switch { + case err != nil && gl.Level >= logger.Error && (!errors.Is(err, logger.ErrRecordNotFound) || !gl.IgnoreRecordNotFoundError): + sql, rows := fc() + src := utils.FileWithLineNum() + + zerolog.Ctx(ctx).Err(err).Str("src", src).Int64("rows", rows).Dur("elapsed", elapsed).Str("sql", sql).Msg("GORM") + case elapsed > gl.SlowThreshold && gl.SlowThreshold != 0 && gl.Level >= logger.Warn: + sql, rows := fc() + src := utils.FileWithLineNum() + zerolog.Ctx(ctx).Warn().Str("src", src).Int64("rows", rows).Dur("elapsed", elapsed).Str("sql", sql).Msgf("GORM: Slow SQL >= ", gl.SlowThreshold) + case gl.Level == logger.Info: + sql, rows := fc() + src := utils.FileWithLineNum() + + zerolog.Ctx(ctx).Debug().Str("src", src).Int64("rows", rows).Dur("elapsed", elapsed).Str("sql", sql).Msg("GORM") + } +} diff --git a/program.go b/program.go index 4b3cc88..ec3bc07 100644 --- a/program.go +++ b/program.go @@ -9,6 +9,7 @@ import ( "github.com/FAU-CDI/wisski-distillery/internal/bootstrap" "github.com/FAU-CDI/wisski-distillery/internal/cli" "github.com/FAU-CDI/wisski-distillery/internal/dis" + "github.com/rs/zerolog" "github.com/tkw1536/goprogram" "github.com/tkw1536/goprogram/exit" ) @@ -50,6 +51,8 @@ type Arguments = goprogram.Arguments[wdCliFlags] type ContextCleanupFunc = goprogram.ContextCleanupFunc[wdcliEnv, wdcliParameters, wdCliFlags, wdcliRequirements] type Description = goprogram.Description[wdCliFlags, wdcliRequirements] +var GetContext = goprogram.GetContext[wdcliEnv, wdcliParameters, wdCliFlags, wdcliRequirements] + // an error when nor arguments are provided. var errUserIsNotRoot = exit.Error{ ExitCode: exit.ExitGeneralArguments, @@ -80,8 +83,18 @@ func NewProgram() Program { if params == nil { return parent, nil, nil } - ctx, stop := signal.NotifyContext(parent, os.Interrupt) - // ctx = zerolog.New(zerolog.NewConsoleWriter()).WithContext(ctx) + + { + context := GetContext(parent) + writer := zerolog.NewConsoleWriter() + writer.Out = context.Stdout + + logger := zerolog.New(writer).Level(context.Args.Flags.LogLevel.Level()) + + parent = logger.WithContext(parent) + } + + ctx, stop := signal.NotifyContext(parent, os.Interrupt, os.Kill) return ctx, func(context *Context) { stop() }, nil },