diff --git a/config.example.yml b/config.example.yml index 4dbfd02..c093edd 100644 --- a/config.example.yml +++ b/config.example.yml @@ -67,4 +67,13 @@ destination: - token: blabla url: bla.bla.com local: - - path: /some/path/gickup \ No newline at end of file + - path: /some/path/gickup + +cron: 0 22 * * * + +log: + timeformat: 2006-01-02 15:04:05 + file-logging: + dir: log + file: gickup.log + maxage: 7 # keep logs for 7 days \ No newline at end of file diff --git a/go.mod b/go.mod index 739d358..3fb8fe6 100644 --- a/go.mod +++ b/go.mod @@ -30,5 +30,6 @@ require ( golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 // indirect golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect google.golang.org/protobuf v1.27.1 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index 8e3f217..f5f1efd 100644 --- a/go.sum +++ b/go.sum @@ -531,6 +531,8 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/logger/logger.go b/logger/logger.go new file mode 100644 index 0000000..85b04c0 --- /dev/null +++ b/logger/logger.go @@ -0,0 +1,41 @@ +package logger + +import ( + "io" + "os" + "path" + + "gickup/types" + + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + "gopkg.in/natefinch/lumberjack.v2" +) + +func NewRollingFile(config types.FileLogging) io.Writer { + if config.Dir != "" { + if err := os.MkdirAll(config.Dir, 0744); err != nil { + log.Error().Err(err).Str("path", config.Dir).Msg("can't create log directory") + return nil + } + } else { + config.Dir = "." + } + + return &lumberjack.Logger{ + Filename: path.Join(config.Dir, config.File), + MaxAge: config.MaxAge, // days + } +} + +func CreateLogger(conf types.Logging) zerolog.Logger { + var writers []io.Writer + + writers = append(writers, zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: conf.Timeformat}) + if conf.FileLogging.File != "" { + writers = append(writers, NewRollingFile(conf.FileLogging)) + } + mw := io.MultiWriter(writers...) + + return zerolog.New(mw).With().Timestamp().Logger() +} diff --git a/main.go b/main.go index 1023dbc..44b8bf2 100644 --- a/main.go +++ b/main.go @@ -12,6 +12,7 @@ import ( "gickup/gitlab" "gickup/gogs" "gickup/local" + "gickup/logger" "gickup/types" "github.com/alecthomas/kong" @@ -96,6 +97,8 @@ func RunBackup(conf *types.Conf) { //Bitbucket repos = bitbucket.Get(conf) Backup(repos, conf) + + conf.HasValidCronSpec() } func PlaysForever() { @@ -106,8 +109,7 @@ func PlaysForever() { } func main() { - zerolog.TimeFieldFormat = zerolog.TimeFormatUnix - log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) + log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: "2006-01-02T15:04:05Z07:00"}) kong.Parse(&cli, kong.Name("gickup"), kong.Description("a tool to backup all your favorite repos")) @@ -121,8 +123,9 @@ func main() { log.Info().Str("file", cli.Configfile).Msgf("Reading %s", types.Green(cli.Configfile)) conf := ReadConfigfile(cli.Configfile) + log.Logger = logger.CreateLogger(conf.Log) + if conf.HasValidCronSpec() { - log.Info().Str("cron", conf.Cron).Msg("running in cron mode") c := cron.New() c.AddFunc(conf.Cron, func() { RunBackup(conf) }) c.Start() diff --git a/types/types.go b/types/types.go index 83fac24..3d00617 100644 --- a/types/types.go +++ b/types/types.go @@ -29,6 +29,18 @@ type Conf struct { Source Source `yaml:"source"` Destination Destination `yaml:"destination"` Cron string `yaml:"cron"` + Log Logging `yaml:"log"` +} + +type Logging struct { + Timeformat string `yaml:"timeformat"` + FileLogging FileLogging `yaml:"file-logging"` +} + +type FileLogging struct { + Dir string `yaml:"dir"` + File string `yaml:"file"` + MaxAge int `yaml:"maxage"` } func (conf Conf) MissingCronSpec() bool { @@ -54,7 +66,7 @@ func (conf Conf) HasValidCronSpec() bool { if parsedSched != nil { nextRun := parsedSched.Next(time.Now()).String() - log.Info().Str("next", nextRun).Msg("Next cron run") + log.Info().Str("next", nextRun).Str("cron", conf.Cron).Msg("Next cron run") } return parsedSched != nil