Skip to content

Commit

Permalink
move to using slog for internal logging requirements
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulSonOfLars committed Nov 3, 2024
1 parent f72e10b commit 5ed76b7
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 55 deletions.
16 changes: 4 additions & 12 deletions ext/botmapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"encoding/json"
"errors"
"io"
"log"
"log/slog"
"net/http"
"strings"
"sync"
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand Down
14 changes: 14 additions & 0 deletions ext/common.go
Original file line number Diff line number Diff line change
@@ -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)
}
33 changes: 13 additions & 20 deletions ext/dispatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import (
"encoding/json"
"errors"
"fmt"
"log"
"log/slog"
"os"
"runtime/debug"
"strings"
"sync"
Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand All @@ -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{})
Expand All @@ -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{}
Expand All @@ -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)
Expand Down Expand Up @@ -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)
}
}

Expand Down
39 changes: 16 additions & 23 deletions ext/updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import (
"encoding/json"
"errors"
"fmt"
"log"
"log/slog"
"net"
"net/http"
"os"
"strconv"
"strings"
"time"
Expand All @@ -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{}
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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
}
Expand All @@ -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
}
Expand Down

0 comments on commit 5ed76b7

Please sign in to comment.