Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try out using the new log/slog library for layered logging information #202

Open
wants to merge 5 commits into
base: v2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 4 additions & 12 deletions ext/botmapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"encoding/json"
"errors"
"io"
"log"
"log/slog"
"net/http"
"strings"
"sync"
Expand Down Expand Up @@ -46,8 +46,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 (
Expand Down Expand Up @@ -198,7 +198,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 @@ -208,14 +208,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)
}
34 changes: 12 additions & 22 deletions ext/dispatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"encoding/json"
"errors"
"fmt"
"log"
"log/slog"
"runtime/debug"
"strings"
"sync"
Expand Down Expand Up @@ -74,11 +74,10 @@ 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.
// If nil, logging is done via the log package's standard logger.
ErrorLog *log.Logger
// Logger specifies an optional logger for unexpected behavior from handlers.
Logger *slog.Logger

// handlers represents all available handlers.
handlers handlerMapping
Expand All @@ -101,18 +100,17 @@ 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.
// If nil, logging is done via the log package's standard logger.
ErrorLog *log.Logger
// Logger specifies an optional logger for unexpected behavior from handlers.
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 +125,7 @@ func NewDispatcher(opts *DispatcherOpts) *Dispatcher {
var errHandler DispatcherErrorHandler
var panicHandler DispatcherPanicHandler
var unhandledErrFunc ErrorFunc
var errLog *log.Logger
logger := slog.Default()

maxRoutines := DefaultMaxRoutines
processor := Processor(BaseProcessor{})
Expand All @@ -143,7 +141,7 @@ func NewDispatcher(opts *DispatcherOpts) *Dispatcher {
errHandler = opts.Error
panicHandler = opts.Panic
unhandledErrFunc = opts.UnhandledErrFunc
errLog = opts.ErrorLog
logger = opts.Logger
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is opinionated, but I find that having this type of helper function may help in some cases:

func iftrue[T any](cond bool, t T, f T) T {
   if cond {
      return t
   }
   return f
}

(addressing the lack of C-style ternary condition operator ?: in Go)

and then:

logger = iftrue(opts.Logger == nil, logger, opts.Logger)

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooh, I like that, thank you!

}

var limiter chan struct{}
Expand All @@ -157,25 +155,17 @@ func NewDispatcher(opts *DispatcherOpts) *Dispatcher {
}

return &Dispatcher{
Logger: logger.With("component", "dispatcher"),
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 +205,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
40 changes: 15 additions & 25 deletions ext/updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"log"
"log/slog"
"net"
"net/http"
"strconv"
Expand All @@ -32,11 +32,10 @@ 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.
// If nil, logging is done via the log package's standard logger.
ErrorLog *log.Logger
// Logger specifies an optional logger for unexpected behavior from handlers.
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 +50,33 @@ 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.
// If nil, logging is done via the log package's standard logger.
ErrorLog *log.Logger
// Logger specifies an optional logger for unexpected behavior from handlers.
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.Default()

if opts != nil {
unhandledErrFunc = opts.UnhandledErrFunc
errLog = opts.ErrorLog
logger = opts.Logger
}

return &Updater{
Dispatcher: dispatcher,
UnhandledErrFunc: unhandledErrFunc,
ErrorLog: errLog,
Logger: logger.With("component", "updater"),
botMapping: botMapping{
errFunc: unhandledErrFunc,
errorLog: errLog,
errFunc: unhandledErrFunc,
logger: logger.With("component", "botmapping"),
},
}
}

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 @@ -196,7 +186,7 @@ func (u *Updater) pollingLoop(ctx context.Context, bData *botData, opts *gotgbot
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 @@ -210,7 +200,7 @@ func (u *Updater) pollingLoop(ctx context.Context, bData *botData, opts *gotgbot
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 @@ -228,7 +218,7 @@ func (u *Updater) pollingLoop(ctx context.Context, bData *botData, opts *gotgbot
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
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module github.com/PaulSonOfLars/gotgbot/v2

go 1.19
go 1.21
2 changes: 1 addition & 1 deletion samples/callbackqueryBot/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/PaulSonOfLars/gotgbot/samples/callbackqueryBot

go 1.19
go 1.21

require github.com/PaulSonOfLars/gotgbot/v2 v2.99.99

Expand Down
2 changes: 1 addition & 1 deletion samples/commandBot/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/PaulSonOfLars/gotgbot/samples/commandBot

go 1.19
go 1.21

require github.com/PaulSonOfLars/gotgbot/v2 v2.99.99

Expand Down
2 changes: 1 addition & 1 deletion samples/conversationBot/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/PaulSonOfLars/gotgbot/samples/conversationBot

go 1.19
go 1.21

require github.com/PaulSonOfLars/gotgbot/v2 v2.99.99

Expand Down
2 changes: 1 addition & 1 deletion samples/echoBot/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/PaulSonOfLars/gotgbot/samples/echoBot

go 1.19
go 1.21

require github.com/PaulSonOfLars/gotgbot/v2 v2.99.99

Expand Down
2 changes: 1 addition & 1 deletion samples/echoMultiBot/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/PaulSonOfLars/gotgbot/samples/echoMultiBot

go 1.19
go 1.21

require github.com/PaulSonOfLars/gotgbot/v2 v2.99.99

Expand Down
2 changes: 1 addition & 1 deletion samples/echoWebhookBot/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/PaulSonOfLars/gotgbot/samples/echoWebhookBot

go 1.19
go 1.21

require github.com/PaulSonOfLars/gotgbot/v2 v2.99.99

Expand Down
2 changes: 1 addition & 1 deletion samples/inlinequeryBot/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/PaulSonOfLars/gotgbot/samples/inlinequeryBot

go 1.19
go 1.21

require github.com/PaulSonOfLars/gotgbot/v2 v2.99.99

Expand Down
2 changes: 1 addition & 1 deletion samples/metricsBot/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/PaulSonOfLars/gotgbot/samples/metricsBot

go 1.19
go 1.21

require (
github.com/PaulSonOfLars/gotgbot/v2 v2.99.99
Expand Down
1 change: 1 addition & 0 deletions samples/metricsBot/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
Expand Down
2 changes: 1 addition & 1 deletion samples/middlewareBot/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/PaulSonOfLars/gotgbot/samples/middlewareBot

go 1.19
go 1.21

require github.com/PaulSonOfLars/gotgbot/v2 v2.99.99

Expand Down
2 changes: 1 addition & 1 deletion samples/paymentsBot/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/PaulSonOfLars/gotgbot/samples/paymentsBot

go 1.19
go 1.21

require (
github.com/PaulSonOfLars/gotgbot/v2 v2.99.99
Expand Down
2 changes: 1 addition & 1 deletion samples/statefulClientBot/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/PaulSonOfLars/gotgbot/samples/statefulClientBot

go 1.19
go 1.21

require github.com/PaulSonOfLars/gotgbot/v2 v2.99.99

Expand Down
2 changes: 1 addition & 1 deletion samples/webappBot/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/PaulSonOfLars/gotgbot/samples/webappBot

go 1.19
go 1.21

require github.com/PaulSonOfLars/gotgbot/v2 v2.99.99

Expand Down
2 changes: 1 addition & 1 deletion scripts/ci/ensure-consistent-sample-mod-files.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set -euo pipefail
SAMPLES_DIR="samples"

REPO="github.com/PaulSonOfLars/gotgbot" # Current library import path
GO_VERSION="1.19" # Go version we expect our samples to be using
GO_VERSION="1.21" # Go version we expect our samples to be using
V_MAJOR="v2" # Current major version for the library
V_DUMMY="v2.99.99" # dummy version for the library

Expand Down
Loading