Skip to content

Commit

Permalink
Merge pull request #39 from pior/logs
Browse files Browse the repository at this point in the history
Refactor logging
  • Loading branch information
pior authored Jul 30, 2023
2 parents 769e398 + b0c9b77 commit a06be4b
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 49 deletions.
15 changes: 12 additions & 3 deletions logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,25 @@ import (
"os"
)

var log Logger = stdlog.New(os.Stdout, "[RUNNABLE] ", stdlog.Ldate|stdlog.Ltime)
var log Logger

func init() {
SetLogger(nil)
}

// SetLogger replaces the default logger with a runnable.Logger.
func SetLogger(l Logger) {
if l == nil {
panic("Runnable: logger cannot be nil")
l = stdlog.New(os.Stdout, "[RUNNABLE] ", stdlog.Ldate|stdlog.Ltime)
}
log = l
}

type Logger interface {
Printf(format string, args ...interface{})
Printf(format string, args ...any)
}

// Log logs a formatted message, prefixed by the runnable chain.
func Log(self any, format string, args ...any) {
log.Printf(findName(self)+": "+format, args...)
}
16 changes: 8 additions & 8 deletions manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,15 @@ func (m *manager) Run(ctx context.Context) error {
// run the runnables in Go routines.
for _, c := range m.containers {
c.launch(completedChan, dying)
log.Printf("manager: %s started", c.name())
Log(m, "%s started", c.name())
}

// block until group is cancelled, or a runnable dies.
select {
case <-ctx.Done():
log.Printf("manager: starting shutdown (context cancelled)")
Log(m, "starting shutdown (context cancelled)")
case c := <-dying:
log.Printf("manager: starting shutdown (%s died)", c.name())
Log(m, "starting shutdown (%s died)", c.name())
}

// starting shutdown
Expand Down Expand Up @@ -117,7 +117,7 @@ func (m *manager) Run(ctx context.Context) error {
}

if !cancelled.contains(c) {
log.Printf("manager: %s cancelled", c.name())
Log(m, "%s cancelled", c.name())
c.shutdown()
cancelled.insert(c)
}
Expand All @@ -129,9 +129,9 @@ func (m *manager) Run(ctx context.Context) error {
completed.insert(c)

if c.err == nil || errors.Is(c.err, context.Canceled) {
log.Printf("manager: %s stopped", c.name())
Log(m, "%s stopped", c.name())
} else {
log.Printf("manager: %s stopped with error: %+v", c.name(), c.err)
Log(m, "%s stopped with error: %+v", c.name(), c.err)
}

if len(completed) == len(m.containers) {
Expand All @@ -146,15 +146,15 @@ func (m *manager) Run(ctx context.Context) error {
errs := []string{}
for _, c := range m.containers {
if !completed.contains(c) {
log.Printf("manager: %s is still running", c.name())
Log(m, "%s is still running", c.name())
errs = append(errs, fmt.Sprintf("%s is still running", c.name()))
}
if c.err != nil && !errors.Is(c.err, context.Canceled) {
errs = append(errs, fmt.Sprintf("%s crashed with %+v", c.name(), c.err))
}
}

log.Printf("manager: shutdown complete")
Log(m, "shutdown complete")

if len(errs) != 0 {
return fmt.Errorf("manager: %s", strings.Join(errs, ", "))
Expand Down
9 changes: 5 additions & 4 deletions restart.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ func RestartCrashLimit(times int) RestartOption {
}

// RestartDelay sets the time waited before restarting the runnable after a successful execution.
func RestartDelay(times time.Duration) RestartOption {
func RestartDelay(delay time.Duration) RestartOption {
return func(cfg *restartConfig) {
cfg.restartDelay = times
cfg.restartDelay = delay
}
}

Expand Down Expand Up @@ -65,6 +65,7 @@ func (r *restart) Run(ctx context.Context) error {
crashCount := 0

for {
Log(r, "starting (restart=%d crash=%d)", restartCount, crashCount)
err := r.runnable.Run(ctx)
isCrash := err != nil

Expand All @@ -73,12 +74,12 @@ func (r *restart) Run(ctx context.Context) error {
}

if r.cfg.restartLimit > 0 && restartCount >= r.cfg.restartLimit {
log.Printf("restart: not restarting (hit the restart limit: %d)", r.cfg.restartLimit)
Log(r, "not restarting (hit the restart limit: %d)", r.cfg.restartLimit)
return err
}

if r.cfg.crashLimit > 0 && crashCount >= r.cfg.crashLimit {
log.Printf("restart: not restarting (hit the crash limit: %d)", r.cfg.crashLimit)
Log(r, "not restarting (hit the crash limit: %d)", r.cfg.crashLimit)
return err
}

Expand Down
16 changes: 16 additions & 0 deletions restart_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,22 @@ import (
"github.com/stretchr/testify/require"
)

func ExampleRestart() {
ctx, cancel := initializeForExample()
defer cancel()

runnable := newDyingRunnable()

r := Restart(runnable, RestartCrashLimit(3))
_ = r.Run(ctx)

// Output:
// restart/dyingRunnable: starting (restart=0 crash=0)
// restart/dyingRunnable: starting (restart=1 crash=1)
// restart/dyingRunnable: starting (restart=2 crash=2)
// restart/dyingRunnable: not restarting (hit the crash limit: 3)
}

func TestRestart_Cancellation(t *testing.T) {
r := Restart(newDummyRunnable())
AssertRunnableRespectCancellation(t, r, time.Millisecond*100)
Expand Down
6 changes: 3 additions & 3 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func (r *httpServer) Run(ctx context.Context) error {
errChan := make(chan error)

go func() {
log.Printf("http_server: listening on %s", r.server.Addr)
Log(r, "listening on %s", r.server.Addr)
errChan <- r.server.ListenAndServe()
}()

Expand All @@ -31,11 +31,11 @@ func (r *httpServer) Run(ctx context.Context) error {

select {
case <-ctx.Done():
log.Printf("http_server: shutdown")
Log(r, "shutdown")
shutdownErr = r.shutdown()
err = <-errChan
case err = <-errChan:
log.Printf("http_server: shutdown (err: %s)", err)
Log(r, "shutdown (err: %s)", err)
shutdownErr = r.shutdown()
}

Expand Down
34 changes: 11 additions & 23 deletions server_test.go
Original file line number Diff line number Diff line change
@@ -1,53 +1,41 @@
package runnable_test
package runnable

import (
"context"
stdlog "log"
"net/http"
"os"
"time"

"github.com/pior/runnable"
)

func ExampleHTTPServer() {
runnable.SetLogger(stdlog.New(os.Stdout, "", 0))
ctx, cancel := initializeForExample()
defer cancel()

server := &http.Server{
Addr: "127.0.0.1:8080",
Handler: http.NotFoundHandler(),
}

r := runnable.HTTPServer(server)

ctx := context.Background()
ctx, cancel := context.WithTimeout(ctx, time.Millisecond*100)
defer cancel()
r := HTTPServer(server)

_ = r.Run(ctx)

// Output:
// http_server: listening on 127.0.0.1:8080
// http_server: shutdown
// httpserver: listening on 127.0.0.1:8080
// httpserver: shutdown
}

func ExampleHTTPServer_error() {
runnable.SetLogger(stdlog.New(os.Stdout, "", 0))
ctx, cancel := initializeForExample()
defer cancel()

server := &http.Server{
Addr: "INVALID",
Handler: http.NotFoundHandler(),
}

r := runnable.HTTPServer(server)

ctx := context.Background()
ctx, cancel := context.WithTimeout(ctx, time.Millisecond*1000)
defer cancel()
r := HTTPServer(server)

_ = r.Run(ctx)

// Output:
// http_server: listening on INVALID
// http_server: shutdown (err: listen tcp: address INVALID: missing port in address)
// httpserver: listening on INVALID
// httpserver: shutdown (err: listen tcp: address INVALID: missing port in address)
}
14 changes: 7 additions & 7 deletions signals.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package runnable
import (
"context"
"os"
"os/signal"
ossignal "os/signal"
"syscall"
)

Expand All @@ -14,25 +14,25 @@ func Signal(runnable Runnable, signals ...os.Signal) Runnable {
signals = append(signals, syscall.SIGTERM)
}

return &signalRunnable{runnable, signals}
return &signal{runnable, signals}
}

type signalRunnable struct {
type signal struct {
runnable Runnable
signals []os.Signal
}

func (s *signalRunnable) Run(ctx context.Context) error {
func (s *signal) Run(ctx context.Context) error {
ctx, cancelFunc := context.WithCancel(ctx)

sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, s.signals...)
ossignal.Notify(sigChan, s.signals...)

go func() {
defer signal.Reset(s.signals...)
defer ossignal.Reset(s.signals...)

sig := <-sigChan
log.Printf("signal: received signal %s", sig)
Log(s, "received signal %s", sig)
cancelFunc()
}()

Expand Down
15 changes: 14 additions & 1 deletion testing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package runnable
import (
"context"
"errors"
stdlog "log"
"os"
"testing"
"time"

Expand All @@ -17,8 +19,10 @@ func newDummyRunnable() *dummyRunnable {

type dummyRunnable struct{}

func (*dummyRunnable) Run(ctx context.Context) error {
func (r *dummyRunnable) Run(ctx context.Context) error {
Log(r, "started")
<-ctx.Done()
Log(r, "stopped")
return ctx.Err()
}

Expand Down Expand Up @@ -136,3 +140,12 @@ func cancelledContext() context.Context {
cancelFunc()
return ctx
}

func initializeForExample() (context.Context, func()) {
ctx := context.Background()
ctx, cancel := context.WithTimeout(ctx, 200*time.Millisecond)

SetLogger(stdlog.New(os.Stdout, "", 0))

return ctx, cancel
}

0 comments on commit a06be4b

Please sign in to comment.