From 5ed76b71fcece4504396deedd834706b21461fd7 Mon Sep 17 00:00:00 2001 From: Paul Larsen Date: Sun, 3 Nov 2024 22:00:44 +0000 Subject: [PATCH] move to using slog for internal logging requirements --- ext/botmapping.go | 16 ++++------------ ext/common.go | 14 ++++++++++++++ ext/dispatcher.go | 33 +++++++++++++-------------------- ext/updater.go | 39 ++++++++++++++++----------------------- 4 files changed, 47 insertions(+), 55 deletions(-) create mode 100644 ext/common.go diff --git a/ext/botmapping.go b/ext/botmapping.go index b785508..6b0434a 100644 --- a/ext/botmapping.go +++ b/ext/botmapping.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" "io" - "log" + "log/slog" "net/http" "strings" "sync" @@ -43,8 +43,8 @@ type botMapping struct { // errFunc fills the same purpose as Updater.UnhandledErrFunc. errFunc ErrorFunc - // errorLog fills the same purpose as Updater.ErrorLog. - errorLog *log.Logger + // logger fills the same purpose as Updater.Logger. + logger *slog.Logger } var ErrBotAlreadyExists = errors.New("bot already exists in bot mapping") @@ -184,7 +184,7 @@ func (m *botMapping) getHandlerFunc(prefix string) func(writer http.ResponseWrit if m.errFunc != nil { m.errFunc(err) } else { - m.logf("Failed to read incoming update contents: %s", err.Error()) + logError(m.logger, "failed to read incoming update contents", err) } w.WriteHeader(http.StatusInternalServerError) return @@ -194,14 +194,6 @@ func (m *botMapping) getHandlerFunc(prefix string) func(writer http.ResponseWrit } } -func (m *botMapping) logf(format string, args ...interface{}) { - if m.errorLog != nil { - m.errorLog.Printf(format, args...) - } else { - log.Printf(format, args...) - } -} - func (b *botData) stop() { // Close stopUpdates loops first, to ensure any updates currently being polled have the time to be sent to the updateChan. if b.stopUpdates != nil { diff --git a/ext/common.go b/ext/common.go new file mode 100644 index 0000000..70604cd --- /dev/null +++ b/ext/common.go @@ -0,0 +1,14 @@ +package ext + +import ( + "log" + "log/slog" +) + +func logError(l *slog.Logger, text string, err error) { + if l == nil { + log.Printf("ERROR: %s: %s", text, err) + return + } + l.Error(text, "error", err) +} diff --git a/ext/dispatcher.go b/ext/dispatcher.go index 5074ad3..29655f1 100644 --- a/ext/dispatcher.go +++ b/ext/dispatcher.go @@ -4,7 +4,8 @@ import ( "encoding/json" "errors" "fmt" - "log" + "log/slog" + "os" "runtime/debug" "strings" "sync" @@ -74,11 +75,11 @@ type Dispatcher struct { // UnhandledErrFunc provides more flexibility for dealing with unhandled update processing errors. // This includes errors when unmarshalling updates, unhandled panics during handler executions, or unknown // dispatcher actions. - // If nil, the error goes to ErrorLog. + // If nil, the error goes to the logger. UnhandledErrFunc ErrorFunc - // ErrorLog specifies an optional logger for unexpected behavior from handlers. + // Logger specifies an optional logger for unexpected behavior from handlers. // If nil, logging is done via the log package's standard logger. - ErrorLog *log.Logger + Logger *slog.Logger // handlers represents all available handlers. handlers handlerMapping @@ -101,18 +102,18 @@ type DispatcherOpts struct { // More info at Dispatcher.Error. Error DispatcherErrorHandler // Panic handles any panics that occur during handler execution. - // If no panic handlers are defined, the stack is logged to ErrorLog. + // If no panic handlers are defined, the stack is logged to the logger. // More info at Dispatcher.Panic. Panic DispatcherPanicHandler // UnhandledErrFunc provides more flexibility for dealing with unhandled update processing errors. // This includes errors when unmarshalling updates, unhandled panics during handler executions, or unknown // dispatcher actions. - // If nil, the error goes to ErrorLog. + // If nil, the error goes to the logger. UnhandledErrFunc ErrorFunc - // ErrorLog specifies an optional logger for unexpected behavior from handlers. + // logger specifies an optional logger for unexpected behavior from handlers. // If nil, logging is done via the log package's standard logger. - ErrorLog *log.Logger + Logger *slog.Logger // MaxRoutines is used to decide how to limit the number of goroutines spawned by the dispatcher. // This defines how many updates can be processed at the same time. @@ -127,7 +128,7 @@ func NewDispatcher(opts *DispatcherOpts) *Dispatcher { var errHandler DispatcherErrorHandler var panicHandler DispatcherPanicHandler var unhandledErrFunc ErrorFunc - var errLog *log.Logger + logger := slog.New(slog.NewTextHandler(os.Stderr, nil)) maxRoutines := DefaultMaxRoutines processor := Processor(BaseProcessor{}) @@ -143,7 +144,7 @@ func NewDispatcher(opts *DispatcherOpts) *Dispatcher { errHandler = opts.Error panicHandler = opts.Panic unhandledErrFunc = opts.UnhandledErrFunc - errLog = opts.ErrorLog + logger = opts.Logger } var limiter chan struct{} @@ -157,25 +158,17 @@ func NewDispatcher(opts *DispatcherOpts) *Dispatcher { } return &Dispatcher{ + Logger: logger, Processor: processor, Error: errHandler, Panic: panicHandler, UnhandledErrFunc: unhandledErrFunc, - ErrorLog: errLog, handlers: handlerMapping{}, limiter: limiter, waitGroup: sync.WaitGroup{}, } } -func (d *Dispatcher) logf(format string, args ...interface{}) { - if d.ErrorLog != nil { - d.ErrorLog.Printf(format, args...) - } else { - log.Printf(format, args...) - } -} - // CurrentUsage returns the current number of concurrently processing updates. func (d *Dispatcher) CurrentUsage() int { return len(d.limiter) @@ -215,7 +208,7 @@ func (d *Dispatcher) Start(b *gotgbot.Bot, updates <-chan json.RawMessage) { if d.UnhandledErrFunc != nil { d.UnhandledErrFunc(err) } else { - d.logf("Failed to process update: %s", err.Error()) + logError(d.Logger, "failed to process update", err) } } diff --git a/ext/updater.go b/ext/updater.go index e664617..7a92cfa 100644 --- a/ext/updater.go +++ b/ext/updater.go @@ -5,9 +5,10 @@ import ( "encoding/json" "errors" "fmt" - "log" + "log/slog" "net" "net/http" + "os" "strconv" "strings" "time" @@ -32,11 +33,11 @@ type Updater struct { // UnhandledErrFunc provides more flexibility for dealing with previously unhandled errors, such as failures to get // updates (when long-polling), or failures to unmarshal. - // If nil, the error goes to ErrorLog. + // If nil, the error goes to the logger. UnhandledErrFunc ErrorFunc - // ErrorLog specifies an optional logger for unexpected behavior from handlers. + // Logger specifies an optional logger for unexpected behavior from handlers. // If nil, logging is done via the log package's standard logger. - ErrorLog *log.Logger + Logger *slog.Logger // stopIdling is the channel that blocks the main thread from exiting, to keep the bots running. stopIdling chan struct{} @@ -51,42 +52,34 @@ type Updater struct { type UpdaterOpts struct { // UnhandledErrFunc provides more flexibility for dealing with previously unhandled errors, such as failures to get // updates (when long-polling), or failures to unmarshal. - // If nil, the error goes to ErrorLog. + // If nil, the error goes to the logger. UnhandledErrFunc ErrorFunc - // ErrorLog specifies an optional logger for unexpected behavior from handlers. + // Logger specifies an optional logger for unexpected behavior from handlers. // If nil, logging is done via the log package's standard logger. - ErrorLog *log.Logger + Logger *slog.Logger } // NewUpdater Creates a new Updater, as well as a Dispatcher and any optional updater configurations (via UpdaterOpts). func NewUpdater(dispatcher UpdateDispatcher, opts *UpdaterOpts) *Updater { var unhandledErrFunc ErrorFunc - var errLog *log.Logger + logger := slog.New(slog.NewTextHandler(os.Stderr, nil)) if opts != nil { unhandledErrFunc = opts.UnhandledErrFunc - errLog = opts.ErrorLog + logger = opts.Logger } return &Updater{ Dispatcher: dispatcher, UnhandledErrFunc: unhandledErrFunc, - ErrorLog: errLog, + Logger: logger, botMapping: botMapping{ - errFunc: unhandledErrFunc, - errorLog: errLog, + errFunc: unhandledErrFunc, + logger: logger, }, } } -func (u *Updater) logf(format string, args ...interface{}) { - if u.ErrorLog != nil { - u.ErrorLog.Printf(format, args...) - } else { - log.Printf(format, args...) - } -} - // PollingOpts represents the optional values to start long polling. type PollingOpts struct { // DropPendingUpdates toggles whether to drop updates which were sent before the bot was started. @@ -185,7 +178,7 @@ func (u *Updater) pollingLoop(bData *botData, opts *gotgbot.RequestOpts, v map[s if u.UnhandledErrFunc != nil { u.UnhandledErrFunc(err) } else { - u.logf("Failed to get updates; sleeping 1s: %s", err.Error()) + logError(u.Logger, "failed to get updates; sleeping 1s", err) time.Sleep(time.Second) } continue @@ -199,7 +192,7 @@ func (u *Updater) pollingLoop(bData *botData, opts *gotgbot.RequestOpts, v map[s if u.UnhandledErrFunc != nil { u.UnhandledErrFunc(err) } else { - u.logf("Failed to unmarshal updates: %s", err.Error()) + logError(u.Logger, "failed to unmarshal updates", err) } continue } @@ -217,7 +210,7 @@ func (u *Updater) pollingLoop(bData *botData, opts *gotgbot.RequestOpts, v map[s if u.UnhandledErrFunc != nil { u.UnhandledErrFunc(err) } else { - u.logf("Failed to unmarshal last update: %s", err.Error()) + logError(u.Logger, "failed to unmarshal last update", err) } continue }