Browse Source

logger: add a flag to use UTC time for logging

Nicola Murino 4 years ago
parent
commit
094ee1522e

+ 12 - 0
cmd/root.go

@@ -28,6 +28,8 @@ const (
 	logCompressKey           = "log_compress"
 	logCompressKey           = "log_compress"
 	logVerboseFlag           = "log-verbose"
 	logVerboseFlag           = "log-verbose"
 	logVerboseKey            = "log_verbose"
 	logVerboseKey            = "log_verbose"
+	logUTCTimeFlag           = "log-utc-time"
+	logUTCTimeKey            = "log_utc_time"
 	loadDataFromFlag         = "loaddata-from"
 	loadDataFromFlag         = "loaddata-from"
 	loadDataFromKey          = "loaddata_from"
 	loadDataFromKey          = "loaddata_from"
 	loadDataModeFlag         = "loaddata-mode"
 	loadDataModeFlag         = "loaddata-mode"
@@ -44,6 +46,7 @@ const (
 	defaultLogMaxAge         = 28
 	defaultLogMaxAge         = 28
 	defaultLogCompress       = false
 	defaultLogCompress       = false
 	defaultLogVerbose        = true
 	defaultLogVerbose        = true
+	defaultLogUTCTime        = false
 	defaultLoadDataFrom      = ""
 	defaultLoadDataFrom      = ""
 	defaultLoadDataMode      = 1
 	defaultLoadDataMode      = 1
 	defaultLoadDataQuotaScan = 0
 	defaultLoadDataQuotaScan = 0
@@ -59,6 +62,7 @@ var (
 	logMaxAge         int
 	logMaxAge         int
 	logCompress       bool
 	logCompress       bool
 	logVerbose        bool
 	logVerbose        bool
+	logUTCTime        bool
 	loadDataFrom      string
 	loadDataFrom      string
 	loadDataMode      int
 	loadDataMode      int
 	loadDataQuotaScan int
 	loadDataQuotaScan int
@@ -180,6 +184,14 @@ using SFTPGO_LOG_VERBOSE env var too.
 `)
 `)
 	viper.BindPFlag(logVerboseKey, cmd.Flags().Lookup(logVerboseFlag)) //nolint:errcheck
 	viper.BindPFlag(logVerboseKey, cmd.Flags().Lookup(logVerboseFlag)) //nolint:errcheck
 
 
+	viper.SetDefault(logUTCTimeKey, defaultLogUTCTime)
+	viper.BindEnv(logUTCTimeKey, "SFTPGO_LOG_UTC_TIME") //nolint:errcheck
+	cmd.Flags().BoolVar(&logUTCTime, logUTCTimeFlag, viper.GetBool(logUTCTimeKey),
+		`Use UTC time for logging. This flag can be set
+using SFTPGO_LOG_UTC_TIME env var too.
+`)
+	viper.BindPFlag(logUTCTimeKey, cmd.Flags().Lookup(logUTCTimeFlag)) //nolint:errcheck
+
 	viper.SetDefault(loadDataFromKey, defaultLoadDataFrom)
 	viper.SetDefault(loadDataFromKey, defaultLoadDataFrom)
 	viper.BindEnv(loadDataFromKey, "SFTPGO_LOADDATA_FROM") //nolint:errcheck
 	viper.BindEnv(loadDataFromKey, "SFTPGO_LOADDATA_FROM") //nolint:errcheck
 	cmd.Flags().StringVar(&loadDataFrom, loadDataFromFlag, viper.GetString(loadDataFromKey),
 	cmd.Flags().StringVar(&loadDataFrom, loadDataFromFlag, viper.GetString(loadDataFromKey),

+ 1 - 0
cmd/serve.go

@@ -29,6 +29,7 @@ Please take a look at the usage below to customize the startup options`,
 				LogMaxAge:         logMaxAge,
 				LogMaxAge:         logMaxAge,
 				LogCompress:       logCompress,
 				LogCompress:       logCompress,
 				LogVerbose:        logVerbose,
 				LogVerbose:        logVerbose,
+				LogUTCTime:        logUTCTime,
 				LoadDataFrom:      loadDataFrom,
 				LoadDataFrom:      loadDataFrom,
 				LoadDataMode:      loadDataMode,
 				LoadDataMode:      loadDataMode,
 				LoadDataQuotaScan: loadDataQuotaScan,
 				LoadDataQuotaScan: loadDataQuotaScan,

+ 9 - 0
cmd/startsubsys.go

@@ -44,6 +44,7 @@ Command-line flags should be specified in the Subsystem declaration.
 			if !logVerbose {
 			if !logVerbose {
 				logLevel = zerolog.InfoLevel
 				logLevel = zerolog.InfoLevel
 			}
 			}
+			logger.SetLogTime(logUTCTime)
 			if logJournalD {
 			if logJournalD {
 				logger.InitJournalDLogger(logLevel)
 				logger.InitJournalDLogger(logLevel)
 			} else {
 			} else {
@@ -180,5 +181,13 @@ using SFTPGO_LOG_VERBOSE env var too.
 `)
 `)
 	viper.BindPFlag(logVerboseKey, subsystemCmd.Flags().Lookup(logVerboseFlag)) //nolint:errcheck
 	viper.BindPFlag(logVerboseKey, subsystemCmd.Flags().Lookup(logVerboseFlag)) //nolint:errcheck
 
 
+	viper.SetDefault(logUTCTimeKey, defaultLogUTCTime)
+	viper.BindEnv(logUTCTimeKey, "SFTPGO_LOG_UTC_TIME") //nolint:errcheck
+	subsystemCmd.Flags().BoolVar(&logUTCTime, logUTCTimeFlag, viper.GetBool(logUTCTimeKey),
+		`Use UTC time for logging. This flag can be set
+using SFTPGO_LOG_UTC_TIME env var too.
+`)
+	viper.BindPFlag(logUTCTimeKey, subsystemCmd.Flags().Lookup(logUTCTimeFlag)) //nolint:errcheck
+
 	rootCmd.AddCommand(subsystemCmd)
 	rootCmd.AddCommand(subsystemCmd)
 }
 }

+ 1 - 1
common/protocol_test.go

@@ -63,7 +63,7 @@ var (
 func TestMain(m *testing.M) {
 func TestMain(m *testing.M) {
 	homeBasePath = os.TempDir()
 	homeBasePath = os.TempDir()
 	logFilePath := filepath.Join(configDir, "common_test.log")
 	logFilePath := filepath.Join(configDir, "common_test.log")
-	logger.InitLogger(logFilePath, 5, 1, 28, false, zerolog.DebugLevel)
+	logger.InitLogger(logFilePath, 5, 1, 28, false, false, zerolog.DebugLevel)
 
 
 	os.Setenv("SFTPGO_DATA_PROVIDER__CREATE_DEFAULT_ADMIN", "1")
 	os.Setenv("SFTPGO_DATA_PROVIDER__CREATE_DEFAULT_ADMIN", "1")
 	os.Setenv("SFTPGO_DEFAULT_ADMIN_USERNAME", "admin")
 	os.Setenv("SFTPGO_DEFAULT_ADMIN_USERNAME", "admin")

+ 16 - 4
dataprovider/bolt.go

@@ -1185,15 +1185,18 @@ func (p *BoltProvider) updateShare(share *Share) error {
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		var a []byte
+		var s []byte
 
 
-		if a = bucket.Get([]byte(share.ShareID)); a == nil {
+		if s = bucket.Get([]byte(share.ShareID)); s == nil {
 			return util.NewRecordNotFoundError(fmt.Sprintf("Share %v does not exist", share.ShareID))
 			return util.NewRecordNotFoundError(fmt.Sprintf("Share %v does not exist", share.ShareID))
 		}
 		}
 		var oldObject Share
 		var oldObject Share
-		if err = json.Unmarshal(a, &oldObject); err != nil {
+		if err = json.Unmarshal(s, &oldObject); err != nil {
 			return err
 			return err
 		}
 		}
+		if oldObject.Username != share.Username {
+			return util.NewRecordNotFoundError(fmt.Sprintf("Share %v does not exist", share.ShareID))
+		}
 
 
 		share.ID = oldObject.ID
 		share.ID = oldObject.ID
 		share.ShareID = oldObject.ShareID
 		share.ShareID = oldObject.ShareID
@@ -1219,7 +1222,16 @@ func (p *BoltProvider) deleteShare(share *Share) error {
 			return err
 			return err
 		}
 		}
 
 
-		if bucket.Get([]byte(share.ShareID)) == nil {
+		var s []byte
+
+		if s = bucket.Get([]byte(share.ShareID)); s == nil {
+			return util.NewRecordNotFoundError(fmt.Sprintf("Share %v does not exist", share.ShareID))
+		}
+		var oldObject Share
+		if err = json.Unmarshal(s, &oldObject); err != nil {
+			return err
+		}
+		if oldObject.Username != share.Username {
 			return util.NewRecordNotFoundError(fmt.Sprintf("Share %v does not exist", share.ShareID))
 			return util.NewRecordNotFoundError(fmt.Sprintf("Share %v does not exist", share.ShareID))
 		}
 		}
 
 

+ 1 - 1
docs/full-configuration.md

@@ -39,7 +39,7 @@ The `serve` command supports the following flags:
 - `--log-max-backups` int. Maximum number of old log files to retain. Default 5 or the value of `SFTPGO_LOG_MAX_BACKUPS` environment variable. It is unused if `log-file-path` is empty.
 - `--log-max-backups` int. Maximum number of old log files to retain. Default 5 or the value of `SFTPGO_LOG_MAX_BACKUPS` environment variable. It is unused if `log-file-path` is empty.
 - `--log-max-size` int. Maximum size in megabytes of the log file before it gets rotated. Default 10 or the value of `SFTPGO_LOG_MAX_SIZE` environment variable. It is unused if `log-file-path` is empty.
 - `--log-max-size` int. Maximum size in megabytes of the log file before it gets rotated. Default 10 or the value of `SFTPGO_LOG_MAX_SIZE` environment variable. It is unused if `log-file-path` is empty.
 - `--log-verbose` boolean. Enable verbose logs. Default `true` or the value of `SFTPGO_LOG_VERBOSE` environment variable (1 or `true`, 0 or `false`).
 - `--log-verbose` boolean. Enable verbose logs. Default `true` or the value of `SFTPGO_LOG_VERBOSE` environment variable (1 or `true`, 0 or `false`).
-- `--profiler` boolean. Enable the built-in profiler. The profiler will be accessible via HTTP/HTTPS using the base URL "/debug/pprof/". Default `false` or the value of `SFTPGO_PROFILER` environment variable (1 or `true`, 0 or `false`).
+- `--log-utc-time` boolean. Enable UTC time for logging. Default `false` or the value of `SFTPGO_LOG_UTC_TIME` environment variable (1 or `true`, 0 or `false`)
 
 
 Log file can be rotated on demand sending a `SIGUSR1` signal on Unix based systems and using the command `sftpgo service rotatelogs` on Windows.
 Log file can be rotated on demand sending a `SIGUSR1` signal on Unix based systems and using the command `sftpgo service rotatelogs` on Windows.
 
 

+ 24 - 16
docs/sftp-subsystem.md

@@ -20,27 +20,32 @@ Flags:
                                starting directory. The home directory for a new
                                starting directory. The home directory for a new
                                user will be:
                                user will be:
 
 
-                               <base-home-dir>/<username>
+                               [base-home-dir]/[username]
 
 
                                base-home-dir must be an absolute path.
                                base-home-dir must be an absolute path.
-  -c, --config-dir string      Location for SFTPGo config dir. This directory
-                               should contain the "sftpgo" configuration file
-                               or the configured config-file and it is used as
-                               the base for files with a relative path (eg. the
-                               private keys for the SFTP server, the SQLite
-                               database if you use SQLite as data provider).
+  -c, --config-dir string      Location for the config dir. This directory
+                               is used as the base for files with a relative
+                               path, eg. the private keys for the SFTP
+                               server or the SQLite database if you use
+                               SQLite as data provider.
+                               The configuration file, if not explicitly set,
+                               is looked for in this dir. We support reading
+                               from JSON, TOML, YAML, HCL, envfile and Java
+                               properties config files. The default config
+                               file name is "sftpgo" and therefore
+                               "sftpgo.json", "sftpgo.yaml" and so on are
+                               searched.
                                This flag can be set using SFTPGO_CONFIG_DIR
                                This flag can be set using SFTPGO_CONFIG_DIR
                                env var too. (default ".")
                                env var too. (default ".")
-  -f, --config-file string     Name for SFTPGo configuration file. It must be
-                               the name of a file stored in config-dir not the
-                               absolute path to the configuration file. The
-                               specified file name must have no extension we
-                               automatically load JSON, YAML, TOML, HCL and
-                               Java properties. Therefore if you set "sftpgo"
-                               then "sftpgo.json", "sftpgo.yaml" and so on
-                               are searched.
+      --config-file string     Path to SFTPGo configuration file.
+                               This flag explicitly defines the path, name
+                               and extension of the config file. If must be
+                               an absolute path or a path relative to the
+                               configuration directory. The specified file
+                               name must have a supported extension (JSON,
+                               YAML, TOML, HCL or Java properties).
                                This flag can be set using SFTPGO_CONFIG_FILE
                                This flag can be set using SFTPGO_CONFIG_FILE
-                               env var too. (default "sftpgo")
+                               env var too.
   -h, --help                   help for startsubsys
   -h, --help                   help for startsubsys
   -j, --log-to-journald        Send logs to journald. Only available on Linux.
   -j, --log-to-journald        Send logs to journald. Only available on Linux.
                                Use:
                                Use:
@@ -50,6 +55,9 @@ Flags:
                                To see full logs.
                                To see full logs.
                                If not set, the logs will be sent to the standard
                                If not set, the logs will be sent to the standard
                                error
                                error
+      --log-utc-time           Use UTC time for logging. This flag can be set
+                               using SFTPGO_LOG_UTC_TIME env var too.
+                                (default true)
   -v, --log-verbose            Enable verbose logs. This flag can be set
   -v, --log-verbose            Enable verbose logs. This flag can be set
                                using SFTPGO_LOG_VERBOSE env var too.
                                using SFTPGO_LOG_VERBOSE env var too.
                                 (default true)
                                 (default true)

+ 1 - 1
ftpd/ftpd_test.go

@@ -247,7 +247,7 @@ func TestMain(m *testing.M) {
 	logFilePath = filepath.Join(configDir, "sftpgo_ftpd_test.log")
 	logFilePath = filepath.Join(configDir, "sftpgo_ftpd_test.log")
 	bannerFileName := "banner_file"
 	bannerFileName := "banner_file"
 	bannerFile := filepath.Join(configDir, bannerFileName)
 	bannerFile := filepath.Join(configDir, bannerFileName)
-	logger.InitLogger(logFilePath, 5, 1, 28, false, zerolog.DebugLevel)
+	logger.InitLogger(logFilePath, 5, 1, 28, false, false, zerolog.DebugLevel)
 	err := os.WriteFile(bannerFile, []byte("SFTPGo test ready\nsimple banner line\n"), os.ModePerm)
 	err := os.WriteFile(bannerFile, []byte("SFTPGo test ready\nsimple banner line\n"), os.ModePerm)
 	if err != nil {
 	if err != nil {
 		logger.ErrorToConsole("error creating banner file: %v", err)
 		logger.ErrorToConsole("error creating banner file: %v", err)

+ 1 - 1
httpd/httpd_test.go

@@ -245,7 +245,7 @@ type recoveryCode struct {
 func TestMain(m *testing.M) {
 func TestMain(m *testing.M) {
 	homeBasePath = os.TempDir()
 	homeBasePath = os.TempDir()
 	logfilePath := filepath.Join(configDir, "sftpgo_api_test.log")
 	logfilePath := filepath.Join(configDir, "sftpgo_api_test.log")
-	logger.InitLogger(logfilePath, 5, 1, 28, false, zerolog.DebugLevel)
+	logger.InitLogger(logfilePath, 5, 1, 28, false, false, zerolog.DebugLevel)
 	os.Setenv("SFTPGO_COMMON__UPLOAD_MODE", "2")
 	os.Setenv("SFTPGO_COMMON__UPLOAD_MODE", "2")
 	os.Setenv("SFTPGO_DATA_PROVIDER__CREATE_DEFAULT_ADMIN", "1")
 	os.Setenv("SFTPGO_DATA_PROVIDER__CREATE_DEFAULT_ADMIN", "1")
 	os.Setenv("SFTPGO_DEFAULT_ADMIN_USERNAME", "admin")
 	os.Setenv("SFTPGO_DEFAULT_ADMIN_USERNAME", "admin")

+ 16 - 2
logger/logger.go

@@ -14,6 +14,7 @@ import (
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
 	"runtime"
 	"runtime"
+	"time"
 
 
 	ftpserverlog "github.com/fclairamb/go-log"
 	ftpserverlog "github.com/fclairamb/go-log"
 	"github.com/rs/zerolog"
 	"github.com/rs/zerolog"
@@ -136,9 +137,21 @@ func GetLogger() *zerolog.Logger {
 	return &logger
 	return &logger
 }
 }
 
 
-// InitLogger configures the logger using the given parameters
-func InitLogger(logFilePath string, logMaxSize int, logMaxBackups int, logMaxAge int, logCompress bool, level zerolog.Level) {
+// SetLogTime sets logging time related setting
+func SetLogTime(utc bool) {
 	zerolog.TimeFieldFormat = dateFormat
 	zerolog.TimeFieldFormat = dateFormat
+	if utc {
+		zerolog.TimestampFunc = time.Now().UTC
+	} else {
+		zerolog.TimestampFunc = time.Now
+	}
+}
+
+// InitLogger configures the logger using the given parameters
+func InitLogger(logFilePath string, logMaxSize int, logMaxBackups int, logMaxAge int, logCompress, logUTCTime bool,
+	level zerolog.Level,
+) {
+	SetLogTime(logUTCTime)
 	if isLogFilePathValid(logFilePath) {
 	if isLogFilePathValid(logFilePath) {
 		logDir := filepath.Dir(logFilePath)
 		logDir := filepath.Dir(logFilePath)
 		if _, err := os.Stat(logDir); os.IsNotExist(err) {
 		if _, err := os.Stat(logDir); os.IsNotExist(err) {
@@ -153,6 +166,7 @@ func InitLogger(logFilePath string, logMaxSize int, logMaxBackups int, logMaxAge
 			MaxBackups: logMaxBackups,
 			MaxBackups: logMaxBackups,
 			MaxAge:     logMaxAge,
 			MaxAge:     logMaxAge,
 			Compress:   logCompress,
 			Compress:   logCompress,
+			LocalTime:  !logUTCTime,
 		}
 		}
 		logger = zerolog.New(rollingLogger)
 		logger = zerolog.New(rollingLogger)
 		EnableConsoleLogger(level)
 		EnableConsoleLogger(level)

+ 2 - 1
service/service.go

@@ -39,6 +39,7 @@ type Service struct {
 	PortableUser      dataprovider.User
 	PortableUser      dataprovider.User
 	LogCompress       bool
 	LogCompress       bool
 	LogVerbose        bool
 	LogVerbose        bool
+	LogUTCTime        bool
 	LoadDataClean     bool
 	LoadDataClean     bool
 	LoadDataFrom      string
 	LoadDataFrom      string
 	LoadDataMode      int
 	LoadDataMode      int
@@ -55,7 +56,7 @@ func (s *Service) initLogger() {
 	if !filepath.IsAbs(s.LogFilePath) && util.IsFileInputValid(s.LogFilePath) {
 	if !filepath.IsAbs(s.LogFilePath) && util.IsFileInputValid(s.LogFilePath) {
 		s.LogFilePath = filepath.Join(s.ConfigDir, s.LogFilePath)
 		s.LogFilePath = filepath.Join(s.ConfigDir, s.LogFilePath)
 	}
 	}
-	logger.InitLogger(s.LogFilePath, s.LogMaxSize, s.LogMaxBackups, s.LogMaxAge, s.LogCompress, logLevel)
+	logger.InitLogger(s.LogFilePath, s.LogMaxSize, s.LogMaxBackups, s.LogMaxAge, s.LogCompress, s.LogUTCTime, logLevel)
 	if s.PortableMode == 1 {
 	if s.PortableMode == 1 {
 		logger.EnableConsoleLogger(logLevel)
 		logger.EnableConsoleLogger(logLevel)
 		if s.LogFilePath == "" {
 		if s.LogFilePath == "" {

+ 1 - 1
sftpd/sftpd_test.go

@@ -144,7 +144,7 @@ func TestMain(m *testing.M) {
 	logFilePath = filepath.Join(configDir, "sftpgo_sftpd_test.log")
 	logFilePath = filepath.Join(configDir, "sftpgo_sftpd_test.log")
 	loginBannerFileName := "login_banner"
 	loginBannerFileName := "login_banner"
 	loginBannerFile := filepath.Join(configDir, loginBannerFileName)
 	loginBannerFile := filepath.Join(configDir, loginBannerFileName)
-	logger.InitLogger(logFilePath, 5, 1, 28, false, zerolog.DebugLevel)
+	logger.InitLogger(logFilePath, 5, 1, 28, false, false, zerolog.DebugLevel)
 	err := os.WriteFile(loginBannerFile, []byte("simple login banner\n"), os.ModePerm)
 	err := os.WriteFile(loginBannerFile, []byte("simple login banner\n"), os.ModePerm)
 	if err != nil {
 	if err != nil {
 		logger.ErrorToConsole("error creating login banner: %v", err)
 		logger.ErrorToConsole("error creating login banner: %v", err)

+ 1 - 1
webdavd/webdavd_test.go

@@ -248,7 +248,7 @@ var (
 
 
 func TestMain(m *testing.M) {
 func TestMain(m *testing.M) {
 	logFilePath = filepath.Join(configDir, "sftpgo_webdavd_test.log")
 	logFilePath = filepath.Join(configDir, "sftpgo_webdavd_test.log")
-	logger.InitLogger(logFilePath, 5, 1, 28, false, zerolog.DebugLevel)
+	logger.InitLogger(logFilePath, 5, 1, 28, false, false, zerolog.DebugLevel)
 	os.Setenv("SFTPGO_DATA_PROVIDER__CREATE_DEFAULT_ADMIN", "1")
 	os.Setenv("SFTPGO_DATA_PROVIDER__CREATE_DEFAULT_ADMIN", "1")
 	os.Setenv("SFTPGO_DEFAULT_ADMIN_USERNAME", "admin")
 	os.Setenv("SFTPGO_DEFAULT_ADMIN_USERNAME", "admin")
 	os.Setenv("SFTPGO_DEFAULT_ADMIN_PASSWORD", "password")
 	os.Setenv("SFTPGO_DEFAULT_ADMIN_PASSWORD", "password")