A Golang job scheduling library that lets you run Go functions at pre-determined intervals using cron expressions, fixed durations, daily, weekly, monthly, or one-time schedules with support for distributed deployments.
Guide to configuring logging in gocron.
Gocron uses a logger interface for internal logging. You can use the default logger or provide a custom implementation.
By default, gocron uses a logger that outputs to stdout:
s, _ := gocron.NewScheduler()
// Uses default loggertype Logger interface {
Debug(msg string, args ...any)
Error(msg string, args ...any)
Info(msg string, args ...any)
Warn(msg string, args ...any)
}type myLogger struct{}
func (l *myLogger) Debug(msg string, args ...any) {
log.Printf("[DEBUG] "+msg, args...)
}
func (l *myLogger) Error(msg string, args ...any) {
log.Printf("[ERROR] "+msg, args...)
}
func (l *myLogger) Info(msg string, args ...any) {
log.Printf("[INFO] "+msg, args...)
}
func (l *myLogger) Warn(msg string, args ...any) {
log.Printf("[WARN] "+msg, args...)
}
s, _ := gocron.NewScheduler(
gocron.WithLogger(&myLogger{}),
)import "go.uber.org/zap"
type zapLogger struct {
logger *zap.SugaredLogger
}
func (l *zapLogger) Debug(msg string, args ...any) {
l.logger.Debugf(msg, args...)
}
func (l *zapLogger) Error(msg string, args ...any) {
l.logger.Errorf(msg, args...)
}
func (l *zapLogger) Info(msg string, args ...any) {
l.logger.Infof(msg, args...)
}
func (l *zapLogger) Warn(msg string, args ...any) {
l.logger.Warnf(msg, args...)
}
zapLog, _ := zap.NewProduction()
defer zapLog.Sync()
s, _ := gocron.NewScheduler(
gocron.WithLogger(&zapLogger{logger: zapLog.Sugar()}),
)import "github.com/sirupsen/logrus"
type logrusLogger struct {
logger *logrus.Logger
}
func (l *logrusLogger) Debug(msg string, args ...any) {
l.logger.Debugf(msg, args...)
}
func (l *logrusLogger) Error(msg string, args ...any) {
l.logger.Errorf(msg, args...)
}
func (l *logrusLogger) Info(msg string, args ...any) {
l.logger.Infof(msg, args...)
}
func (l *logrusLogger) Warn(msg string, args ...any) {
l.logger.Warnf(msg, args...)
}
logrusLog := logrus.New()
logrusLog.SetLevel(logrus.InfoLevel)
s, _ := gocron.NewScheduler(
gocron.WithLogger(&logrusLogger{logger: logrusLog}),
)import "github.com/rs/zerolog"
type zerologLogger struct {
logger zerolog.Logger
}
func (l *zerologLogger) Debug(msg string, args ...any) {
l.logger.Debug().Msgf(msg, args...)
}
func (l *zerologLogger) Error(msg string, args ...any) {
l.logger.Error().Msgf(msg, args...)
}
func (l *zerologLogger) Info(msg string, args ...any) {
l.logger.Info().Msgf(msg, args...)
}
func (l *zerologLogger) Warn(msg string, args ...any) {
l.logger.Warn().Msgf(msg, args...)
}
zerologLog := zerolog.New(os.Stdout).With().Timestamp().Logger()
s, _ := gocron.NewScheduler(
gocron.WithLogger(&zerologLogger{logger: zerologLog}),
)Control verbosity by implementing selective logging:
type levelLogger struct {
level string // "debug", "info", "warn", "error"
}
func (l *levelLogger) Debug(msg string, args ...any) {
if l.level == "debug" {
log.Printf("[DEBUG] "+msg, args...)
}
}
func (l *levelLogger) Info(msg string, args ...any) {
if l.level == "debug" || l.level == "info" {
log.Printf("[INFO] "+msg, args...)
}
}
// ... similar for Warn and Error
s, _ := gocron.NewScheduler(
gocron.WithLogger(&levelLogger{level: "info"}),
)Add context with structured fields:
type structuredLogger struct {
logger *zap.SugaredLogger
}
func (l *structuredLogger) Debug(msg string, args ...any) {
l.logger.With("component", "gocron").Debugf(msg, args...)
}
func (l *structuredLogger) Error(msg string, args ...any) {
l.logger.With(
"component", "gocron",
"timestamp", time.Now(),
).Errorf(msg, args...)
}
// ... similar for Info and WarnGocron logs the following events:
Create a no-op logger to disable logging:
type noopLogger struct{}
func (l *noopLogger) Debug(msg string, args ...any) {}
func (l *noopLogger) Error(msg string, args ...any) {}
func (l *noopLogger) Info(msg string, args ...any) {}
func (l *noopLogger) Warn(msg string, args ...any) {}
s, _ := gocron.NewScheduler(
gocron.WithLogger(&noopLogger{}),
)Add job-specific context:
j, _ := s.NewJob(
gocron.DurationJob(time.Minute),
gocron.NewTask(func() {
log.Printf("[%s] Starting work", j.Name())
doWork()
log.Printf("[%s] Completed work", j.Name())
}),
gocron.WithName("my-job"),
)Integrate with log rotation systems:
import "gopkg.in/natefinch/lumberjack.v2"
logFile := &lumberjack.Logger{
Filename: "/var/log/gocron.log",
MaxSize: 100, // MB
MaxBackups: 3,
MaxAge: 28, // days
Compress: true,
}
log.SetOutput(logFile)
s, _ := gocron.NewScheduler(
gocron.WithLogger(&myLogger{}),
)// Debug for development
l.Debug("Job scheduled: %v", nextRun)
// Info for normal operations
l.Info("Job started: %s", jobName)
// Warn for issues that don't prevent operation
l.Warn("Queue growing: %d jobs waiting", queueSize)
// Error for failures
l.Error("Job failed: %v", err)l.Info("Job completed: name=%s, duration=%v, status=%s",
job.Name(), duration, status)// Bad: logs every iteration
for i := 0; i < 1000000; i++ {
l.Debug("Processing item %d", i)
}
// Good: log summary
l.Info("Processed %d items", 1000000)Install with Tessl CLI
npx tessl i tessl/golang-github-com-go-co-op-gocron-v2@2.19.1docs
api
examples
guides