Skip to content

Commit

Permalink
Add rotated logs support
Browse files Browse the repository at this point in the history
Issue #4
  • Loading branch information
flexoid committed Jul 26, 2020
1 parent c727dd1 commit 3d380dc
Show file tree
Hide file tree
Showing 13 changed files with 854 additions and 16 deletions.
47 changes: 39 additions & 8 deletions app/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"context"
"fmt"
"io"
"io/ioutil"
"os"
"os/signal"
Expand All @@ -15,6 +16,7 @@ import (
"github.com/go-pkgz/repeater/strategy"
"github.com/robfig/cron/v3"
"github.com/umputun/go-flags"
"gopkg.in/natefinch/lumberjack.v2"

"github.com/umputun/cronn/app/crontab"
"github.com/umputun/cronn/app/notify"
Expand Down Expand Up @@ -52,6 +54,14 @@ var opts struct {
MaxLogLines int `long:"max-log" env:"MAX_LOG" default:"100" description:"max number of log lines name"`
HostName string `long:"host" env:"HOSTNAME" description:"host name running cronn"`
} `group:"notify" namespace:"notify" env-namespace:"CRONN_NOTIFY"`

Log struct {
Filename string `long:"filename" env:"FILENAME" description:"file to write logs to. Log to stdout if not specified"`
MaxSize int `long:"max-size" env:"MAX_SIZE" default:"100" description:"maximum size in megabytes of the log file before it gets rotated"`
MaxAge int `long:"max-age" env:"MAX_AGE" default:"0" description:"maximum number of days to retain old log files"`
MaxBackups int `long:"max-backups" env:"MAX_BACKUPS" default:"7" description:"maximum number of old log files to retain"`
EnabledCompress bool `long:"enabled-compress" env:"ENABLED_COMPRESS" description:"determines if the rotated log files should be compressed using gzip"`
} `group:"log" namespace:"log" env-namespace:"CRONN_LOG"`
}

var revision = "unknown"
Expand All @@ -62,7 +72,7 @@ func main() {
if _, err := flags.Parse(&opts); err != nil {
os.Exit(2)
}
setupLogs(opts.LogEnabled, opts.Dbg)
stdout := setupLogs()

defer func() {
if x := recover(); x != nil {
Expand Down Expand Up @@ -93,6 +103,7 @@ func main() {
Notifier: makeNotifier(),
HostName: makeHostName(),
MaxLogLines: opts.Notify.MaxLogLines,
Stdout: stdout,
}
signals(cancel) // handle SIGQUIT and SIGTERM
cronService.Do(ctx)
Expand Down Expand Up @@ -135,17 +146,37 @@ func makeHostName() string {
return host
}

func setupLogs(enabled, dbg bool) {
if !enabled {
func setupLogs() io.Writer {
if !opts.LogEnabled {
log.Setup(log.Out(ioutil.Discard), log.Err(ioutil.Discard))
return
return os.Stdout
}

if dbg {
log.Setup(log.Debug, log.Msec, log.CallerFunc, log.CallerPkg, log.CallerFile)
return
}
log.Setup(log.Msec)

if opts.Dbg {
log.Setup(log.Debug, log.CallerFunc, log.CallerPkg, log.CallerFile)
}

if opts.Log.Filename != "" {
fileLogger := &lumberjack.Logger{
Filename: opts.Log.Filename,
MaxSize: opts.Log.MaxSize,
MaxBackups: opts.Log.MaxBackups,
MaxAge: opts.Log.MaxAge,
Compress: opts.Log.EnabledCompress,
LocalTime: true, // as log files have content in local time format
}

log.Setup(
log.Out(fileLogger),
log.Err(fileLogger),
)

return fileLogger
}

return os.Stdout
}

func signals(cancel context.CancelFunc) {
Expand Down
11 changes: 6 additions & 5 deletions app/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type Scheduler struct {
HostName string
MaxLogLines int
Repeater *repeater.Repeater
stdout io.Writer
Stdout io.Writer
}

// Resumer defines interface for resumer.Resumer providing auto-restart for failed jobs
Expand Down Expand Up @@ -73,8 +73,8 @@ type Notifier interface {

// Do runs blocking scheduler
func (s *Scheduler) Do(ctx context.Context) {
if s.stdout == nil {
s.stdout = os.Stdout
if s.Stdout == nil {
s.Stdout = os.Stdout
}
s.resumeInterrupted()

Expand Down Expand Up @@ -115,7 +115,7 @@ func (s *Scheduler) jobFunc(r crontab.JobSpec, sched cron.Schedule) cron.FuncJob

rfile, rerr := s.Resumer.OnStart(cmd)

if err = s.executeCommand(cmd, s.stdout); err != nil {
if err = s.executeCommand(cmd, s.Stdout); err != nil {
if e := s.notify(r, err.Error()); e != nil {
return errors.Wrap(err, "failed to notify")
}
Expand Down Expand Up @@ -149,6 +149,7 @@ func (s *Scheduler) executeCommand(command string, logWriter io.Writer) error {
err := s.Repeater.Do(context.Background(), func() error {
cmd := exec.Command("sh", "-c", command) // nolint gosec
serr := NewErrorWriter(s.MaxLogLines)

logWithErr := io.MultiWriter(logWriter, serr)
cmd.Stdout = logWithErr
cmd.Stderr = logWithErr
Expand Down Expand Up @@ -237,7 +238,7 @@ func (s *Scheduler) resumeInterrupted() {

go func() {
for _, cmd := range cmds {
if err := s.executeCommand(cmd.Command, os.Stdout); err != nil {
if err := s.executeCommand(cmd.Command, s.Stdout); err != nil {
r := crontab.JobSpec{Spec: "auto-resume", Command: cmd.Command}
if e := s.notify(r, err.Error()); e != nil {
log.Printf("[WARN] failed to notify, %v", e)
Expand Down
6 changes: 3 additions & 3 deletions app/service/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func TestScheduler_DoIntegration(t *testing.T) {
CrontabParser: parser,
UpdatesEnabled: false,
Notifier: notif,
stdout: out,
Stdout: out,
}
ctx, cancel := context.WithTimeout(context.Background(), 110*time.Second)
defer cancel()
Expand Down Expand Up @@ -111,7 +111,7 @@ func TestScheduler_jobFunc(t *testing.T) {
resmr := &mocks.Resumer{}
scheduleMock := &scheduleMock{next: time.Date(2020, 7, 21, 16, 30, 0, 0, time.UTC)}
wr := bytes.NewBuffer(nil)
svc := Scheduler{MaxLogLines: 10, stdout: wr, Resumer: resmr, Repeater: repeater.New(&strategy.Once{})}
svc := Scheduler{MaxLogLines: 10, Stdout: wr, Resumer: resmr, Repeater: repeater.New(&strategy.Once{})}

resmr.On("List").Return(nil).Once()
resmr.On("OnStart", "echo 123").Return("resume.file", nil).Once()
Expand All @@ -128,7 +128,7 @@ func TestScheduler_jobFuncFailed(t *testing.T) {
notif.On("IsOnError").Return(true)
scheduleMock := &scheduleMock{next: time.Date(2020, 7, 21, 16, 30, 0, 0, time.UTC)}
wr := bytes.NewBuffer(nil)
svc := Scheduler{MaxLogLines: 10, stdout: wr, Resumer: resmr, Notifier: notif, Repeater: repeater.New(&strategy.Once{})}
svc := Scheduler{MaxLogLines: 10, Stdout: wr, Resumer: resmr, Notifier: notif, Repeater: repeater.New(&strategy.Once{})}

resmr.On("List").Return(nil).Once()
resmr.On("OnStart", "no-such-thing").Return("resume.file", nil).Once()
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ require (
github.com/robfig/cron/v3 v3.0.1
github.com/stretchr/testify v1.4.0
github.com/umputun/go-flags v1.5.1
gopkg.in/natefinch/lumberjack.v2 v2.0.0
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,7 @@ github.com/umputun/go-flags v1.5.1 h1:vRauoXV3Ultt1HrxivSxowbintgZLJE+EcBy5ta3/m
github.com/umputun/go-flags v1.5.1/go.mod h1:nTbvsO/hKqe7Utri/NoyN18GR3+EWf+9RrmsdwdhrEc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
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/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
23 changes: 23 additions & 0 deletions vendor/gopkg.in/natefinch/lumberjack.v2/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions vendor/gopkg.in/natefinch/lumberjack.v2/.travis.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions vendor/gopkg.in/natefinch/lumberjack.v2/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 3d380dc

Please sign in to comment.