diff --git a/cmd/server/flags.go b/cmd/server/flags.go index 38a312df8..bb22fd6e9 100644 --- a/cmd/server/flags.go +++ b/cmd/server/flags.go @@ -29,6 +29,16 @@ var flags = []cli.Flag{ Name: "log-level", Usage: "set logging level", }, + &cli.BoolFlag{ + EnvVars: []string{"WOODPECKER_LOG_XORM"}, + Name: "log-xorm", + Usage: "enable xorm logging", + }, + &cli.BoolFlag{ + EnvVars: []string{"WOODPECKER_LOG_XORM_SQL"}, + Name: "log-xorm-sql", + Usage: "enable xorm sql command logging", + }, &cli.BoolFlag{ EnvVars: []string{"WOODPECKER_DEBUG_PRETTY"}, Name: "pretty", diff --git a/cmd/server/setup.go b/cmd/server/setup.go index 0a3c66af2..99a8d76bd 100644 --- a/cmd/server/setup.go +++ b/cmd/server/setup.go @@ -54,6 +54,10 @@ import ( func setupStore(c *cli.Context) (store.Store, error) { datasource := c.String("datasource") driver := c.String("driver") + xorm := store.XORM{ + Log: c.Bool("log-xorm"), + ShowSQL: c.Bool("log-xorm-sql"), + } if driver == "sqlite3" { if datastore.SupportedDriver("sqlite3") { @@ -78,6 +82,7 @@ func setupStore(c *cli.Context) (store.Store, error) { opts := &store.Opts{ Driver: driver, Config: datasource, + XORM: xorm, } log.Trace().Msgf("setup datastore: %#v", *opts) store, err := datastore.NewEngine(opts) diff --git a/docs/docs/30-administration/10-server-config.md b/docs/docs/30-administration/10-server-config.md index fe54c14ec..9c111257d 100644 --- a/docs/docs/30-administration/10-server-config.md +++ b/docs/docs/30-administration/10-server-config.md @@ -189,6 +189,16 @@ The following list describes all available server configuration options. Configures the logging level. Possible values are `trace`, `debug`, `info`, `warn`, `error`, `fatal`, `panic`, `disabled` and empty. +### `WOODPECKER_LOG_XORM` +> Default: `false` + +Enable XORM logs. + +### `WOODPECKER_LOG_XORM_SQL` +> Default: `false` + +Enable XORM SQL command logs. + ### `WOODPECKER_DEBUG_PRETTY` > Default: `false` diff --git a/server/store/common.go b/server/store/common.go index 7d984f435..ee919991d 100644 --- a/server/store/common.go +++ b/server/store/common.go @@ -14,8 +14,14 @@ package store +type XORM struct { + Log bool + ShowSQL bool +} + // Opts are options for a new database connection type Opts struct { Driver string Config string + XORM XORM } diff --git a/server/store/datastore/engine.go b/server/store/datastore/engine.go index a761e316c..d856f6acd 100644 --- a/server/store/datastore/engine.go +++ b/server/store/datastore/engine.go @@ -15,10 +15,12 @@ package datastore import ( + "github.com/rs/zerolog" "github.com/woodpecker-ci/woodpecker/server/store" "github.com/woodpecker-ci/woodpecker/server/store/datastore/migration" "xorm.io/xorm" + xlog "xorm.io/xorm/log" ) type storage struct { @@ -33,7 +35,15 @@ func NewEngine(opts *store.Opts) (store.Store, error) { return nil, err } - // engine.SetLogger(X) // TODO: special config to enable xorm logging + level := xlog.LogLevel(zerolog.GlobalLevel()) + if !opts.XORM.Log { + level = xlog.LOG_OFF + } + + logger := newXORMLogger(level) + engine.SetLogger(logger) + engine.ShowSQL(opts.XORM.ShowSQL) + return &storage{ engine: engine, }, nil diff --git a/server/store/datastore/xorm.go b/server/store/datastore/xorm.go new file mode 100644 index 000000000..8e3536901 --- /dev/null +++ b/server/store/datastore/xorm.go @@ -0,0 +1,117 @@ +// Copyright 2023 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datastore + +import ( + "fmt" + + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + xlog "xorm.io/xorm/log" +) + +func newXORMLogger(level xlog.LogLevel) xlog.Logger { + return &xormLogger{ + logger: log.With().Str("component", "xorm").Logger(), + level: level, + } +} + +// xormLogger custom log implementation for ILogger +type xormLogger struct { + logger zerolog.Logger + level xlog.LogLevel + showSQL bool +} + +// Error implement ILogger +func (x *xormLogger) Error(v ...interface{}) { + if x.level <= xlog.LOG_ERR { + x.logger.Error().Msg(fmt.Sprintln(v...)) + } +} + +// Errorf implement ILogger +func (x *xormLogger) Errorf(format string, v ...interface{}) { + if x.level <= xlog.LOG_ERR { + x.logger.Error().Msg(fmt.Sprintf(format, v...)) + } +} + +// Debug implement ILogger +func (x *xormLogger) Debug(v ...interface{}) { + if x.level <= xlog.LOG_DEBUG { + x.logger.Debug().Msg(fmt.Sprintln(v...)) + } +} + +// Debugf implement ILogger +func (x *xormLogger) Debugf(format string, v ...interface{}) { + if x.level <= xlog.LOG_DEBUG { + x.logger.Debug().Msg(fmt.Sprintf(format, v...)) + } +} + +// Info implement ILogger +func (x *xormLogger) Info(v ...interface{}) { + if x.level <= xlog.LOG_INFO { + x.logger.Info().Msg(fmt.Sprintln(v...)) + } +} + +// Infof implement ILogger +func (x *xormLogger) Infof(format string, v ...interface{}) { + if x.level <= xlog.LOG_INFO { + x.logger.Info().Msg(fmt.Sprintf(format, v...)) + } +} + +// Warn implement ILogger +func (x *xormLogger) Warn(v ...interface{}) { + if x.level <= xlog.LOG_WARNING { + x.logger.Warn().Msg(fmt.Sprintln(v...)) + } +} + +// Warnf implement ILogger +func (x *xormLogger) Warnf(format string, v ...interface{}) { + if x.level <= xlog.LOG_WARNING { + x.logger.Warn().Msg(fmt.Sprintf(format, v...)) + } +} + +// Level implement ILogger +func (x *xormLogger) Level() xlog.LogLevel { + return xlog.LOG_INFO +} + +// SetLevel implement ILogger +func (x *xormLogger) SetLevel(l xlog.LogLevel) { + x.level = l +} + +// ShowSQL implement ILogger +func (x *xormLogger) ShowSQL(show ...bool) { + if len(show) == 0 { + x.showSQL = true + return + } + x.showSQL = show[0] +} + +// IsShowSQL implement ILogger +func (x *xormLogger) IsShowSQL() bool { + return x.showSQL +}