Skip to content

Commit

Permalink
feat(logger): use slog
Browse files Browse the repository at this point in the history
  • Loading branch information
janrnc committed Feb 20, 2024
1 parent a522463 commit c0c5e76
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 136 deletions.
9 changes: 5 additions & 4 deletions chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cron

import (
"fmt"
"log/slog"
"runtime"
"sync"
"time"
Expand Down Expand Up @@ -38,7 +39,7 @@ func (c Chain) Then(job func()) func() {
}

// Recover panics in wrapped jobs and log them with the provided logger.
func Recover(logger Logger) JobWrapper {
func Recover(logger *slog.Logger) JobWrapper {
return func(job func()) func() {
return func() {
defer func() {
Expand All @@ -50,7 +51,7 @@ func Recover(logger Logger) JobWrapper {
if !ok {
err = fmt.Errorf("%v", r)
}
logger.Error(err, "panic", "stack", "...\n"+string(buf))
logger.Error(err.Error(), "event", "panic", "stack", "...\n"+string(buf))
}
}()
job()
Expand All @@ -61,7 +62,7 @@ func Recover(logger Logger) JobWrapper {
// DelayIfStillRunning serializes jobs, delaying subsequent runs until the
// previous one is complete. Jobs running after a delay of more than a minute
// have the delay logged at Info.
func DelayIfStillRunning(logger Logger) JobWrapper {
func DelayIfStillRunning(logger *slog.Logger) JobWrapper {
return func(job func()) func() {
var mu sync.Mutex
return func() {
Expand All @@ -78,7 +79,7 @@ func DelayIfStillRunning(logger Logger) JobWrapper {

// SkipIfStillRunning skips an invocation of the job if a previous invocation is
// still running. It logs skips to the given logger at Info level.
func SkipIfStillRunning(logger Logger) JobWrapper {
func SkipIfStillRunning(logger *slog.Logger) JobWrapper {
return func(job func()) func() {
var ch = make(chan struct{}, 1)
ch <- struct{}{}
Expand Down
27 changes: 12 additions & 15 deletions chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package cron

import (
"io"
"log"
"log/slog"
"reflect"
"sync"
"testing"
"time"
)

var discardLogger = slog.New(slog.NewTextHandler(io.Discard, nil))

func appendingJob(slice *[]int, value int) func() {
var m sync.Mutex
return func() {
Expand Down Expand Up @@ -56,12 +58,7 @@ func TestChainRecover(t *testing.T) {
})

t.Run("Recovering JobWrapper recovers", func(t *testing.T) {
NewChain(Recover(PrintfLogger(log.New(io.Discard, "", 0)))).
Then(panickingJob)()
})

t.Run("composed with the *IfStillRunning wrappers", func(t *testing.T) {
NewChain(Recover(PrintfLogger(log.New(io.Discard, "", 0)))).
NewChain(Recover(discardLogger)).
Then(panickingJob)()
})
}
Expand Down Expand Up @@ -101,7 +98,7 @@ func TestChainDelayIfStillRunning(t *testing.T) {

t.Run("runs immediately", func(t *testing.T) {
var j countJob
wrappedJob := NewChain(DelayIfStillRunning(DiscardLogger)).Then(j.job())
wrappedJob := NewChain(DelayIfStillRunning(discardLogger)).Then(j.job())
go wrappedJob()
time.Sleep(2 * time.Millisecond) // Give the job 2ms to complete.
if c := j.Done(); c != 1 {
Expand All @@ -111,7 +108,7 @@ func TestChainDelayIfStillRunning(t *testing.T) {

t.Run("second run immediate if first done", func(t *testing.T) {
var j countJob
wrappedJob := NewChain(DelayIfStillRunning(DiscardLogger)).Then(j.job())
wrappedJob := NewChain(DelayIfStillRunning(discardLogger)).Then(j.job())
go func() {
go wrappedJob()
time.Sleep(time.Millisecond)
Expand All @@ -126,7 +123,7 @@ func TestChainDelayIfStillRunning(t *testing.T) {
t.Run("second run delayed if first not done", func(t *testing.T) {
var j countJob
j.delay = 10 * time.Millisecond
wrappedJob := NewChain(DelayIfStillRunning(DiscardLogger)).Then(j.job())
wrappedJob := NewChain(DelayIfStillRunning(discardLogger)).Then(j.job())
go func() {
go wrappedJob()
time.Sleep(time.Millisecond)
Expand Down Expand Up @@ -155,7 +152,7 @@ func TestChainSkipIfStillRunning(t *testing.T) {

t.Run("runs immediately", func(t *testing.T) {
var j countJob
wrappedJob := NewChain(SkipIfStillRunning(DiscardLogger)).Then(j.job())
wrappedJob := NewChain(SkipIfStillRunning(discardLogger)).Then(j.job())
go wrappedJob()
time.Sleep(2 * time.Millisecond) // Give the job 2ms to complete.
if c := j.Done(); c != 1 {
Expand All @@ -165,7 +162,7 @@ func TestChainSkipIfStillRunning(t *testing.T) {

t.Run("second run immediate if first done", func(t *testing.T) {
var j countJob
wrappedJob := NewChain(SkipIfStillRunning(DiscardLogger)).Then(j.job())
wrappedJob := NewChain(SkipIfStillRunning(discardLogger)).Then(j.job())
go func() {
go wrappedJob()
time.Sleep(time.Millisecond)
Expand All @@ -180,7 +177,7 @@ func TestChainSkipIfStillRunning(t *testing.T) {
t.Run("second run skipped if first not done", func(t *testing.T) {
var j countJob
j.delay = 10 * time.Millisecond
wrappedJob := NewChain(SkipIfStillRunning(DiscardLogger)).Then(j.job())
wrappedJob := NewChain(SkipIfStillRunning(discardLogger)).Then(j.job())
go func() {
go wrappedJob()
time.Sleep(time.Millisecond)
Expand All @@ -206,7 +203,7 @@ func TestChainSkipIfStillRunning(t *testing.T) {
t.Run("skip 10 jobs on rapid fire", func(t *testing.T) {
var j countJob
j.delay = 10 * time.Millisecond
wrappedJob := NewChain(SkipIfStillRunning(DiscardLogger)).Then(j.job())
wrappedJob := NewChain(SkipIfStillRunning(discardLogger)).Then(j.job())
for i := 0; i < 11; i++ {
go wrappedJob()
}
Expand All @@ -221,7 +218,7 @@ func TestChainSkipIfStillRunning(t *testing.T) {
var j1, j2 countJob
j1.delay = 10 * time.Millisecond
j2.delay = 10 * time.Millisecond
chain := NewChain(SkipIfStillRunning(DiscardLogger))
chain := NewChain(SkipIfStillRunning(discardLogger))
wrappedJob1 := chain.Then(j1.job())
wrappedJob2 := chain.Then(j2.job())
for i := 0; i < 11; i++ {
Expand Down
39 changes: 20 additions & 19 deletions cron.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package cron

import (
"container/heap"
"context"
"fmt"
"log/slog"
"sync"
"time"
"fmt"
"container/heap"
)

// Cron keeps track of any number of entries, invoking the associated func as
Expand All @@ -19,11 +20,11 @@ type Cron struct {
remove chan ID
snapshot chan chan []Entry
running bool
logger Logger
logger *slog.Logger
runningMu sync.Mutex
location *time.Location
parser ScheduleParser
next ID
next ID
jobWaiter sync.WaitGroup
}

Expand Down Expand Up @@ -65,17 +66,17 @@ type Entry struct {
//
// Available Settings
//
// Time Zone
// Description: The time zone in which schedules are interpreted
// Default: time.Local
// Time Zone
// Description: The time zone in which schedules are interpreted
// Default: time.Local
//
// Parser
// Description: Parser converts cron spec strings into cron.Schedules.
// Default: Accepts this spec: https://en.wikipedia.org/wiki/Cron
// Parser
// Description: Parser converts cron spec strings into cron.Schedules.
// Default: Accepts this spec: https://en.wikipedia.org/wiki/Cron
//
// Chain
// Description: Wrap submitted jobs to customize behavior.
// Default: A chain that recovers panics and logs them to stderr.
// Chain
// Description: Wrap submitted jobs to customize behavior.
// Default: A chain that recovers panics and logs them to stderr.
//
// See "cron.With*" to modify the default behavior.
func New(opts ...Option) *Cron {
Expand All @@ -88,10 +89,10 @@ func New(opts ...Option) *Cron {
remove: make(chan ID),
running: false,
runningMu: sync.Mutex{},
logger: DefaultLogger,
logger: slog.Default(),
location: time.Local,
parser: standardParser,
next: 1,
next: 1,
}
for _, opt := range opts {
opt(c)
Expand All @@ -115,15 +116,15 @@ func (c *Cron) Add(spec string, cmd func()) (ID, error) {
func (c *Cron) Schedule(schedule Schedule, cmd func()) (ID, error) {
c.runningMu.Lock()
defer c.runningMu.Unlock()

if c.next == 0 {
return 0, fmt.Errorf("run out of available ids")
}

entry := &Entry{
ID: c.next,
Schedule: schedule,
job: c.chain.Then(cmd),
ID: c.next,
Schedule: schedule,
job: c.chain.Then(cmd),
}
c.next++
if !c.running {
Expand Down
10 changes: 5 additions & 5 deletions cron_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ package cron

import (
"bytes"
"container/heap"
"fmt"
"log"
"log/slog"
"strings"
"sync"
"sync/atomic"
"testing"
"time"
"container/heap"
)

// Many tests schedule a job for every second, and then wait at most a second
Expand All @@ -35,8 +35,8 @@ func (sw *syncWriter) String() string {
return sw.wr.String()
}

func newBufLogger(sw *syncWriter) Logger {
return PrintfLogger(log.New(sw, "", log.LstdFlags))
func newBufLogger(sw *syncWriter) *slog.Logger {
return slog.New(slog.NewTextHandler(sw, nil))
}

func TestFuncPanicRecovery(t *testing.T) {
Expand Down Expand Up @@ -529,7 +529,7 @@ func TestJob(t *testing.T) {

cron.Start()
defer cron.Stop()

select {
case <-time.After(OneSecond):
t.FailNow()
Expand Down
86 changes: 0 additions & 86 deletions logger.go

This file was deleted.

3 changes: 2 additions & 1 deletion option.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cron

import (
"log/slog"
"time"
)

Expand Down Expand Up @@ -38,7 +39,7 @@ func WithChain(wrappers ...JobWrapper) Option {
}

// WithLogger uses the provided logger.
func WithLogger(logger Logger) Option {
func WithLogger(logger *slog.Logger) Option {
return func(c *Cron) {
c.logger = logger
}
Expand Down
Loading

0 comments on commit c0c5e76

Please sign in to comment.