diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 345ea9c17..c20a0c05c 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,6 +1,8 @@ name: Go -on: [ push ] +on: + push: + pull_request_target: jobs: gobuild: @@ -8,7 +10,7 @@ jobs: steps: - uses: actions/setup-go@v3 with: - go-version: 1.18 + go-version: 1.21 - uses: actions/checkout@v3 - name: go build run: go build -v ./... @@ -18,7 +20,7 @@ jobs: steps: - uses: actions/setup-go@v3 with: - go-version: 1.18 + go-version: 1.21 - uses: actions/checkout@v3 - name: go build run: go test -v ./... @@ -28,7 +30,7 @@ jobs: steps: - uses: actions/setup-go@v3 with: - go-version: 1.18 + go-version: 1.21 - uses: actions/checkout@v3 - name: golangci-lint uses: golangci/golangci-lint-action@v3 diff --git a/README.md b/README.md index 571240c10..962920449 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ A full Ping Pong example can also be found [here](https://github.com/disgoorg/di ### Logging -DisGo uses our own small [logging interface](https://github.com/disgoorg/log) which you can use with most other logging libraries. This lib also comes with a default logger which is based on the standard log package. +DisGo uses [slog](https://pkg.go.dev/log/slog) for logging. ## Documentation @@ -156,10 +156,6 @@ Being used in production by FredBoat, Dyno, LewdBot, and more. Is a [Lavalink-Client](https://github.com/freyacodes/Lavalink) which can be used to communicate with Lavalink to play/search tracks -### [DisLog](https://github.com/disgoorg/dislog) - -Is a Discord webhook logger hook for [logrus](https://github.com/sirupsen/logrus) - ## Other Golang Discord Libraries * [discordgo](https://github.com/bwmarrin/discordgo) diff --git a/_examples/application_commands/gateway/example.go b/_examples/application_commands/gateway/example.go index fe7b6615c..e318e7ee8 100644 --- a/_examples/application_commands/gateway/example.go +++ b/_examples/application_commands/gateway/example.go @@ -2,17 +2,16 @@ package main import ( "context" + "log/slog" "os" "os/signal" "syscall" - "github.com/disgoorg/log" - "github.com/disgoorg/snowflake/v2" - "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/events" + "github.com/disgoorg/snowflake/v2" ) var ( @@ -40,30 +39,29 @@ var ( ) func main() { - log.SetLevel(log.LevelInfo) - log.Info("starting example...") - log.Info("disgo version: ", disgo.Version) + slog.Info("starting example...") + slog.Info("disgo version", slog.String("version", disgo.Version)) client, err := disgo.New(token, bot.WithDefaultGateway(), bot.WithEventListenerFunc(commandListener), ) if err != nil { - log.Fatal("error while building disgo instance: ", err) + slog.Error("error while building disgo instance", slog.Any("err", err)) return } defer client.Close(context.TODO()) if _, err = client.Rest().SetGuildCommands(client.ApplicationID(), guildID, commands); err != nil { - log.Fatal("error while registering commands: ", err) + slog.Error("error while registering commands", slog.Any("err", err)) } if err = client.OpenGateway(context.TODO()); err != nil { - log.Fatal("error while connecting to gateway: ", err) + slog.Error("error while connecting to gateway", slog.Any("err", err)) } - log.Infof("example is now running. Press CTRL-C to exit.") + slog.Info("example is now running. Press CTRL-C to exit.") s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-s @@ -78,7 +76,7 @@ func commandListener(event *events.ApplicationCommandInteractionCreate) { Build(), ) if err != nil { - event.Client().Logger().Error("error on sending response: ", err) + slog.Error("error on sending response", slog.Any("err", err)) } } } diff --git a/_examples/application_commands/http/example.go b/_examples/application_commands/http/example.go index 85b2f4d13..ee4b1a3df 100644 --- a/_examples/application_commands/http/example.go +++ b/_examples/application_commands/http/example.go @@ -2,19 +2,18 @@ package main import ( "context" + "log/slog" "os" "os/signal" "syscall" - "github.com/disgoorg/log" - "github.com/disgoorg/snowflake/v2" - "github.com/oasisprotocol/curve25519-voi/primitives/ed25519" - "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/events" "github.com/disgoorg/disgo/httpserver" + "github.com/disgoorg/snowflake/v2" + "github.com/oasisprotocol/curve25519-voi/primitives/ed25519" ) var ( @@ -43,9 +42,8 @@ var ( ) func main() { - log.SetLevel(log.LevelDebug) - log.Info("starting example...") - log.Info("disgo version: ", disgo.Version) + slog.Info("starting example...") + slog.Info("disgo version", slog.String("version", disgo.Version)) // use custom ed25519 verify implementation httpserver.Verify = func(publicKey httpserver.PublicKey, message, sig []byte) bool { @@ -60,21 +58,20 @@ func main() { bot.WithEventListenerFunc(commandListener), ) if err != nil { - log.Fatal("error while building disgo instance: ", err) - return + panic("error while building disgo instance: " + err.Error()) } defer client.Close(context.TODO()) if _, err = client.Rest().SetGuildCommands(client.ApplicationID(), guildID, commands); err != nil { - log.Fatal("error while registering commands: ", err) + panic("error while registering commands: " + err.Error()) } if err = client.OpenHTTPServer(); err != nil { - log.Fatal("error while starting http server: ", err) + panic("error while starting http server: " + err.Error()) } - log.Info("example is now running. Press CTRL-C to exit.") + slog.Info("example is now running. Press CTRL-C to exit.") s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-s diff --git a/_examples/application_commands/http/go.mod b/_examples/application_commands/http/go.mod index a58b722b4..41e778051 100644 --- a/_examples/application_commands/http/go.mod +++ b/_examples/application_commands/http/go.mod @@ -1,10 +1,11 @@ module github.com/disgoorg/disgo/_examples/application_commands/http -go 1.18 +go 1.21 + +replace github.com/disgoorg/disgo => ../../../ require ( github.com/disgoorg/disgo v0.16.8 - github.com/disgoorg/log v1.2.1 github.com/disgoorg/snowflake/v2 v2.0.1 github.com/oasisprotocol/curve25519-voi v0.0.0-20230110094441-db37f07504ce ) @@ -14,6 +15,5 @@ require ( github.com/gorilla/websocket v1.5.0 // indirect github.com/sasha-s/go-csync v0.0.0-20210812194225-61421b77c44b // indirect golang.org/x/crypto v0.12.0 // indirect - golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b // indirect golang.org/x/sys v0.11.0 // indirect ) diff --git a/_examples/application_commands/http/go.sum b/_examples/application_commands/http/go.sum index dfd5b37d7..39b2a5fc4 100644 --- a/_examples/application_commands/http/go.sum +++ b/_examples/application_commands/http/go.sum @@ -1,10 +1,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/disgoorg/disgo v0.16.8 h1:tvUeX+3Iu8U6koDc8RAgcQadRciWJwsI95Y7edHqq2g= -github.com/disgoorg/disgo v0.16.8/go.mod h1:5fsaUpfu6Yv0p+PfmsAeQkV395KQskVu/d1bdq8vsNI= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/disgoorg/json v1.1.0 h1:7xigHvomlVA9PQw9bMGO02PHGJJPqvX5AnwlYg/Tnys= github.com/disgoorg/json v1.1.0/go.mod h1:BHDwdde0rpQFDVsRLKhma6Y7fTbQKub/zdGO5O9NqqA= -github.com/disgoorg/log v1.2.1 h1:kZYAWkUBcGy4LbZcgYtgYu49xNVLy+xG5Uq3yz5VVQs= -github.com/disgoorg/log v1.2.1/go.mod h1:hhQWYTFTnIGzAuFPZyXJEi11IBm9wq+/TVZt/FEwX0o= github.com/disgoorg/snowflake/v2 v2.0.1 h1:CuUxGLwggUxEswZOmZ+mZ5i0xSumQdXW9tXW7uGqe+0= github.com/disgoorg/snowflake/v2 v2.0.1/go.mod h1:SPU9c2CNn5DSyb86QcKtdZgix9osEtKrHLW4rMhfLCs= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= @@ -12,13 +9,14 @@ github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/oasisprotocol/curve25519-voi v0.0.0-20230110094441-db37f07504ce h1:/pEpMk55wH0X+E5zedGEMOdLuWmV8P4+4W3+LZaM6kg= github.com/oasisprotocol/curve25519-voi v0.0.0-20230110094441-db37f07504ce/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sasha-s/go-csync v0.0.0-20210812194225-61421b77c44b h1:qYTY2tN72LhgDj2rtWG+LI6TXFl2ygFQQ4YezfVaGQE= github.com/sasha-s/go-csync v0.0.0-20210812194225-61421b77c44b/go.mod h1:/pA7k3zsXKdjjAiUhB5CjuKib9KJGCaLvZwtxGC8U0s= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b h1:r+vk0EmXNmekl0S0BascoeeoHk/L7wmaW2QF90K+kYI= -golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/_examples/application_commands/localization/example.go b/_examples/application_commands/localization/example.go index 4a7d1d3b4..8f08bc192 100644 --- a/_examples/application_commands/localization/example.go +++ b/_examples/application_commands/localization/example.go @@ -2,17 +2,16 @@ package main import ( "context" + "log/slog" "os" "os/signal" "syscall" - "github.com/disgoorg/log" - "github.com/disgoorg/snowflake/v2" - "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/events" + "github.com/disgoorg/snowflake/v2" ) var ( @@ -64,30 +63,28 @@ var ( ) func main() { - log.SetLevel(log.LevelTrace) - log.Info("starting example...") - log.Infof("disgo version: %s", disgo.Version) + slog.Info("starting example...") + slog.Info("disgo version", slog.String("version", disgo.Version)) client, err := disgo.New(token, bot.WithDefaultGateway(), bot.WithEventListenerFunc(commandListener), ) if err != nil { - log.Fatal("error while building disgo instance: ", err) - return + panic("error while building disgo instance: " + err.Error()) } defer client.Close(context.TODO()) if _, err = client.Rest().SetGuildCommands(client.ApplicationID(), guildID, commands); err != nil { - log.Fatal("error while registering commands: ", err) + panic("error while registering commands: " + err.Error()) } if err = client.OpenGateway(context.TODO()); err != nil { - log.Fatal("error while connecting to gateway: ", err) + panic("error while connecting to gateway: " + err.Error()) } - log.Infof("example is now running. Press CTRL-C to exit.") + slog.Info("example is now running. Press CTRL-C to exit.") s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-s diff --git a/_examples/auto_moderation/example.go b/_examples/auto_moderation/example.go index c5e638b36..0e41558d9 100644 --- a/_examples/auto_moderation/example.go +++ b/_examples/auto_moderation/example.go @@ -3,20 +3,19 @@ package main import ( "context" "fmt" + "log/slog" "os" "os/signal" "syscall" "time" - "github.com/disgoorg/json" - "github.com/disgoorg/log" - "github.com/disgoorg/snowflake/v2" - "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/events" "github.com/disgoorg/disgo/gateway" + "github.com/disgoorg/json" + "github.com/disgoorg/snowflake/v2" ) var ( @@ -26,9 +25,8 @@ var ( ) func main() { - log.SetLevel(log.LevelInfo) - log.Info("starting example...") - log.Infof("disgo version: %s", disgo.Version) + slog.Info("starting example...") + slog.Info("disgo version", slog.String("version", disgo.Version)) client, err := disgo.New(token, bot.WithGatewayConfigOpts(gateway.WithIntents(gateway.IntentAutoModerationConfiguration, gateway.IntentAutoModerationExecution)), @@ -49,16 +47,18 @@ func main() { }), ) if err != nil { - log.Fatal("error while building bot: ", err) + slog.Error("error while building bot", slog.Any("err", err)) + return } defer client.Close(context.TODO()) if err = client.OpenGateway(context.TODO()); err != nil { - log.Fatal("error while connecting to gateway: ", err) + slog.Error("error while connecting to gateway", slog.Any("err", err)) + return } - log.Infof("example is now running. Press CTRL-C to exit.") + slog.Info("example is now running. Press CTRL-C to exit.") s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-s @@ -86,7 +86,7 @@ func showCaseAutoMod(client bot.Client) { Enabled: json.Ptr(true), }) if err != nil { - log.Error("error while creating rule: ", err) + slog.Error("error while creating rule", slog.Any("err", err)) return } @@ -107,7 +107,7 @@ func showCaseAutoMod(client bot.Client) { }, }) if err != nil { - log.Error("error while updating rule: ", err) + slog.Error("error while updating rule", slog.Any("err", err)) return } @@ -115,7 +115,7 @@ func showCaseAutoMod(client bot.Client) { err = client.Rest().DeleteAutoModerationRule(guildID, rule.ID) if err != nil { - log.Error("error while deleting rule: ", err) + slog.Error("error while deleting rule", slog.Any("err", err)) return } diff --git a/_examples/components/example.go b/_examples/components/example.go index 8e6b349ec..140976572 100644 --- a/_examples/components/example.go +++ b/_examples/components/example.go @@ -2,17 +2,15 @@ package main import ( "context" + "log/slog" "os" "os/signal" "syscall" "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/bot" - "github.com/disgoorg/disgo/events" - - "github.com/disgoorg/log" - "github.com/disgoorg/disgo/discord" + "github.com/disgoorg/disgo/events" "github.com/disgoorg/disgo/gateway" ) @@ -21,9 +19,8 @@ var ( ) func main() { - log.SetLevel(log.LevelDebug) - log.Info("starting example...") - log.Infof("disgo version: %s", disgo.Version) + slog.Info("starting example...") + slog.Info("disgo version", slog.String("version", disgo.Version)) client, err := disgo.New(token, bot.WithGatewayConfigOpts(gateway.WithIntents(gateway.IntentGuilds, gateway.IntentGuildMessages, gateway.IntentDirectMessages)), @@ -46,16 +43,17 @@ func main() { }), ) if err != nil { - log.Fatal("error while building bot: ", err) + slog.Error("error while building bot: ", err) + return } - defer client.Close(context.TODO()) if err = client.OpenGateway(context.TODO()); err != nil { - log.Fatal("error while connecting to gateway: ", err) + slog.Error("error while connecting to gateway: ", err) + return } - log.Infof("example is now running. Press CTRL-C to exit.") + slog.Info("example is now running. Press CTRL-C to exit.") s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-s diff --git a/_examples/custom_cache/example.go b/_examples/custom_cache/example.go index d2f94c191..bf2ed19c9 100644 --- a/_examples/custom_cache/example.go +++ b/_examples/custom_cache/example.go @@ -2,20 +2,19 @@ package main import ( "context" + "log/slog" "os" "os/signal" "sync" "syscall" "time" - "github.com/disgoorg/log" - "github.com/disgoorg/snowflake/v2" - "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/cache" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/gateway" + "github.com/disgoorg/snowflake/v2" ) var ( @@ -23,9 +22,8 @@ var ( ) func main() { - log.SetLevel(log.LevelDebug) - log.Info("starting example...") - log.Infof("disgo version: %s", disgo.Version) + slog.Info("starting example...") + slog.Info("disgo version", slog.String("version", disgo.Version)) client, err := disgo.New(token, bot.WithGatewayConfigOpts(gateway.WithIntents(gateway.IntentGuilds|gateway.IntentGuildMessages|gateway.IntentDirectMessages)), @@ -35,7 +33,8 @@ func main() { ), ) if err != nil { - log.Fatal("error while building bot: ", err) + slog.Error("error while building bot", slog.Any("err", err)) + return } defer func() { @@ -47,10 +46,10 @@ func main() { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err = client.OpenGateway(ctx); err != nil { - log.Fatal("error while connecting to gateway: ", err) + slog.Error("error while connecting to gateway", slog.Any("err", err)) } - log.Infof("example is now running. Press CTRL-C to exit.") + slog.Info("example is now running. Press CTRL-C to exit.") s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-s diff --git a/_examples/echo/echo.go b/_examples/echo/echo.go index 05b792ca9..080d05b56 100644 --- a/_examples/echo/echo.go +++ b/_examples/echo/echo.go @@ -3,21 +3,19 @@ package main import ( "context" "errors" - "fmt" + "log/slog" "net" "os" "os/signal" "syscall" "time" - "github.com/disgoorg/log" - "github.com/disgoorg/snowflake/v2" - "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/events" "github.com/disgoorg/disgo/gateway" "github.com/disgoorg/disgo/voice" + "github.com/disgoorg/snowflake/v2" ) var ( @@ -27,9 +25,7 @@ var ( ) func main() { - log.SetLevel(log.LevelTrace) - log.SetFlags(log.LstdFlags | log.Llongfile) - log.Info("starting up") + slog.Info("starting up") client, err := disgo.New(token, bot.WithGatewayConfigOpts(gateway.WithIntents(gateway.IntentGuildVoiceStates)), @@ -38,16 +34,18 @@ func main() { }), ) if err != nil { - log.Fatal("error creating client: ", err) + slog.Error("error creating client", slog.Any("err", err)) + return } defer client.Close(context.TODO()) if err = client.OpenGateway(context.TODO()); err != nil { - log.Fatal("error connecting to voicegateway: ", err) + slog.Error("error connecting to voice gateway", slog.Any("err", err)) + return } - log.Info("ExampleBot is now running. Press CTRL-C to exit.") + slog.Info("ExampleBot is now running. Press CTRL-C to exit.") s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill) <-s @@ -68,7 +66,7 @@ func play(client bot.Client) { conn.Close(ctx2) }() - println("starting playback") + slog.Info("starting playback") if err := conn.SetSpeaking(ctx, voice.SpeakingFlagMicrophone); err != nil { panic("error setting speaking flag: " + err.Error()) @@ -81,18 +79,18 @@ func play(client bot.Client) { packet, err := conn.UDP().ReadPacket() if err != nil { if errors.Is(err, net.ErrClosed) { - println("connection closed") + slog.Info("connection closed") return } - fmt.Printf("error while reading from reader: %s", err) + slog.Info("error while reading from reader", slog.Any("err", err)) continue } if _, err = conn.UDP().Write(packet.Opus); err != nil { if errors.Is(err, net.ErrClosed) { - println("connection closed") + slog.Info("connection closed") return } - fmt.Printf("error while writing to UDPConn: %s", err) + slog.Info("error while writing to UDPConn", slog.Any("err", err)) continue } } diff --git a/_examples/guild_scheduled_events/example.go b/_examples/guild_scheduled_events/example.go index 27ca45e24..af3b5acf3 100644 --- a/_examples/guild_scheduled_events/example.go +++ b/_examples/guild_scheduled_events/example.go @@ -2,13 +2,12 @@ package main import ( "context" + "log/slog" "os" "os/signal" "syscall" "time" - "github.com/disgoorg/log" - "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/cache" @@ -22,9 +21,7 @@ var ( ) func main() { - log.SetFlags(log.LstdFlags | log.Lshortfile) - log.SetLevel(log.LevelDebug) - log.Info("starting example...") + slog.Info("starting example...") client, err := disgo.New(token, bot.WithGatewayConfigOpts( @@ -36,22 +33,22 @@ func main() { bot.WithMemberChunkingFilter(bot.MemberChunkingFilterNone), bot.WithEventListeners(&events.ListenerAdapter{ OnGuildScheduledEventCreate: func(event *events.GuildScheduledEventCreate) { - log.Infof("%T\n", event) + slog.Info("OnGuildScheduledEventCreate") }, OnGuildScheduledEventUpdate: func(event *events.GuildScheduledEventUpdate) { - log.Infof("%T\n", event) + slog.Info("OnGuildScheduledEventUpdate") }, OnGuildScheduledEventDelete: func(event *events.GuildScheduledEventDelete) { - log.Infof("%T\n", event) + slog.Info("OnGuildScheduledEventDelete") }, OnGuildScheduledEventUserAdd: func(event *events.GuildScheduledEventUserAdd) { - log.Infof("%T\n", event) + slog.Info("OnGuildScheduledEventUserAdd") }, OnGuildScheduledEventUserRemove: func(event *events.GuildScheduledEventUserRemove) { - log.Infof("%T\n", event) + slog.Info("OnGuildScheduledEventUserRemove") }, OnMessageCreate: func(event *events.MessageCreate) { - log.Infof("%T\n", event) + slog.Info("OnMessageCreate") if event.Message.Content != "test" { return } @@ -60,7 +57,7 @@ func main() { Name: "test", PrivacyLevel: discord.ScheduledEventPrivacyLevelGuildOnly, ScheduledStartTime: time.Now().Add(time.Hour), - Description: "", + Description: "test", EntityType: discord.ScheduledEventEntityTypeVoice, }) @@ -68,7 +65,6 @@ func main() { gse, _ = event.Client().Rest().UpdateGuildScheduledEvent(gse.GuildID, gse.ID, discord.GuildScheduledEventUpdate{ Status: &status, }) - //_ = gse.AudioChannel().Connect() time.Sleep(time.Second * 10) @@ -76,20 +72,19 @@ func main() { gse, _ = event.Client().Rest().UpdateGuildScheduledEvent(gse.GuildID, gse.ID, discord.GuildScheduledEventUpdate{ Status: &status, }) - //_ = gse.Guilds().Disconnect() }, }), ) if err != nil { - log.Fatal("error while building bot instance: ", err) + slog.Error("error while building bot instance", slog.Any("err", err)) return } if err = client.OpenGateway(context.TODO()); err != nil { - log.Fatal("error while connecting to discord: ", err) + slog.Error("error while connecting to discord", slog.Any("err", err)) } - log.Info("Example is now running. Press CTRL-C to exit.") + slog.Info("Example is now running. Press CTRL-C to exit.") s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-s diff --git a/_examples/handler/example.go b/_examples/handler/example.go index 44c2a826c..8ccf4fe4b 100644 --- a/_examples/handler/example.go +++ b/_examples/handler/example.go @@ -2,19 +2,18 @@ package main import ( "context" + "log/slog" "os" "os/signal" "syscall" - "github.com/disgoorg/log" - "github.com/disgoorg/snowflake/v2" - "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/events" "github.com/disgoorg/disgo/handler" "github.com/disgoorg/disgo/handler/middleware" + "github.com/disgoorg/snowflake/v2" ) var ( @@ -64,9 +63,8 @@ var ( ) func main() { - log.SetLevel(log.LevelInfo) - log.Info("starting example...") - log.Infof("disgo version: %s", disgo.Version) + slog.Info("starting example...") + slog.Info("disgo version", slog.String("version", disgo.Version)) r := handler.New() r.Use(middleware.Logger) @@ -92,20 +90,22 @@ func main() { bot.WithEventListeners(r), ) if err != nil { - log.Fatal("error while building bot: ", err) + slog.Error("error while building bot", slog.Any("err", err)) + return } if err = handler.SyncCommands(client, commands, []snowflake.ID{guildID}); err != nil { - log.Fatal("error while syncing commands: ", err) + slog.Error("error while syncing commands", slog.Any("err", err)) + return } defer client.Close(context.TODO()) if err = client.OpenGateway(context.TODO()); err != nil { - log.Fatal("error while connecting to gateway: ", err) + slog.Error("error while connecting to gateway", slog.Any("err", err)) } - log.Info("example is now running. Press CTRL-C to exit.") + slog.Info("example is now running. Press CTRL-C to exit.") s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-s diff --git a/_examples/listening_events/example.go b/_examples/listening_events/example.go index 52bcd9e36..0d1102a48 100644 --- a/_examples/listening_events/example.go +++ b/_examples/listening_events/example.go @@ -2,17 +2,16 @@ package main import ( "context" + "log/slog" "os" "os/signal" "syscall" - "github.com/disgoorg/log" - "github.com/disgoorg/snowflake/v2" - "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/events" + "github.com/disgoorg/snowflake/v2" ) var ( @@ -21,9 +20,8 @@ var ( ) func main() { - log.SetLevel(log.LevelInfo) - log.Info("starting example...") - log.Info("disgo version: ", disgo.Version) + slog.Info("starting example...") + slog.Info("disgo version", slog.String("version", disgo.Version)) client, err := disgo.New(token, bot.WithDefaultGateway(), @@ -32,17 +30,17 @@ func main() { bot.WithEventListeners(&events.ListenerAdapter{OnMessageCreate: eventListenerFunc}), ) if err != nil { - log.Fatal("error while building disgo instance: ", err) + slog.Error("error while building disgo instance", slog.Any("err", err)) return } defer client.Close(context.TODO()) if err = client.OpenGateway(context.TODO()); err != nil { - log.Fatal("error while connecting to gateway: ", err) + slog.Error("error while connecting to gateway", slog.Any("err", err)) } - log.Infof("example is now running. Press CTRL-C to exit.") + slog.Info("example is now running. Press CTRL-C to exit.") s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-s diff --git a/_examples/message_collector/example.go b/_examples/message_collector/example.go index f9ffe3536..c5dd4698d 100644 --- a/_examples/message_collector/example.go +++ b/_examples/message_collector/example.go @@ -2,6 +2,7 @@ package main import ( "context" + "log/slog" "os" "os/signal" "strconv" @@ -10,9 +11,6 @@ import ( "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/bot" - - "github.com/disgoorg/log" - "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/events" "github.com/disgoorg/disgo/gateway" @@ -23,25 +21,26 @@ var ( ) func main() { - log.SetLevel(log.LevelDebug) - log.Info("starting example...") - log.Infof("disgo version: %s", disgo.Version) + slog.Info("starting example...") + slog.Info("disgo version", slog.String("version", disgo.Version)) client, err := disgo.New(token, bot.WithGatewayConfigOpts(gateway.WithIntents(gateway.IntentGuilds, gateway.IntentGuildMessages, gateway.IntentDirectMessages, gateway.IntentMessageContent)), bot.WithEventListenerFunc(onMessageCreate), ) if err != nil { - log.Fatal("error while building bot: ", err) + slog.Error("error while building bot", slog.Any("err", err)) + return } defer client.Close(context.TODO()) if err = client.OpenGateway(context.TODO()); err != nil { - log.Fatal("error while connecting to gateway: ", err) + slog.Error("error while connecting to gateway", slog.Any("err", err)) + return } - log.Infof("example is now running. Press CTRL-C to exit.") + slog.Info("example is now running. Press CTRL-C to exit.") s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-s diff --git a/_examples/oauth2/example.go b/_examples/oauth2/example.go index 46111f755..6e1c323fd 100644 --- a/_examples/oauth2/example.go +++ b/_examples/oauth2/example.go @@ -2,19 +2,18 @@ package main import ( "fmt" + "log/slog" "math/rand" "net/http" "os" "time" - "github.com/disgoorg/json" - "github.com/disgoorg/log" - "github.com/disgoorg/snowflake/v2" - "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/oauth2" "github.com/disgoorg/disgo/rest" + "github.com/disgoorg/json" + "github.com/disgoorg/snowflake/v2" ) var ( @@ -22,7 +21,6 @@ var ( clientID = snowflake.GetEnv("client_id") clientSecret = os.Getenv("client_secret") baseURL = os.Getenv("base_url") - logger = log.Default() httpClient = http.DefaultClient client oauth2.Client sessions map[string]oauth2.Session @@ -33,11 +31,10 @@ func init() { } func main() { - logger.SetLevel(log.LevelDebug) - logger.Info("starting example...") - logger.Infof("disgo %s", disgo.Version) + slog.Info("starting example...") + slog.Info("disgo version", slog.String("version", disgo.Version)) - client = oauth2.New(clientID, clientSecret, oauth2.WithLogger(logger), oauth2.WithRestClientConfigOpts(rest.WithHTTPClient(httpClient))) + client = oauth2.New(clientID, clientSecret, oauth2.WithRestClientConfigOpts(rest.WithHTTPClient(httpClient))) mux := http.NewServeMux() mux.HandleFunc("/", handleRoot) diff --git a/_examples/pagination/examplebot.go b/_examples/pagination/examplebot.go index 80a0c605f..b4efdce6f 100644 --- a/_examples/pagination/examplebot.go +++ b/_examples/pagination/examplebot.go @@ -1,11 +1,9 @@ package main import ( - _ "embed" + "log/slog" "os" - "github.com/disgoorg/log" - "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/rest" ) @@ -13,10 +11,8 @@ import ( var token = os.Getenv("disgo_token") func main() { - log.SetFlags(log.LstdFlags | log.Lshortfile) - log.SetLevel(log.LevelDebug) - log.Info("starting example...") - log.Info("bot version: ", disgo.Version) + slog.Info("starting example...") + slog.Info("disgo version", slog.String("version", disgo.Version)) client := rest.New(rest.NewClient(token)) @@ -25,15 +21,15 @@ func main() { var i int for page.Next() { for _, m := range page.Items { - println(m.ID) + slog.Info(m.ID.String()) } - println("---") + slog.Info("---") i++ if i >= 3 { break } } if page.Err != nil { - log.Error(page.Err) + slog.Error("error getting messages", slog.Any("err", page.Err)) } } diff --git a/_examples/ping_pong/example.go b/_examples/ping_pong/example.go index 0a89fc7fc..7e65508cb 100644 --- a/_examples/ping_pong/example.go +++ b/_examples/ping_pong/example.go @@ -2,12 +2,11 @@ package main import ( "context" + "log/slog" "os" "os/signal" "syscall" - "github.com/disgoorg/log" - "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/discord" @@ -16,8 +15,8 @@ import ( ) func main() { - log.SetLevel(log.LevelDebug) - log.SetFlags(log.LstdFlags | log.Lshortfile) + slog.Info("starting example...") + slog.Info("disgo version", slog.String("version", disgo.Version)) client, err := disgo.New(os.Getenv("disgo_token"), bot.WithGatewayConfigOpts( @@ -29,16 +28,18 @@ func main() { bot.WithEventListenerFunc(onMessageCreate), ) if err != nil { - log.Fatal("error while building disgo: ", err) + slog.Error("error while building disgo", slog.String("err", err.Error())) + return } defer client.Close(context.TODO()) if err = client.OpenGateway(context.TODO()); err != nil { - log.Fatal("errors while connecting to gateway: ", err) + slog.Error("errors while connecting to gateway", slog.String("err", err.Error())) + return } - log.Info("example is now running. Press CTRL-C to exit.") + slog.Info("example is now running. Press CTRL-C to exit.") s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-s diff --git a/_examples/proxy/example.go b/_examples/proxy/example.go index 4dfd5810d..399fd68e0 100644 --- a/_examples/proxy/example.go +++ b/_examples/proxy/example.go @@ -2,13 +2,11 @@ package main import ( "context" + "log/slog" "os" "os/signal" "syscall" - "github.com/disgoorg/log" - "github.com/disgoorg/snowflake/v2" - "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/discord" @@ -16,6 +14,7 @@ import ( "github.com/disgoorg/disgo/gateway" "github.com/disgoorg/disgo/rest" "github.com/disgoorg/disgo/sharding" + "github.com/disgoorg/snowflake/v2" ) var ( @@ -45,9 +44,8 @@ var ( ) func main() { - log.SetLevel(log.LevelInfo) - log.Info("starting example...") - log.Info("disgo version: ", disgo.Version) + slog.Info("starting example...") + slog.Info("disgo version", slog.String("version", disgo.Version)) client, err := disgo.New(token, bot.WithShardManagerConfigOpts( @@ -65,21 +63,23 @@ func main() { ) if err != nil { - log.Fatal("error while building disgo instance: ", err) + slog.Error("error while building disgo instance", slog.Any("err", err)) return } defer client.Close(context.TODO()) if _, err = client.Rest().SetGuildCommands(client.ApplicationID(), guildID, commands); err != nil { - log.Fatal("error while registering commands: ", err) + slog.Error("error while registering commands", slog.Any("err", err)) + return } if err = client.OpenGateway(context.TODO()); err != nil { - log.Fatal("error while connecting to gateway: ", err) + slog.Error("error while connecting to gateway", slog.Any("err", err)) + return } - log.Infof("example is now running. Press CTRL-C to exit.") + slog.Info("example is now running. Press CTRL-C to exit.") s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-s @@ -94,7 +94,7 @@ func commandListener(event *events.ApplicationCommandInteractionCreate) { Build(), ) if err != nil { - event.Client().Logger().Error("error on sending response: ", err) + slog.Error("error on sending response", slog.Any("err", err)) } } } diff --git a/_examples/sharding/example.go b/_examples/sharding/example.go index 135c7b8cd..6c98706da 100644 --- a/_examples/sharding/example.go +++ b/_examples/sharding/example.go @@ -2,12 +2,11 @@ package main import ( "context" + "log/slog" "os" "os/signal" "syscall" - "github.com/disgoorg/log" - "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/discord" @@ -21,10 +20,8 @@ var ( ) func main() { - log.SetFlags(log.LstdFlags | log.Lshortfile) - log.SetLevel(log.LevelDebug) - log.Info("starting example...") - log.Info("disgo version: ", disgo.Version) + slog.Info("starting example...") + slog.Info("disgo version", slog.Any("version", disgo.Version)) client, err := disgo.New(token, bot.WithShardManagerConfigOpts( @@ -39,24 +36,26 @@ func main() { bot.WithEventListeners(&events.ListenerAdapter{ OnMessageCreate: onMessageCreate, OnGuildReady: func(event *events.GuildReady) { - log.Infof("guild %s ready", event.GuildID) + slog.Info("guild %s ready", event.GuildID) }, OnGuildsReady: func(event *events.GuildsReady) { - log.Infof("guilds on shard %d ready", event.ShardID) + slog.Info("guilds on shard %d ready", event.ShardID) }, }), ) if err != nil { - log.Fatalf("error while building disgo: %s", err) + slog.Error("error while building disgo", slog.Any("err", err)) + return } defer client.Close(context.TODO()) if err = client.OpenShardManager(context.TODO()); err != nil { - log.Fatal("error while connecting to gateway: ", err) + slog.Error("error while connecting to gateway", slog.Any("err", err)) + return } - log.Infof("example is now running. Press CTRL-C to exit.") + slog.Info("example is now running. Press CTRL-C to exit.") s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-s diff --git a/_examples/test/commands.go b/_examples/test/commands.go index e3a85ab01..dec675376 100644 --- a/_examples/test/commands.go +++ b/_examples/test/commands.go @@ -1,7 +1,7 @@ package main import ( - "github.com/disgoorg/log" + "log/slog" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/discord" @@ -40,6 +40,6 @@ var commands = []discord.ApplicationCommandCreate{ func registerCommands(client bot.Client) { if _, err := client.Rest().SetGuildCommands(client.ApplicationID(), guildID, commands); err != nil { - log.Fatalf("error while registering guild commands: %s", err) + slog.Error("error while registering guild commands", slog.Any("err", err)) } } diff --git a/_examples/test/examplebot.go b/_examples/test/examplebot.go index cac003bed..0d72c9776 100644 --- a/_examples/test/examplebot.go +++ b/_examples/test/examplebot.go @@ -3,18 +3,17 @@ package main import ( "context" _ "embed" + "log/slog" "os" "os/signal" "syscall" - "github.com/disgoorg/log" - "github.com/disgoorg/snowflake/v2" - "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/cache" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/gateway" + "github.com/disgoorg/snowflake/v2" ) var ( @@ -26,10 +25,8 @@ var ( ) func main() { - log.SetFlags(log.LstdFlags | log.Lshortfile) - log.SetLevel(log.LevelDebug) - log.Info("starting example...") - log.Info("bot version: ", disgo.Version) + slog.Info("starting example...") + slog.Info("disgo version", slog.Any("version", disgo.Version)) client, err := disgo.New(token, bot.WithGatewayConfigOpts( @@ -43,19 +40,19 @@ func main() { bot.WithEventListeners(listener), ) if err != nil { - log.Fatal("error while building bot instance: ", err) + slog.Error("error while building bot instance", slog.Any("err", err)) return } registerCommands(client) if err = client.OpenGateway(context.TODO()); err != nil { - log.Fatal("error while connecting to discord: ", err) + slog.Error("error while connecting to discord", slog.Any("err", err)) } defer client.Close(context.TODO()) - log.Info("ExampleBot is now running. Press CTRL-C to exit.") + slog.Info("ExampleBot is now running. Press CTRL-C to exit.") s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-s diff --git a/_examples/test/listeners.go b/_examples/test/listeners.go index d883d432e..20d64ed01 100644 --- a/_examples/test/listeners.go +++ b/_examples/test/listeners.go @@ -2,11 +2,10 @@ package main import ( "bytes" + "log/slog" "strings" "time" - "github.com/disgoorg/log" - "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/events" @@ -88,7 +87,7 @@ func componentListener(event *events.ComponentInteractionCreate) { switch data.CustomID() { case "test3": if err := event.DeferUpdateMessage(); err != nil { - log.Errorf("error sending interaction response: %s", err) + slog.Error("error sending interaction response", slog.Any("err", err)) } _, _ = event.Client().Rest().CreateFollowupMessage(event.ApplicationID(), event.Token(), discord.NewMessageCreateBuilder(). SetEphemeral(true). @@ -101,7 +100,7 @@ func componentListener(event *events.ComponentInteractionCreate) { switch data.CustomID() { case "test4": if err := event.DeferUpdateMessage(); err != nil { - log.Errorf("error sending interaction response: %s", err) + slog.Error("error sending interaction response", slog.Any("err", err)) } _, _ = event.Client().Rest().CreateFollowupMessage(event.ApplicationID(), event.Token(), discord.NewMessageCreateBuilder(). SetEphemeral(true). @@ -121,7 +120,7 @@ func applicationCommandListener(event *events.ApplicationCommandInteractionCreat Build(), ) if err != nil { - event.Client().Logger().Error("error on sending response: ", err) + slog.Error("error on sending response", slog.Any("err", err)) } case "say": @@ -169,7 +168,7 @@ func autocompleteListener(event *events.AutocompleteInteractionCreate) { Value: 2, }, }); err != nil { - event.Client().Logger().Error("error on sending response: ", err) + slog.Error("error on sending response", slog.Any("err", err)) } } } @@ -199,7 +198,7 @@ func messageListener(event *events.GuildMessageCreate) { Build(), ) if err != nil { - event.Client().Logger().Error("error on sending response: ", err) + slog.Error("error on sending response", slog.Any("err", err)) } time.Sleep(1 * time.Second) _, err = event.Client().Rest().UpdateMessage(event.ChannelID, message.ID, discord.NewMessageUpdateBuilder(). @@ -208,7 +207,7 @@ func messageListener(event *events.GuildMessageCreate) { Build(), ) if err != nil { - event.Client().Logger().Error("error on updating response: ", err) + slog.Error("error on updating response", slog.Any("err", err)) } case "panic": @@ -227,7 +226,7 @@ func messageListener(event *events.GuildMessageCreate) { go func() { message, err := event.Client().Rest().CreateMessage(event.ChannelID, discord.NewMessageCreateBuilder().SetContent("test").Build()) if err != nil { - log.Errorf("error while sending file: %s", err) + slog.Error("error while sending file", slog.Any("err", err)) return } time.Sleep(time.Second * 2) diff --git a/_examples/threads/example.go b/_examples/threads/example.go index 94052318a..6db639aa3 100644 --- a/_examples/threads/example.go +++ b/_examples/threads/example.go @@ -2,12 +2,11 @@ package main import ( "context" + "log/slog" "os" "os/signal" "syscall" - "github.com/disgoorg/log" - "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/cache" @@ -19,10 +18,8 @@ import ( var token = os.Getenv("token") func main() { - log.SetFlags(log.LstdFlags | log.Lshortfile) - log.SetLevel(log.LevelInfo) - log.Info("starting example...") - log.Infof("bot version: %s", disgo.Version) + slog.Info("starting example...") + slog.Info("bot version", slog.String("version", disgo.Version)) client, err := disgo.New(token, bot.WithGatewayConfigOpts( @@ -36,45 +33,45 @@ func main() { OnMessageCreate: func(event *events.MessageCreate) { if channel, ok := event.Channel(); ok { if _, ok = channel.(discord.GuildThread); ok { - println("MessageCreateEvent") + slog.Info("MessageCreateEvent") } } }, OnThreadCreate: func(event *events.ThreadCreate) { - println("ThreadCreateEvent") + slog.Info("ThreadCreateEvent") }, OnThreadUpdate: func(event *events.ThreadUpdate) { - println("ThreadUpdateEvent") + slog.Info("ThreadUpdateEvent") }, OnThreadDelete: func(event *events.ThreadDelete) { - println("ThreadDeleteEvent") + slog.Info("ThreadDeleteEvent") }, OnThreadHide: func(event *events.ThreadHide) { - println("ThreadHideEvent") + slog.Info("ThreadHideEvent") }, OnThreadShow: func(event *events.ThreadShow) { - println("ThreadShowEvent") + slog.Info("ThreadShowEvent") }, OnThreadMemberAdd: func(event *events.ThreadMemberAdd) { - println("ThreadMemberAddEvent") + slog.Info("ThreadMemberAddEvent") }, OnThreadMemberUpdate: func(event *events.ThreadMemberUpdate) { - println("ThreadMemberUpdateEvent") + slog.Info("ThreadMemberUpdateEvent") }, OnThreadMemberRemove: func(event *events.ThreadMemberRemove) { - println("ThreadMemberRemoveEvent") + slog.Info("ThreadMemberRemoveEvent") }, }), ) if err != nil { - log.Fatal("error while building bot instance: ", err) + slog.Error("error while building bot instance", slog.Any("err", err)) return } defer client.Close(context.TODO()) if err = client.OpenGateway(context.TODO()); err != nil { - log.Fatal("error while connecting to discord: ", err) + slog.Error("error while connecting to discord", slog.Any("err", err)) } s := make(chan os.Signal, 1) diff --git a/_examples/verified_roles/main.go b/_examples/verified_roles/main.go index cd5096b2c..2fadbaa57 100644 --- a/_examples/verified_roles/main.go +++ b/_examples/verified_roles/main.go @@ -1,18 +1,17 @@ package main import ( + "log/slog" "math/rand" "net/http" "os" "strconv" - "github.com/disgoorg/json" - "github.com/disgoorg/log" - "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/oauth2" + "github.com/disgoorg/json" ) var ( @@ -25,14 +24,14 @@ var ( ) func main() { - log.SetLevel(log.LevelDebug) - log.Info("starting example...") - log.Infof("disgo %s", disgo.Version) + slog.Info("starting example...") + slog.Info("disgo version", slog.String("version", disgo.Version)) var err error client, err = disgo.New(token) if err != nil { - log.Panic(err) + slog.Error("error creating client", slog.Any("err", err)) + return } _, _ = client.Rest().UpdateApplicationRoleConnectionMetadata(client.ApplicationID(), []discord.ApplicationRoleConnectionMetadata{ diff --git a/_examples/voice/voice.go b/_examples/voice/voice.go index 6d316be74..90b71742a 100644 --- a/_examples/voice/voice.go +++ b/_examples/voice/voice.go @@ -4,21 +4,18 @@ import ( "context" "encoding/binary" "io" - _ "net/http/pprof" + "log/slog" "os" "os/signal" "syscall" "time" - "github.com/disgoorg/disgo/voice" - - "github.com/disgoorg/log" - "github.com/disgoorg/snowflake/v2" - "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/events" "github.com/disgoorg/disgo/gateway" + "github.com/disgoorg/disgo/voice" + "github.com/disgoorg/snowflake/v2" ) var ( @@ -28,9 +25,8 @@ var ( ) func main() { - log.SetLevel(log.LevelInfo) - log.SetFlags(log.LstdFlags | log.Llongfile) - log.Info("starting up") + slog.Info("starting up") + slog.Info("disgo version", slog.String("version", disgo.Version)) s := make(chan os.Signal, 1) @@ -41,7 +37,7 @@ func main() { }), ) if err != nil { - log.Fatal("error creating client: ", err) + slog.Error("error creating client", slog.Any("err", err)) } defer func() { @@ -51,10 +47,11 @@ func main() { }() if err = client.OpenGateway(context.TODO()); err != nil { - log.Fatal("error connecting to gateway: ", err) + slog.Error("error connecting to gateway", slog.Any("error", err)) + return } - log.Info("ExampleBot is now running. Press CTRL-C to exit.") + slog.Info("ExampleBot is now running. Press CTRL-C to exit.") signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-s } diff --git a/_examples/webhook/example.go b/_examples/webhook/example.go index 5720020a8..9cb1c3e5d 100644 --- a/_examples/webhook/example.go +++ b/_examples/webhook/example.go @@ -2,17 +2,16 @@ package main import ( "context" + "log/slog" "os" "sync" "time" - "github.com/disgoorg/log" - "github.com/disgoorg/snowflake/v2" - "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/rest" "github.com/disgoorg/disgo/webhook" + "github.com/disgoorg/snowflake/v2" ) var ( @@ -21,10 +20,8 @@ var ( ) func main() { - log.SetLevel(log.LevelDebug) - log.SetFlags(log.LstdFlags | log.Lshortfile) - log.Info("starting webhook example...") - log.Info("disgo version: ", disgo.Version) + slog.Info("starting webhook example...") + slog.Info("disgo version", slog.String("version", disgo.Version)) // construct new webhook client client := webhook.New(webhookID, webhookToken) @@ -41,7 +38,7 @@ func main() { // wait for all messages to be sent wg.Wait() - log.Info("exiting webhook example...") + slog.Info("exiting webhook example...") } // send(s) a message to the webhook @@ -54,6 +51,6 @@ func send(wg *sync.WaitGroup, client webhook.Client, i int) { // delay each request by 2 seconds rest.WithDelay(2*time.Second), ); err != nil { - log.Errorf("error sending message %d: %s", i, err) + slog.Error("error sending message to webhook", slog.Any("error", err), slog.Int("i", i)) } } diff --git a/bot/client.go b/bot/client.go index 3ef9a888d..82f90f422 100644 --- a/bot/client.go +++ b/bot/client.go @@ -2,9 +2,7 @@ package bot import ( "context" - - "github.com/disgoorg/log" - "github.com/disgoorg/snowflake/v2" + "log/slog" "github.com/disgoorg/disgo/cache" "github.com/disgoorg/disgo/discord" @@ -13,6 +11,7 @@ import ( "github.com/disgoorg/disgo/rest" "github.com/disgoorg/disgo/sharding" "github.com/disgoorg/disgo/voice" + "github.com/disgoorg/snowflake/v2" ) var _ Client = (*clientImpl)(nil) @@ -22,7 +21,7 @@ var _ Client = (*clientImpl)(nil) // Create a new client with disgo.New. type Client interface { // Logger returns the logger for the client. - Logger() log.Logger + Logger() *slog.Logger // Close will clean up all disgo internals and close the discord gracefully. Close(ctx context.Context) @@ -116,7 +115,7 @@ type clientImpl struct { token string applicationID snowflake.ID - logger log.Logger + logger *slog.Logger restServices rest.Rest @@ -134,7 +133,7 @@ type clientImpl struct { memberChunkingManager MemberChunkingManager } -func (c *clientImpl) Logger() log.Logger { +func (c *clientImpl) Logger() *slog.Logger { return c.logger } diff --git a/bot/config.go b/bot/config.go index 4108ccb4d..880f182d3 100644 --- a/bot/config.go +++ b/bot/config.go @@ -2,8 +2,7 @@ package bot import ( "fmt" - - "github.com/disgoorg/log" + "log/slog" "github.com/disgoorg/disgo/cache" "github.com/disgoorg/disgo/discord" @@ -18,7 +17,7 @@ import ( // DefaultConfig returns a Config with sensible defaults. func DefaultConfig(gatewayHandlers map[gateway.EventType]GatewayEventHandler, httpHandler HTTPServerEventHandler) *Config { return &Config{ - Logger: log.Default(), + Logger: slog.Default(), EventManagerConfigOpts: []EventManagerConfigOpt{WithGatewayHandlers(gatewayHandlers), WithHTTPServerHandler(httpHandler)}, MemberChunkingFilter: MemberChunkingFilterNone, } @@ -26,7 +25,7 @@ func DefaultConfig(gatewayHandlers map[gateway.EventType]GatewayEventHandler, ht // Config lets you configure your Client instance. type Config struct { - Logger log.Logger + Logger *slog.Logger RestClient rest.Client RestClientConfigOpts []rest.ConfigOpt @@ -65,8 +64,8 @@ func (c *Config) Apply(opts []ConfigOpt) { } } -// WithLogger lets you inject your own logger implementing log.Logger. -func WithLogger(logger log.Logger) ConfigOpt { +// WithLogger lets you inject your own logger implementing *slog.Logger. +func WithLogger(logger *slog.Logger) ConfigOpt { return func(config *Config) { config.Logger = logger } @@ -210,7 +209,7 @@ func WithMemberChunkingFilter(memberChunkingFilter MemberChunkingFilter) ConfigO } // BuildClient creates a new Client instance with the given token, Config, gateway handlers, http handlers os, name, github & version. -func BuildClient(token string, config Config, gatewayEventHandlerFunc func(client Client) gateway.EventHandlerFunc, httpServerEventHandlerFunc func(client Client) httpserver.EventHandlerFunc, os string, name string, github string, version string) (Client, error) { +func BuildClient(token string, cfg *Config, gatewayEventHandlerFunc func(client Client) gateway.EventHandlerFunc, httpServerEventHandlerFunc func(client Client) httpserver.EventHandlerFunc, os string, name string, github string, version string) (Client, error) { if token == "" { return nil, discord.ErrNoBotToken } @@ -220,62 +219,62 @@ func BuildClient(token string, config Config, gatewayEventHandlerFunc func(clien } client := &clientImpl{ token: token, - logger: config.Logger, + logger: cfg.Logger, } client.applicationID = *id - if config.RestClient == nil { + if cfg.RestClient == nil { // prepend standard user-agent. this can be overridden as it's appended to the front of the slice - config.RestClientConfigOpts = append([]rest.ConfigOpt{ + cfg.RestClientConfigOpts = append([]rest.ConfigOpt{ rest.WithUserAgent(fmt.Sprintf("DiscordBot (%s, %s)", github, version)), rest.WithLogger(client.logger), func(config *rest.Config) { - config.RateLimiterConfigOpts = append([]rest.RateLimiterConfigOpt{rest.WithRateLimiterLogger(client.logger)}, config.RateLimiterConfigOpts...) + config.RateLimiterConfigOpts = append([]rest.RateLimiterConfigOpt{rest.WithRateLimiterLogger(cfg.Logger)}, config.RateLimiterConfigOpts...) }, - }, config.RestClientConfigOpts...) + }, cfg.RestClientConfigOpts...) - config.RestClient = rest.NewClient(client.token, config.RestClientConfigOpts...) + cfg.RestClient = rest.NewClient(client.token, cfg.RestClientConfigOpts...) } - if config.Rest == nil { - config.Rest = rest.New(config.RestClient) + if cfg.Rest == nil { + cfg.Rest = rest.New(cfg.RestClient) } - client.restServices = config.Rest + client.restServices = cfg.Rest - if config.VoiceManager == nil { - config.VoiceManager = voice.NewManager(client.UpdateVoiceState, *id, append([]voice.ManagerConfigOpt{voice.WithLogger(client.logger)}, config.VoiceManagerConfigOpts...)...) + if cfg.VoiceManager == nil { + cfg.VoiceManager = voice.NewManager(client.UpdateVoiceState, *id, append([]voice.ManagerConfigOpt{voice.WithLogger(cfg.Logger)}, cfg.VoiceManagerConfigOpts...)...) } - client.voiceManager = config.VoiceManager + client.voiceManager = cfg.VoiceManager - if config.EventManager == nil { - config.EventManager = NewEventManager(client, config.EventManagerConfigOpts...) + if cfg.EventManager == nil { + cfg.EventManager = NewEventManager(client, append([]EventManagerConfigOpt{WithEventManagerLogger(cfg.Logger)}, cfg.EventManagerConfigOpts...)...) } - client.eventManager = config.EventManager + client.eventManager = cfg.EventManager - if config.Gateway == nil && len(config.GatewayConfigOpts) > 0 { + if cfg.Gateway == nil && len(cfg.GatewayConfigOpts) > 0 { var gatewayRs *discord.Gateway gatewayRs, err = client.restServices.GetGateway() if err != nil { return nil, err } - config.GatewayConfigOpts = append([]gateway.ConfigOpt{ + cfg.GatewayConfigOpts = append([]gateway.ConfigOpt{ gateway.WithURL(gatewayRs.URL), - gateway.WithLogger(client.logger), + gateway.WithLogger(cfg.Logger), gateway.WithOS(os), gateway.WithBrowser(name), gateway.WithDevice(name), func(config *gateway.Config) { - config.RateLimiterConfigOpts = append([]gateway.RateLimiterConfigOpt{gateway.WithRateLimiterLogger(client.logger)}, config.RateLimiterConfigOpts...) + config.RateLimiterConfigOpts = append([]gateway.RateLimiterConfigOpt{gateway.WithRateLimiterLogger(cfg.Logger)}, config.RateLimiterConfigOpts...) }, - }, config.GatewayConfigOpts...) + }, cfg.GatewayConfigOpts...) - config.Gateway = gateway.New(token, gatewayEventHandlerFunc(client), nil, config.GatewayConfigOpts...) + cfg.Gateway = gateway.New(token, gatewayEventHandlerFunc(client), nil, cfg.GatewayConfigOpts...) } - client.gateway = config.Gateway + client.gateway = cfg.Gateway - if config.ShardManager == nil && len(config.ShardManagerConfigOpts) > 0 { + if cfg.ShardManager == nil && len(cfg.ShardManagerConfigOpts) > 0 { var gatewayBotRs *discord.GatewayBot gatewayBotRs, err = client.restServices.GetGatewayBot() if err != nil { @@ -287,47 +286,47 @@ func BuildClient(token string, config Config, gatewayEventHandlerFunc func(clien shardIDs[i] = i } - config.ShardManagerConfigOpts = append([]sharding.ConfigOpt{ + cfg.ShardManagerConfigOpts = append([]sharding.ConfigOpt{ sharding.WithShardCount(gatewayBotRs.Shards), sharding.WithShardIDs(shardIDs...), sharding.WithGatewayConfigOpts( gateway.WithURL(gatewayBotRs.URL), - gateway.WithLogger(client.logger), + gateway.WithLogger(cfg.Logger), gateway.WithOS(os), gateway.WithBrowser(name), gateway.WithDevice(name), func(config *gateway.Config) { - config.RateLimiterConfigOpts = append([]gateway.RateLimiterConfigOpt{gateway.WithRateLimiterLogger(client.logger)}, config.RateLimiterConfigOpts...) + config.RateLimiterConfigOpts = append([]gateway.RateLimiterConfigOpt{gateway.WithRateLimiterLogger(cfg.Logger)}, config.RateLimiterConfigOpts...) }, ), - sharding.WithLogger(client.logger), + sharding.WithLogger(cfg.Logger), func(config *sharding.Config) { - config.RateLimiterConfigOpts = append([]sharding.RateLimiterConfigOpt{sharding.WithRateLimiterLogger(client.logger), sharding.WithMaxConcurrency(gatewayBotRs.SessionStartLimit.MaxConcurrency)}, config.RateLimiterConfigOpts...) + config.RateLimiterConfigOpts = append([]sharding.RateLimiterConfigOpt{sharding.WithRateLimiterLogger(cfg.Logger), sharding.WithMaxConcurrency(gatewayBotRs.SessionStartLimit.MaxConcurrency)}, config.RateLimiterConfigOpts...) }, - }, config.ShardManagerConfigOpts...) + }, cfg.ShardManagerConfigOpts...) - config.ShardManager = sharding.New(token, gatewayEventHandlerFunc(client), config.ShardManagerConfigOpts...) + cfg.ShardManager = sharding.New(token, gatewayEventHandlerFunc(client), cfg.ShardManagerConfigOpts...) } - client.shardManager = config.ShardManager + client.shardManager = cfg.ShardManager - if config.HTTPServer == nil && config.PublicKey != "" { - config.HTTPServerConfigOpts = append([]httpserver.ConfigOpt{ - httpserver.WithLogger(client.logger), - }, config.HTTPServerConfigOpts...) + if cfg.HTTPServer == nil && cfg.PublicKey != "" { + cfg.HTTPServerConfigOpts = append([]httpserver.ConfigOpt{ + httpserver.WithLogger(cfg.Logger), + }, cfg.HTTPServerConfigOpts...) - config.HTTPServer = httpserver.New(config.PublicKey, httpServerEventHandlerFunc(client), config.HTTPServerConfigOpts...) + cfg.HTTPServer = httpserver.New(cfg.PublicKey, httpServerEventHandlerFunc(client), cfg.HTTPServerConfigOpts...) } - client.httpServer = config.HTTPServer + client.httpServer = cfg.HTTPServer - if config.MemberChunkingManager == nil { - config.MemberChunkingManager = NewMemberChunkingManager(client, config.Logger, config.MemberChunkingFilter) + if cfg.MemberChunkingManager == nil { + cfg.MemberChunkingManager = NewMemberChunkingManager(client, cfg.Logger, cfg.MemberChunkingFilter) } - client.memberChunkingManager = config.MemberChunkingManager + client.memberChunkingManager = cfg.MemberChunkingManager - if config.Caches == nil { - config.Caches = cache.New(config.CacheConfigOpts...) + if cfg.Caches == nil { + cfg.Caches = cache.New(cfg.CacheConfigOpts...) } - client.caches = config.Caches + client.caches = cfg.Caches return client, nil } diff --git a/bot/event_manager.go b/bot/event_manager.go index 84565fed3..7083ae864 100644 --- a/bot/event_manager.go +++ b/bot/event_manager.go @@ -1,6 +1,7 @@ package bot import ( + "log/slog" "runtime/debug" "sync" @@ -12,12 +13,17 @@ var _ EventManager = (*eventManagerImpl)(nil) // NewEventManager returns a new EventManager with the EventManagerConfigOpt(s) applied. func NewEventManager(client Client, opts ...EventManagerConfigOpt) EventManager { - config := DefaultEventManagerConfig() - config.Apply(opts) + cfg := DefaultEventManagerConfig() + cfg.Apply(opts) + cfg.Logger = cfg.Logger.With(slog.String("name", "bot_event_manager")) return &eventManagerImpl{ - client: client, - config: *config, + client: client, + logger: cfg.Logger, + eventListeners: cfg.EventListeners, + asyncEventsEnabled: cfg.AsyncEventsEnabled, + gatewayHandlers: cfg.GatewayHandlers, + httpServerHandler: cfg.HTTPServerHandler, } } @@ -112,68 +118,72 @@ type HTTPServerEventHandler interface { } type eventManagerImpl struct { - client Client - eventListenerMu sync.Mutex - config EventManagerConfig - mu sync.Mutex + + client Client + logger *slog.Logger + eventListenerMu sync.Mutex + eventListeners []EventListener + asyncEventsEnabled bool + gatewayHandlers map[gateway.EventType]GatewayEventHandler + httpServerHandler HTTPServerEventHandler } func (e *eventManagerImpl) HandleGatewayEvent(gatewayEventType gateway.EventType, sequenceNumber int, shardID int, event gateway.EventData) { e.mu.Lock() defer e.mu.Unlock() - if handler, ok := e.config.GatewayHandlers[gatewayEventType]; ok { + if handler, ok := e.gatewayHandlers[gatewayEventType]; ok { handler.HandleGatewayEvent(e.client, sequenceNumber, shardID, event) } else { - e.config.Logger.Warnf("no handler for gateway event '%s' found", gatewayEventType) + e.logger.Warn("no handler for gateway event found", slog.Any("event_type", gatewayEventType)) } } func (e *eventManagerImpl) HandleHTTPEvent(respondFunc httpserver.RespondFunc, event httpserver.EventInteractionCreate) { e.mu.Lock() defer e.mu.Unlock() - e.config.HTTPServerHandler.HandleHTTPEvent(e.client, respondFunc, event) + e.httpServerHandler.HandleHTTPEvent(e.client, respondFunc, event) } func (e *eventManagerImpl) DispatchEvent(event Event) { defer func() { if r := recover(); r != nil { - e.config.Logger.Errorf("recovered from panic in event listener: %+v\nstack: %s", r, string(debug.Stack())) + e.logger.Error("recovered from panic in event listener", slog.Any("arg", r), slog.String("stack", string(debug.Stack()))) return } }() e.eventListenerMu.Lock() defer e.eventListenerMu.Unlock() - for i := range e.config.EventListeners { - if e.config.AsyncEventsEnabled { + for i := range e.eventListeners { + if e.asyncEventsEnabled { go func(i int) { defer func() { if r := recover(); r != nil { - e.config.Logger.Errorf("recovered from panic in event listener: %+v\nstack: %s", r, string(debug.Stack())) + e.logger.Error("recovered from panic in event listener", slog.Any("arg", r), slog.String("stack", string(debug.Stack()))) return } }() - e.config.EventListeners[i].OnEvent(event) + e.eventListeners[i].OnEvent(event) }(i) continue } - e.config.EventListeners[i].OnEvent(event) + e.eventListeners[i].OnEvent(event) } } func (e *eventManagerImpl) AddEventListeners(listeners ...EventListener) { e.eventListenerMu.Lock() defer e.eventListenerMu.Unlock() - e.config.EventListeners = append(e.config.EventListeners, listeners...) + e.eventListeners = append(e.eventListeners, listeners...) } func (e *eventManagerImpl) RemoveEventListeners(listeners ...EventListener) { e.eventListenerMu.Lock() defer e.eventListenerMu.Unlock() for _, listener := range listeners { - for i, l := range e.config.EventListeners { + for i, l := range e.eventListeners { if l == listener { - e.config.EventListeners = append(e.config.EventListeners[:i], e.config.EventListeners[i+1:]...) + e.eventListeners = append(e.eventListeners[:i], e.eventListeners[i+1:]...) break } } diff --git a/bot/event_manager_config.go b/bot/event_manager_config.go index e62e72d41..2bf40d427 100644 --- a/bot/event_manager_config.go +++ b/bot/event_manager_config.go @@ -1,7 +1,7 @@ package bot import ( - "github.com/disgoorg/log" + "log/slog" "github.com/disgoorg/disgo/gateway" ) @@ -9,13 +9,13 @@ import ( // DefaultEventManagerConfig returns a new EventManagerConfig with all default values. func DefaultEventManagerConfig() *EventManagerConfig { return &EventManagerConfig{ - Logger: log.Default(), + Logger: slog.Default(), } } // EventManagerConfig can be used to configure the EventManager. type EventManagerConfig struct { - Logger log.Logger + Logger *slog.Logger EventListeners []EventListener AsyncEventsEnabled bool @@ -34,7 +34,7 @@ func (c *EventManagerConfig) Apply(opts []EventManagerConfigOpt) { } // WithEventManagerLogger overrides the default logger in the EventManagerConfig. -func WithEventManagerLogger(logger log.Logger) EventManagerConfigOpt { +func WithEventManagerLogger(logger *slog.Logger) EventManagerConfigOpt { return func(config *EventManagerConfig) { config.Logger = logger } diff --git a/bot/member_chunking_filter.go b/bot/member_chunking_filter.go index 2216efb61..6a2348b73 100644 --- a/bot/member_chunking_filter.go +++ b/bot/member_chunking_filter.go @@ -1,8 +1,9 @@ package bot import ( + "slices" + "github.com/disgoorg/snowflake/v2" - "golang.org/x/exp/slices" ) // MemberChunkingFilterAll is a MemberChunkingFilter which includes all guilds. diff --git a/bot/member_chunking_manager.go b/bot/member_chunking_manager.go index 283110000..3e089de41 100644 --- a/bot/member_chunking_manager.go +++ b/bot/member_chunking_manager.go @@ -2,9 +2,9 @@ package bot import ( "context" + "log/slog" "sync" - "github.com/disgoorg/log" "github.com/disgoorg/snowflake/v2" "github.com/disgoorg/disgo/discord" @@ -15,13 +15,15 @@ import ( var _ MemberChunkingManager = (*memberChunkingManagerImpl)(nil) // NewMemberChunkingManager returns a new MemberChunkingManager with the given MemberChunkingFilter. -func NewMemberChunkingManager(client Client, logger log.Logger, memberChunkingFilter MemberChunkingFilter) MemberChunkingManager { +func NewMemberChunkingManager(client Client, logger *slog.Logger, memberChunkingFilter MemberChunkingFilter) MemberChunkingManager { if memberChunkingFilter == nil { memberChunkingFilter = MemberChunkingFilterNone } if logger == nil { - logger = log.Default() + logger = slog.Default() } + logger = logger.With(slog.String("name", "bot_member_chunking_manager")) + return &memberChunkingManagerImpl{ client: client, logger: logger, @@ -88,7 +90,7 @@ type chunkingRequest struct { type memberChunkingManagerImpl struct { client Client - logger log.Logger + logger *slog.Logger memberChunkingFilter MemberChunkingFilter chunkingRequestsMu sync.RWMutex @@ -104,7 +106,7 @@ func (m *memberChunkingManagerImpl) HandleChunk(payload gateway.EventGuildMember request, ok := m.chunkingRequests[payload.Nonce] m.chunkingRequestsMu.RUnlock() if !ok { - m.logger.Debug("received unknown member chunk event: ", payload) + m.logger.Debug("received unknown member chunk event: ", slog.Any("payload", payload)) return } diff --git a/cache/cache_policy.go b/cache/cache_policy.go index 195024f17..a54e0587f 100644 --- a/cache/cache_policy.go +++ b/cache/cache_policy.go @@ -1,10 +1,10 @@ package cache import ( - "github.com/disgoorg/snowflake/v2" - "golang.org/x/exp/slices" + "slices" "github.com/disgoorg/disgo/discord" + "github.com/disgoorg/snowflake/v2" ) // PolicyNone returns a policy that will never cache anything. diff --git a/disgo.go b/disgo.go index ec05f01ae..02818c932 100644 --- a/disgo.go +++ b/disgo.go @@ -100,7 +100,7 @@ func New(token string, opts ...bot.ConfigOpt) (bot.Client, error) { config.Apply(opts) return bot.BuildClient(token, - *config, + config, handlers.DefaultGatewayEventHandlerFunc, handlers.DefaultHTTPServerEventHandlerFunc, OS, diff --git a/events/listener_adapter.go b/events/listener_adapter.go index 79a73edbb..9f38bc815 100644 --- a/events/listener_adapter.go +++ b/events/listener_adapter.go @@ -1,6 +1,9 @@ package events import ( + "fmt" + "log/slog" + "github.com/disgoorg/disgo/bot" ) @@ -666,6 +669,6 @@ func (l *ListenerAdapter) OnEvent(event bot.Event) { } default: - e.Client().Logger().Errorf("unexpected event received: '%T', event: '%+v'", event, event) + e.Client().Logger().Error("unexpected event received", slog.String("type", fmt.Sprintf("%T", event)), slog.String("data", fmt.Sprintf("%+v", event))) } } diff --git a/gateway/gateway_config.go b/gateway/gateway_config.go index 26d17df68..6177652db 100644 --- a/gateway/gateway_config.go +++ b/gateway/gateway_config.go @@ -1,14 +1,15 @@ package gateway import ( - "github.com/disgoorg/log" + "log/slog" + "github.com/gorilla/websocket" ) // DefaultConfig returns a Config with sensible defaults. func DefaultConfig() *Config { return &Config{ - Logger: log.Default(), + Logger: slog.Default(), Dialer: websocket.DefaultDialer, LargeThreshold: 50, Intents: IntentsDefault, @@ -23,8 +24,8 @@ func DefaultConfig() *Config { // Config lets you configure your Gateway instance. type Config struct { - // Logger is the logger of the Gateway. Defaults to log.Default(). - Logger log.Logger + // Logger is the Logger of the Gateway. Defaults to slog.Default(). + Logger *slog.Logger // Dialer is the websocket.Dialer of the Gateway. Defaults to websocket.DefaultDialer. Dialer *websocket.Dialer // LargeThreshold is the threshold for the Gateway. Defaults to 50 @@ -80,7 +81,7 @@ func (c *Config) Apply(opts []ConfigOpt) { } // WithLogger sets the Logger for the Gateway. -func WithLogger(logger log.Logger) ConfigOpt { +func WithLogger(logger *slog.Logger) ConfigOpt { return func(config *Config) { config.Logger = logger } diff --git a/gateway/gateway_impl.go b/gateway/gateway_impl.go index d6a0d09a7..f644bf880 100644 --- a/gateway/gateway_impl.go +++ b/gateway/gateway_impl.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "io" + "log/slog" "net" "sync" "syscall" @@ -24,6 +25,7 @@ var _ Gateway = (*gatewayImpl)(nil) func New(token string, eventHandlerFunc EventHandlerFunc, closeHandlerFunc CloseHandlerFunc, opts ...ConfigOpt) Gateway { config := DefaultConfig() config.Apply(opts) + config.Logger = config.Logger.With(slog.String("name", "gateway"), slog.Int("shard_id", config.ShardID), slog.Int("shard_count", config.ShardCount)) return &gatewayImpl{ config: *config, @@ -70,26 +72,12 @@ func (g *gatewayImpl) Intents() Intents { return g.config.Intents } -func (g *gatewayImpl) formatLogsf(format string, a ...any) string { - if g.config.ShardCount > 1 { - return fmt.Sprintf("[%d/%d] %s", g.config.ShardID, g.config.ShardCount, fmt.Sprintf(format, a...)) - } - return fmt.Sprintf(format, a...) -} - -func (g *gatewayImpl) formatLogs(a ...any) string { - if g.config.ShardCount > 1 { - return fmt.Sprintf("[%d/%d] %s", g.config.ShardID, g.config.ShardCount, fmt.Sprint(a...)) - } - return fmt.Sprint(a...) -} - func (g *gatewayImpl) Open(ctx context.Context) error { return g.reconnectTry(ctx, 0) } func (g *gatewayImpl) open(ctx context.Context) error { - g.config.Logger.Debug(g.formatLogs("opening gateway connection")) + g.config.Logger.Debug("opening gateway connection") g.connMu.Lock() defer g.connMu.Unlock() @@ -114,12 +102,12 @@ func (g *gatewayImpl) open(ctx context.Context) error { }() rawBody, bErr := io.ReadAll(rs.Body) if bErr != nil { - g.config.Logger.Error(g.formatLogs("error while reading response body: ", err)) + g.config.Logger.Error("error while reading response body", slog.String("err", bErr.Error())) } body = string(rawBody) } - g.config.Logger.Error(g.formatLogsf("error connecting to the gateway. url: %s, error: %s, body: %s", gatewayURL, err, body)) + g.config.Logger.Error("error connecting to the gateway", slog.String("err", err.Error()), slog.String("url", gatewayURL), slog.String("body", body)) return err } @@ -145,7 +133,7 @@ func (g *gatewayImpl) Close(ctx context.Context) { func (g *gatewayImpl) CloseWithCode(ctx context.Context, code int, message string) { if g.heartbeatChan != nil { - g.config.Logger.Debug(g.formatLogs("closing heartbeat goroutines...")) + g.config.Logger.Debug("closing heartbeat goroutines...") g.heartbeatChan <- struct{}{} } @@ -153,9 +141,9 @@ func (g *gatewayImpl) CloseWithCode(ctx context.Context, code int, message strin defer g.connMu.Unlock() if g.conn != nil { g.config.RateLimiter.Close(ctx) - g.config.Logger.Debug(g.formatLogsf("closing gateway connection with code: %d, message: %s", code, message)) + g.config.Logger.Debug("closing gateway connection", slog.Int("code", code), slog.String("message", message)) if err := g.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(code, message)); err != nil && !errors.Is(err, websocket.ErrCloseSent) { - g.config.Logger.Debug(g.formatLogs("error writing close code. error: ", err)) + g.config.Logger.Debug("error writing close code", slog.String("err", err.Error())) } _ = g.conn.Close() g.conn = nil @@ -198,7 +186,9 @@ func (g *gatewayImpl) send(ctx context.Context, messageType int, data []byte) er } defer g.config.RateLimiter.Unlock() - g.config.Logger.Trace(g.formatLogs("sending gateway command: ", string(data))) + if g.config.Logger.Enabled(ctx, slog.LevelDebug) { + g.config.Logger.Debug("sending gateway command", slog.String("data", string(data))) + } return g.conn.WriteMessage(messageType, data) } @@ -229,7 +219,7 @@ func (g *gatewayImpl) reconnectTry(ctx context.Context, try int) error { if errors.Is(err, discord.ErrGatewayAlreadyConnected) { return err } - g.config.Logger.Error(g.formatLogs("failed to reconnect gateway. error: ", err)) + g.config.Logger.Error("failed to reconnect gateway", slog.String("err", err.Error())) g.status = StatusDisconnected return g.reconnectTry(ctx, try+1) } @@ -239,7 +229,7 @@ func (g *gatewayImpl) reconnectTry(ctx context.Context, try int) error { func (g *gatewayImpl) reconnect() { err := g.reconnectTry(context.Background(), 0) if err != nil { - g.config.Logger.Error(g.formatLogs("failed to reopen gateway. error: ", err)) + g.config.Logger.Error("failed to reopen gateway", slog.String("err", err.Error())) } } @@ -249,7 +239,7 @@ func (g *gatewayImpl) heartbeat() { } heartbeatTicker := time.NewTicker(g.heartbeatInterval) defer heartbeatTicker.Stop() - defer g.config.Logger.Debug(g.formatLogs("exiting heartbeat goroutine...")) + defer g.config.Logger.Debug("exiting heartbeat goroutine") for { select { @@ -263,7 +253,7 @@ func (g *gatewayImpl) heartbeat() { } func (g *gatewayImpl) sendHeartbeat() { - g.config.Logger.Debug(g.formatLogs("sending heartbeat...")) + g.config.Logger.Debug("sending heartbeat") ctx, cancel := context.WithTimeout(context.Background(), g.heartbeatInterval) defer cancel() @@ -271,8 +261,10 @@ func (g *gatewayImpl) sendHeartbeat() { if errors.Is(err, discord.ErrShardNotConnected) || errors.Is(err, syscall.EPIPE) { return } - g.config.Logger.Error(g.formatLogs("failed to send heartbeat. error: ", err)) - g.CloseWithCode(context.TODO(), websocket.CloseServiceRestart, "heartbeat timeout") + g.config.Logger.Error("failed to send heartbeat", slog.String("err", err.Error())) + closeCtx, closeCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer closeCancel() + g.CloseWithCode(closeCtx, websocket.CloseServiceRestart, "heartbeat timeout") go g.reconnect() return } @@ -281,7 +273,7 @@ func (g *gatewayImpl) sendHeartbeat() { func (g *gatewayImpl) identify() { g.status = StatusIdentifying - g.config.Logger.Debug(g.formatLogs("sending Identify command...")) + g.config.Logger.Debug("sending Identify command") identify := MessageDataIdentify{ Token: g.token, @@ -297,8 +289,10 @@ func (g *gatewayImpl) identify() { Shard: &[2]int{g.ShardID(), g.ShardCount()}, } - if err := g.Send(context.TODO(), OpcodeIdentify, identify); err != nil { - g.config.Logger.Error(g.formatLogs("error sending Identify command err: ", err)) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + if err := g.Send(ctx, OpcodeIdentify, identify); err != nil { + g.config.Logger.Error("error sending Identify command", slog.String("err", err.Error())) } g.status = StatusWaitingForReady } @@ -310,18 +304,20 @@ func (g *gatewayImpl) resume() { SessionID: *g.config.SessionID, Seq: *g.config.LastSequenceReceived, } + g.config.Logger.Debug("sending Resume command") - g.config.Logger.Debug(g.formatLogs("sending Resume command...")) - if err := g.Send(context.TODO(), OpcodeResume, resume); err != nil { - g.config.Logger.Error(g.formatLogs("error sending resume command err: ", err)) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + if err := g.Send(ctx, OpcodeResume, resume); err != nil { + g.config.Logger.Error("error sending resume command", slog.String("err", err.Error())) } } func (g *gatewayImpl) listen(conn *websocket.Conn) { - defer g.config.Logger.Debug(g.formatLogs("exiting listen goroutine...")) + defer g.config.Logger.Debug("exiting listen goroutine") loop: for { - mt, data, err := conn.ReadMessage() + mt, r, err := conn.NextReader() if err != nil { g.connMu.Lock() sameConnection := g.conn == conn @@ -343,17 +339,22 @@ loop: g.config.SessionID = nil g.config.ResumeURL = nil } - message := g.formatLogsf("gateway close received, reconnect: %t, code: %d, error: %s", g.config.AutoReconnect && reconnect, closeError.Code, closeError.Text) + msg := "gateway close received" + args := []any{ + slog.Bool("reconnect", reconnect), + slog.Int("code", closeError.Code), + slog.String("error", closeError.Text), + } if reconnect { - g.config.Logger.Debug(message) + g.config.Logger.Debug(msg, args...) } else { - g.config.Logger.Error(message) + g.config.Logger.Error(msg, args...) } } else if errors.Is(err, net.ErrClosed) { // we closed the connection ourselves. Don't try to reconnect here reconnect = false } else { - g.config.Logger.Debug(g.formatLogs("failed to read next message from gateway. error: ", err)) + g.config.Logger.Debug("failed to read next message from gateway", slog.String("err", err.Error())) } // make sure the connection is properly closed @@ -369,9 +370,9 @@ loop: break loop } - message, err := g.parseMessage(mt, data) + message, err := g.parseMessage(mt, r) if err != nil { - g.config.Logger.Error(g.formatLogs("error while parsing gateway message. error: ", err)) + g.config.Logger.Error("error while parsing gateway message", slog.String("err", err.Error())) continue } @@ -393,7 +394,7 @@ loop: eventData, ok := message.D.(EventData) if !ok && message.D != nil { - g.config.Logger.Error(g.formatLogsf("invalid message data of type %T received", message.D)) + g.config.Logger.Error("invalid message data received", slog.String("data", fmt.Sprintf("%T", message.D))) continue } @@ -402,11 +403,11 @@ loop: g.config.SessionID = &readyEvent.SessionID g.config.ResumeURL = &readyEvent.ResumeGatewayURL g.status = StatusReady - g.config.Logger.Debug(g.formatLogs("ready message received")) + g.config.Logger.Debug("ready message received") } if unknownEvent, ok := eventData.(EventUnknown); ok { - g.config.Logger.Debug(g.formatLogsf("unknown event received: %s, data: %s", message.T, unknownEvent)) + g.config.Logger.Debug("unknown event received", slog.String("event", string(message.T)), slog.String("data", string(unknownEvent))) continue } @@ -457,31 +458,35 @@ loop: g.lastHeartbeatReceived = newHeartbeat default: - g.config.Logger.Debug(g.formatLogsf("unknown opcode received: %d, data: %s", message.Op, message.D)) + + g.config.Logger.Debug("unknown opcode received", slog.Int("opcode", int(message.Op)), slog.String("data", fmt.Sprintf("%s", message.D))) } } } -func (g *gatewayImpl) parseMessage(mt int, data []byte) (Message, error) { - var finalData []byte +func (g *gatewayImpl) parseMessage(mt int, r io.Reader) (Message, error) { if mt == websocket.BinaryMessage { - g.config.Logger.Trace(g.formatLogs("binary message received. decompressing...")) + g.config.Logger.Debug("binary message received. decompressing") - reader, err := zlib.NewReader(bytes.NewReader(data)) + reader, err := zlib.NewReader(r) if err != nil { return Message{}, fmt.Errorf("failed to decompress zlib: %w", err) } defer reader.Close() - finalData, err = io.ReadAll(reader) + r = reader + } + + if g.config.Logger.Enabled(context.Background(), slog.LevelDebug) { + buff := new(bytes.Buffer) + tr := io.TeeReader(r, buff) + data, err := io.ReadAll(tr) if err != nil { - return Message{}, fmt.Errorf("failed to read decompressed data: %w", err) + return Message{}, fmt.Errorf("failed to read message: %w", err) } - } else { - finalData = data + g.config.Logger.Debug("received gateway message", slog.String("data", string(data))) + r = buff } - g.config.Logger.Trace(g.formatLogs("received gateway message: ", string(finalData))) - var message Message - return message, json.Unmarshal(finalData, &message) + return message, json.NewDecoder(r).Decode(&message) } diff --git a/gateway/gateway_rate_limiter.go b/gateway/gateway_rate_limiter.go index 027ec7b0e..b8349ef52 100644 --- a/gateway/gateway_rate_limiter.go +++ b/gateway/gateway_rate_limiter.go @@ -4,6 +4,9 @@ import ( "context" ) +// CommandsPerMinute is the default number of commands per minute that the Gateway will allow. +const CommandsPerMinute = 120 + // RateLimiter provides handles the rate limiting logic for connecting to Discord's Gateway. type RateLimiter interface { // Close gracefully closes the RateLimiter. diff --git a/gateway/gateway_rate_limiter_config.go b/gateway/gateway_rate_limiter_config.go index 0f2afa005..fa5ff8d9c 100644 --- a/gateway/gateway_rate_limiter_config.go +++ b/gateway/gateway_rate_limiter_config.go @@ -1,20 +1,20 @@ package gateway import ( - "github.com/disgoorg/log" + "log/slog" ) // DefaultRateLimiterConfig returns a RateLimiterConfig with sensible defaults. func DefaultRateLimiterConfig() *RateLimiterConfig { return &RateLimiterConfig{ - Logger: log.Default(), - CommandsPerMinute: 120, + Logger: slog.Default(), + CommandsPerMinute: CommandsPerMinute, } } // RateLimiterConfig lets you configure your Gateway instance. type RateLimiterConfig struct { - Logger log.Logger + Logger *slog.Logger CommandsPerMinute int } @@ -29,7 +29,7 @@ func (c *RateLimiterConfig) Apply(opts []RateLimiterConfigOpt) { } // WithRateLimiterLogger sets the Logger for the Gateway. -func WithRateLimiterLogger(logger log.Logger) RateLimiterConfigOpt { +func WithRateLimiterLogger(logger *slog.Logger) RateLimiterConfigOpt { return func(config *RateLimiterConfig) { config.Logger = logger } diff --git a/gateway/gateway_rate_limiter_impl.go b/gateway/gateway_rate_limiter_impl.go index 372d70776..defca34f1 100644 --- a/gateway/gateway_rate_limiter_impl.go +++ b/gateway/gateway_rate_limiter_impl.go @@ -2,6 +2,7 @@ package gateway import ( "context" + "log/slog" "time" "github.com/sasha-s/go-csync" @@ -11,6 +12,7 @@ import ( func NewRateLimiter(opts ...RateLimiterConfigOpt) RateLimiter { config := DefaultRateLimiterConfig() config.Apply(opts) + config.Logger = config.Logger.With(slog.String("name", "gateway_rate_limiter")) return &rateLimiterImpl{ config: *config, @@ -37,7 +39,7 @@ func (l *rateLimiterImpl) Reset() { } func (l *rateLimiterImpl) Wait(ctx context.Context) error { - l.config.Logger.Trace("locking gateway rate limiter") + l.config.Logger.Debug("locking gateway rate limiter") if err := l.mu.CLock(ctx); err != nil { return err } @@ -62,7 +64,7 @@ func (l *rateLimiterImpl) Wait(ctx context.Context) error { } func (l *rateLimiterImpl) Unlock() { - l.config.Logger.Trace("unlocking gateway rate limiter") + l.config.Logger.Debug("unlocking gateway rate limiter") now := time.Now() if l.reset.Before(now) { l.reset = now.Add(time.Minute) diff --git a/go.mod b/go.mod index 2517f4d80..a647df749 100644 --- a/go.mod +++ b/go.mod @@ -1,16 +1,14 @@ module github.com/disgoorg/disgo -go 1.18 +go 1.21 require ( github.com/disgoorg/json v1.1.0 - github.com/disgoorg/log v1.2.1 github.com/disgoorg/snowflake/v2 v2.0.1 github.com/gorilla/websocket v1.5.0 github.com/sasha-s/go-csync v0.0.0-20210812194225-61421b77c44b - github.com/stretchr/testify v1.8.1 + github.com/stretchr/testify v1.8.4 golang.org/x/crypto v0.12.0 - golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b ) require ( diff --git a/go.sum b/go.sum index 5f0f4570e..f0a275d67 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,7 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/disgoorg/json v1.1.0 h1:7xigHvomlVA9PQw9bMGO02PHGJJPqvX5AnwlYg/Tnys= github.com/disgoorg/json v1.1.0/go.mod h1:BHDwdde0rpQFDVsRLKhma6Y7fTbQKub/zdGO5O9NqqA= -github.com/disgoorg/log v1.2.1 h1:kZYAWkUBcGy4LbZcgYtgYu49xNVLy+xG5Uq3yz5VVQs= -github.com/disgoorg/log v1.2.1/go.mod h1:hhQWYTFTnIGzAuFPZyXJEi11IBm9wq+/TVZt/FEwX0o= github.com/disgoorg/snowflake/v2 v2.0.1 h1:CuUxGLwggUxEswZOmZ+mZ5i0xSumQdXW9tXW7uGqe+0= github.com/disgoorg/snowflake/v2 v2.0.1/go.mod h1:SPU9c2CNn5DSyb86QcKtdZgix9osEtKrHLW4rMhfLCs= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= @@ -13,21 +10,13 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sasha-s/go-csync v0.0.0-20210812194225-61421b77c44b h1:qYTY2tN72LhgDj2rtWG+LI6TXFl2ygFQQ4YezfVaGQE= github.com/sasha-s/go-csync v0.0.0-20210812194225-61421b77c44b/go.mod h1:/pA7k3zsXKdjjAiUhB5CjuKib9KJGCaLvZwtxGC8U0s= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b h1:r+vk0EmXNmekl0S0BascoeeoHk/L7wmaW2QF90K+kYI= -golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/handler/middleware/go.go b/handler/middleware/go.go index c67ed1654..6f6041bb5 100644 --- a/handler/middleware/go.go +++ b/handler/middleware/go.go @@ -1,6 +1,8 @@ package middleware import ( + "log/slog" + "github.com/disgoorg/disgo/events" "github.com/disgoorg/disgo/handler" ) @@ -10,7 +12,7 @@ var Go handler.Middleware = func(next handler.Handler) handler.Handler { return func(e *events.InteractionCreate) error { go func() { if err := next(e); err != nil { - e.Client().Logger().Errorf("failed to handle interaction: %s\n", err) + e.Client().Logger().Error("failed to handle interaction", slog.String("err", err.Error())) } }() return nil diff --git a/handler/middleware/logger.go b/handler/middleware/logger.go index 2e9f1dea9..8c5095993 100644 --- a/handler/middleware/logger.go +++ b/handler/middleware/logger.go @@ -1,13 +1,15 @@ package middleware import ( + "log/slog" + "github.com/disgoorg/disgo/events" "github.com/disgoorg/disgo/handler" ) var Logger handler.Middleware = func(next handler.Handler) handler.Handler { return func(e *events.InteractionCreate) error { - e.Client().Logger().Infof("handling interaction: %s\n", e.Interaction.ID()) + e.Client().Logger().Info("handling interaction", slog.Int64("interaction_id", int64(e.Interaction.ID()))) return next(e) } } diff --git a/handler/mux.go b/handler/mux.go index 5577598f6..4dba1c25c 100644 --- a/handler/mux.go +++ b/handler/mux.go @@ -1,6 +1,7 @@ package handler import ( + "log/slog" "strings" "github.com/disgoorg/disgo/bot" @@ -9,7 +10,7 @@ import ( ) var defaultErrorHandler = func(e *events.InteractionCreate, err error) { - e.Client().Logger().Errorf("error handling interaction: %v\n", err) + e.Client().Logger().Error("error handling interaction", slog.String("err", err.Error())) } // New returns a new Router. diff --git a/handlers/guild_emojis_update_handler.go b/handlers/guild_emojis_update_handler.go index a3477097a..b1b608335 100644 --- a/handlers/guild_emojis_update_handler.go +++ b/handlers/guild_emojis_update_handler.go @@ -1,14 +1,14 @@ package handlers import ( - "github.com/disgoorg/snowflake/v2" - "golang.org/x/exp/slices" + "slices" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/cache" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/events" "github.com/disgoorg/disgo/gateway" + "github.com/disgoorg/snowflake/v2" ) type updatedEmoji struct { diff --git a/handlers/interaction_create_handler.go b/handlers/interaction_create_handler.go index 9c7988eb9..c93ccbc0a 100644 --- a/handlers/interaction_create_handler.go +++ b/handlers/interaction_create_handler.go @@ -1,6 +1,9 @@ package handlers import ( + "fmt" + "log/slog" + "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/events" @@ -65,6 +68,6 @@ func handleInteraction(client bot.Client, sequenceNumber int, shardID int, respo }) default: - client.Logger().Errorf("unknown interaction with type %T received", interaction) + client.Logger().Error("unknown interaction", slog.String("type", fmt.Sprintf("%T", interaction))) } } diff --git a/handlers/presence_update_handler.go b/handlers/presence_update_handler.go index 2267796f5..997082596 100644 --- a/handlers/presence_update_handler.go +++ b/handlers/presence_update_handler.go @@ -1,13 +1,14 @@ package handlers import ( + "slices" + "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/cache" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/events" "github.com/disgoorg/disgo/gateway" "github.com/disgoorg/snowflake/v2" - "golang.org/x/exp/slices" ) func gatewayHandlerPresenceUpdate(client bot.Client, sequenceNumber int, shardID int, event gateway.EventPresenceUpdate) { diff --git a/handlers/voice_handlers.go b/handlers/voice_handlers.go index ea906ccc3..27210a12a 100644 --- a/handlers/voice_handlers.go +++ b/handlers/voice_handlers.go @@ -47,7 +47,7 @@ func gatewayHandlerVoiceStateUpdate(client bot.Client, sequenceNumber int, shard OldVoiceState: oldVoiceState, }) } else { - client.Logger().Warnf("could not decide which GuildVoice to fire") + client.Logger().Warn("could not decide which GuildVoice to fire") } } diff --git a/httpserver/config.go b/httpserver/config.go index 8666813ce..92b0f231f 100644 --- a/httpserver/config.go +++ b/httpserver/config.go @@ -1,24 +1,24 @@ package httpserver import ( + "log/slog" "net/http" - - "github.com/disgoorg/log" ) // DefaultConfig returns a Config with sensible defaults. func DefaultConfig() *Config { return &Config{ - URL: "/interactions/callback", - Address: ":80", + Logger: slog.Default(), HTTPServer: &http.Server{}, ServeMux: http.NewServeMux(), + URL: "/interactions/callback", + Address: ":80", } } // Config lets you configure your Server instance. type Config struct { - Logger log.Logger + Logger *slog.Logger HTTPServer *http.Server ServeMux *http.ServeMux URL string @@ -38,7 +38,7 @@ func (c *Config) Apply(opts []ConfigOpt) { } // WithLogger sets the Logger of the Config. -func WithLogger(logger log.Logger) ConfigOpt { +func WithLogger(logger *slog.Logger) ConfigOpt { return func(config *Config) { config.Logger = logger } diff --git a/httpserver/server.go b/httpserver/server.go index ab25f3b72..ded77357c 100644 --- a/httpserver/server.go +++ b/httpserver/server.go @@ -5,12 +5,12 @@ import ( "context" "encoding/hex" "io" + "log/slog" "net/http" "sync" "time" "github.com/disgoorg/json" - "github.com/disgoorg/log" "github.com/disgoorg/disgo/discord" ) @@ -102,12 +102,12 @@ const ( ) // HandleInteraction handles an interaction from Discord's Outgoing Webhooks. It verifies and parses the interaction and then calls the passed EventHandlerFunc. -func HandleInteraction(publicKey PublicKey, logger log.Logger, handleFunc EventHandlerFunc) http.HandlerFunc { +func HandleInteraction(publicKey PublicKey, logger *slog.Logger, handleFunc EventHandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if ok := VerifyRequest(r, publicKey); !ok { http.Error(w, "Unauthorized", http.StatusUnauthorized) data, _ := io.ReadAll(r.Body) - logger.Trace("received http interaction with invalid signature. body: ", string(data)) + logger.Debug("received http interaction with invalid signature", slog.String("body", string(data))) return } @@ -117,7 +117,7 @@ func HandleInteraction(publicKey PublicKey, logger log.Logger, handleFunc EventH buff := new(bytes.Buffer) rqData, _ := io.ReadAll(io.TeeReader(r.Body, buff)) - logger.Trace("received http interaction. body: ", string(rqData)) + logger.Debug("received http interaction", slog.String("body", string(rqData))) var v EventInteractionCreate if err := json.NewDecoder(buff).Decode(&v); err != nil { @@ -200,6 +200,6 @@ func HandleInteraction(publicKey PublicKey, logger log.Logger, handleFunc EventH } rsData, _ := io.ReadAll(rsBody) - logger.Trace("response to http interaction. body: ", string(rsData)) + logger.Debug("response to http interaction", slog.String("body", string(rsData))) } } diff --git a/httpserver/server_impl.go b/httpserver/server_impl.go index 02f12fe51..d29a0ea62 100644 --- a/httpserver/server_impl.go +++ b/httpserver/server_impl.go @@ -4,6 +4,7 @@ import ( "context" "encoding/hex" "errors" + "log/slog" "net/http" ) @@ -13,10 +14,11 @@ var _ Server = (*serverImpl)(nil) func New(publicKey string, eventHandlerFunc EventHandlerFunc, opts ...ConfigOpt) Server { config := DefaultConfig() config.Apply(opts) + config.Logger = config.Logger.With(slog.String("name", "httpserver")) hexDecodedKey, err := hex.DecodeString(publicKey) if err != nil { - config.Logger.Errorf("error while decoding hex string: %s", err) + config.Logger.Debug("error while decoding hex string", slog.String("err", err.Error())) } return &serverImpl{ @@ -45,7 +47,7 @@ func (s *serverImpl) Start() { err = s.config.HTTPServer.ListenAndServe() } if !errors.Is(err, http.ErrServerClosed) { - s.config.Logger.Error("error while running http server: ", err) + s.config.Logger.Error("error while running http server", slog.String("err", err.Error())) } }() } diff --git a/internal/flags/flags.go b/internal/flags/flags.go index b7899cb9d..450f6af15 100644 --- a/internal/flags/flags.go +++ b/internal/flags/flags.go @@ -1,9 +1,12 @@ package flags -import "golang.org/x/exp/constraints" +// Integer is a constraint that permits any integer type. +type Integer interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr +} // Add allows you to add multiple bits together, producing a new bit -func Add[T constraints.Integer](f T, bits ...T) T { +func Add[T Integer](f T, bits ...T) T { for _, bit := range bits { f |= bit } @@ -11,7 +14,7 @@ func Add[T constraints.Integer](f T, bits ...T) T { } // Remove allows you to subtract multiple bits from the first, producing a new bit -func Remove[T constraints.Integer](f T, bits ...T) T { +func Remove[T Integer](f T, bits ...T) T { for _, bit := range bits { f &^= bit } @@ -19,7 +22,7 @@ func Remove[T constraints.Integer](f T, bits ...T) T { } // Has will ensure that the bit includes all the bits entered -func Has[T constraints.Integer](f T, bits ...T) bool { +func Has[T Integer](f T, bits ...T) bool { for _, bit := range bits { if (f & bit) != bit { return false @@ -29,7 +32,7 @@ func Has[T constraints.Integer](f T, bits ...T) bool { } // Missing will check whether the bit is missing any one of the bits -func Missing[T constraints.Integer](f T, bits ...T) bool { +func Missing[T Integer](f T, bits ...T) bool { for _, bit := range bits { if (f & bit) != bit { return true diff --git a/internal/insecurerandstr/random_str.go b/internal/insecurerandstr/random_str.go index 360a9ec17..3f5698a27 100644 --- a/internal/insecurerandstr/random_str.go +++ b/internal/insecurerandstr/random_str.go @@ -6,17 +6,17 @@ import ( "time" ) -var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") +var ( + letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") -func init() { - rand.Seed(time.Now().UnixNano()) -} + randStr = rand.New(rand.NewSource(time.Now().UnixNano())) +) // RandStr returns a random string of the given length. func RandStr(n int) string { b := make([]rune, n) for i := range b { - b[i] = letters[rand.Intn(len(letters))] + b[i] = letters[randStr.Intn(len(letters))] } return string(b) } diff --git a/oauth2/client_impl.go b/oauth2/client_impl.go index f3dadff51..f5d2b586a 100644 --- a/oauth2/client_impl.go +++ b/oauth2/client_impl.go @@ -1,6 +1,7 @@ package oauth2 import ( + "log/slog" "time" "github.com/disgoorg/snowflake/v2" @@ -13,6 +14,7 @@ import ( func New(id snowflake.ID, secret string, opts ...ConfigOpt) Client { config := DefaultConfig() config.Apply(opts) + config.Logger = config.Logger.With(slog.String("name", "oauth2")) return &clientImpl{ id: id, diff --git a/oauth2/config.go b/oauth2/config.go index 64c5a4074..0b17ea2b0 100644 --- a/oauth2/config.go +++ b/oauth2/config.go @@ -1,7 +1,7 @@ package oauth2 import ( - "github.com/disgoorg/log" + "log/slog" "github.com/disgoorg/disgo/rest" ) @@ -9,13 +9,13 @@ import ( // DefaultConfig is the configuration which is used by default func DefaultConfig() *Config { return &Config{ - Logger: log.Default(), + Logger: slog.Default(), } } // Config is the configuration for the OAuth2 client type Config struct { - Logger log.Logger + Logger *slog.Logger RestClient rest.Client RestClientConfigOpts []rest.ConfigOpt OAuth2 rest.OAuth2 @@ -43,7 +43,7 @@ func (c *Config) Apply(opts []ConfigOpt) { } // WithLogger applies a custom logger to the OAuth2 client -func WithLogger(logger log.Logger) ConfigOpt { +func WithLogger(logger *slog.Logger) ConfigOpt { return func(config *Config) { config.Logger = logger } diff --git a/oauth2/state_controller.go b/oauth2/state_controller.go index f239dca9f..0f5c50a72 100644 --- a/oauth2/state_controller.go +++ b/oauth2/state_controller.go @@ -1,6 +1,6 @@ package oauth2 -import "github.com/disgoorg/log" +import "log/slog" var ( _ StateController = (*stateControllerImpl)(nil) @@ -19,6 +19,7 @@ type StateController interface { func NewStateController(opts ...StateControllerConfigOpt) StateController { config := DefaultStateControllerConfig() config.Apply(opts) + config.Logger = config.Logger.With(slog.String("name", "oauth2_state_controller")) states := newTTLMap(config.MaxTTL) for state, url := range config.States { @@ -33,14 +34,14 @@ func NewStateController(opts ...StateControllerConfigOpt) StateController { } type stateControllerImpl struct { - logger log.Logger + logger *slog.Logger states *ttlMap newStateFunc func() string } func (c *stateControllerImpl) NewState(redirectURI string) string { state := c.newStateFunc() - c.logger.Debugf("new state: %s for redirect uri: %s", state, redirectURI) + c.logger.Debug("new state: %s for redirect uri", slog.String("state", state), slog.String("redirect_uri", redirectURI)) c.states.put(state, redirectURI) return state } @@ -50,7 +51,7 @@ func (c *stateControllerImpl) UseState(state string) string { if uri == "" { return "" } - c.logger.Debugf("using state: %s for redirect uri: %s", state, uri) + c.logger.Debug("using state: %s for redirect uri", slog.String("state", state), slog.String("redirect_uri", uri)) c.states.delete(state) return uri } diff --git a/oauth2/state_controller_config.go b/oauth2/state_controller_config.go index e9cd8067b..02f43c69f 100644 --- a/oauth2/state_controller_config.go +++ b/oauth2/state_controller_config.go @@ -1,17 +1,16 @@ package oauth2 import ( + "log/slog" "time" - "github.com/disgoorg/log" - "github.com/disgoorg/disgo/internal/insecurerandstr" ) // DefaultStateControllerConfig is the default configuration for the StateController func DefaultStateControllerConfig() *StateControllerConfig { return &StateControllerConfig{ - Logger: log.Default(), + Logger: slog.Default(), States: map[string]string{}, NewStateFunc: func() string { return insecurerandstr.RandStr(32) }, MaxTTL: time.Hour, @@ -20,7 +19,7 @@ func DefaultStateControllerConfig() *StateControllerConfig { // StateControllerConfig is the configuration for the StateController type StateControllerConfig struct { - Logger log.Logger + Logger *slog.Logger States map[string]string NewStateFunc func() string MaxTTL time.Duration @@ -37,7 +36,7 @@ func (c *StateControllerConfig) Apply(opts []StateControllerConfigOpt) { } // WithStateControllerLogger sets the logger for the StateController -func WithStateControllerLogger(logger log.Logger) StateControllerConfigOpt { +func WithStateControllerLogger(logger *slog.Logger) StateControllerConfigOpt { return func(config *StateControllerConfig) { config.Logger = logger } diff --git a/rest/rest_client.go b/rest/rest_client.go index e50edf6d3..605434de9 100644 --- a/rest/rest_client.go +++ b/rest/rest_client.go @@ -5,6 +5,7 @@ import ( "context" "fmt" "io" + "log/slog" "net/http" "net/url" "time" @@ -18,6 +19,7 @@ import ( func NewClient(botToken string, opts ...ConfigOpt) Client { config := DefaultConfig() config.Apply(opts) + config.Logger = config.Logger.With(slog.String("name", "rest_client")) config.RateLimiter.Reset() @@ -83,7 +85,7 @@ func (c *clientImpl) retry(endpoint *CompiledEndpoint, rqBody any, rsBody any, t return fmt.Errorf("failed to marshal request body: %w", err) } } - c.config.Logger.Tracef("request to %s, body: %s", endpoint.URL, string(rawRqBody)) + c.config.Logger.Debug("new request", slog.String("endpoint", endpoint.URL), slog.String("body", string(rawRqBody))) } rq, err := http.NewRequest(endpoint.Endpoint.Method, c.config.URL+endpoint.URL, bytes.NewReader(rawRqBody)) @@ -143,16 +145,15 @@ func (c *clientImpl) retry(endpoint *CompiledEndpoint, rqBody any, rsBody any, t if rawRsBody, err = io.ReadAll(rs.Body); err != nil { return fmt.Errorf("error reading response body in rest client: %w", err) } - c.config.Logger.Tracef("response from %s, code %d, body: %s", endpoint.URL, rs.StatusCode, string(rawRsBody)) + c.config.Logger.Debug("new response", slog.String("endpoint", endpoint.URL), slog.String("code", rs.Status), slog.String("body", string(rawRsBody))) } switch rs.StatusCode { case http.StatusOK, http.StatusCreated, http.StatusNoContent: if rsBody != nil && rs.Body != nil { if err = json.Unmarshal(rawRsBody, rsBody); err != nil { - wErr := fmt.Errorf("error unmarshalling response body: %w", err) - c.config.Logger.Error(wErr) - return wErr + c.config.Logger.Error("error unmarshalling response body", slog.String("err", err.Error()), slog.String("endpoint", endpoint.URL), slog.String("code", rs.Status), slog.String("body", string(rawRsBody))) + return fmt.Errorf("error unmarshalling response body: %w", err) } } return nil diff --git a/rest/rest_config.go b/rest/rest_config.go index 65de4cc15..7fec8507e 100644 --- a/rest/rest_config.go +++ b/rest/rest_config.go @@ -2,16 +2,15 @@ package rest import ( "fmt" + "log/slog" "net/http" "time" - - "github.com/disgoorg/log" ) // DefaultConfig is the configuration which is used by default func DefaultConfig() *Config { return &Config{ - Logger: log.Default(), + Logger: slog.Default(), HTTPClient: &http.Client{Timeout: 20 * time.Second}, URL: fmt.Sprintf("%sv%d", API, Version), } @@ -19,7 +18,7 @@ func DefaultConfig() *Config { // Config is the configuration for the rest client type Config struct { - Logger log.Logger + Logger *slog.Logger HTTPClient *http.Client RateLimiter RateLimiter RateLimiterConfigOpts []RateLimiterConfigOpt @@ -41,7 +40,7 @@ func (c *Config) Apply(opts []ConfigOpt) { } // WithLogger applies a custom logger to the rest rate limiter -func WithLogger(logger log.Logger) ConfigOpt { +func WithLogger(logger *slog.Logger) ConfigOpt { return func(config *Config) { config.Logger = logger } diff --git a/rest/rest_rate_limiter.go b/rest/rest_rate_limiter.go index d9be6977a..c056bb534 100644 --- a/rest/rest_rate_limiter.go +++ b/rest/rest_rate_limiter.go @@ -3,6 +3,7 @@ package rest import ( "context" "fmt" + "log/slog" "net/http" "strconv" "sync" @@ -11,6 +12,13 @@ import ( "github.com/sasha-s/go-csync" ) +const ( + // MaxRetries is the maximum number of retries the client should do + MaxRetries = 10 + // CleanupInterval is the interval at which the rate limiter cleans up old buckets + CleanupInterval = time.Second * 10 +) + // RateLimiter can be used to supply your own rate limit implementation type RateLimiter interface { // MaxRetries returns the maximum number of retries the client should do @@ -34,6 +42,7 @@ type RateLimiter interface { func NewRateLimiter(opts ...RateLimiterConfigOpt) RateLimiter { config := DefaultRateLimiterConfig() config.Apply(opts) + config.Logger = config.Logger.With(slog.String("name", "rest_rate_limiter")) rateLimiter := &rateLimiterImpl{ config: *config, @@ -83,13 +92,13 @@ func (l *rateLimiterImpl) doCleanup() { continue } if b.Reset.Before(now) { - l.config.Logger.Debugf("cleaning up bucket, Hash: %s, ID: %s, Reset: %s", hash, b.ID, b.Reset) + l.config.Logger.Debug("cleaning up bucket", slog.String("hash", hash), slog.String("id", b.ID), slog.Time("reset", b.Reset)) delete(l.buckets, hash) } b.mu.Unlock() } if before != len(l.buckets) { - l.config.Logger.Debugf("cleaned up %d rate limit buckets", before-len(l.buckets)) + l.config.Logger.Debug("cleaned up rate limit buckets", slog.Int("before", before), slog.Int("after", len(l.buckets)), slog.Int("removed", before-len(l.buckets))) } } @@ -132,10 +141,10 @@ func (l *rateLimiterImpl) getRouteHash(endpoint *CompiledEndpoint) string { func (l *rateLimiterImpl) getBucket(endpoint *CompiledEndpoint, create bool) *bucket { hash := l.getRouteHash(endpoint) - l.config.Logger.Trace("locking buckets") + l.config.Logger.Debug("locking buckets") l.bucketsMu.Lock() defer func() { - l.config.Logger.Trace("unlocking buckets") + l.config.Logger.Debug("unlocking buckets") l.bucketsMu.Unlock() }() b, ok := l.buckets[hash] @@ -156,7 +165,7 @@ func (l *rateLimiterImpl) getBucket(endpoint *CompiledEndpoint, create bool) *bu func (l *rateLimiterImpl) WaitBucket(ctx context.Context, endpoint *CompiledEndpoint) error { b := l.getBucket(endpoint, true) - l.config.Logger.Tracef("locking rest bucket, ID: %s, Limit: %d, Remaining: %d, Reset: %s", b.ID, b.Limit, b.Remaining, b.Reset) + l.config.Logger.Debug("locking rest bucket", slog.String("id", b.ID), slog.Int("limit", b.Limit), slog.Int("remaining", b.Remaining), slog.Time("reset", b.Reset)) if err := b.mu.CLock(ctx); err != nil { return err } @@ -192,7 +201,7 @@ func (l *rateLimiterImpl) UnlockBucket(endpoint *CompiledEndpoint, rs *http.Resp return nil } defer func() { - l.config.Logger.Tracef("unlocking rest bucket, ID: %s, Limit: %d, Remaining: %d, Reset: %s", b.ID, b.Limit, b.Remaining, b.Reset) + l.config.Logger.Debug("unlocking rest bucket", slog.String("id", b.ID), slog.Int("limit", b.Limit), slog.Int("remaining", b.Remaining), slog.Time("reset", b.Reset)) b.mu.Unlock() }() @@ -217,7 +226,7 @@ func (l *rateLimiterImpl) UnlockBucket(endpoint *CompiledEndpoint, rs *http.Resp resetAfterHeader := rs.Header.Get("X-RateLimit-Reset-After") retryAfterHeader := rs.Header.Get("Retry-After") - l.config.Logger.Tracef("code: %d, headers: global %t, cloudflare: %t, remaining: %s, limit: %s, reset: %s, retryAfter: %s", rs.StatusCode, global, cloudflare, remainingHeader, limitHeader, resetHeader, retryAfterHeader) + l.config.Logger.Debug("ratelimit response headers", slog.Int("code", rs.StatusCode), slog.Bool("global", global), slog.Bool("cloudflare", cloudflare), slog.String("remaining", remainingHeader), slog.String("limit", limitHeader), slog.String("reset", resetHeader), slog.String("reset_after", resetAfterHeader), slog.String("retry_after", retryAfterHeader)) // we hit a rate limit. let's see if it was global cloudflare or a route specific one if rs.StatusCode == http.StatusTooManyRequests { @@ -228,14 +237,14 @@ func (l *rateLimiterImpl) UnlockBucket(endpoint *CompiledEndpoint, rs *http.Resp reset := time.Now().Add(time.Second * time.Duration(retryAfter)) if global { l.global = reset - l.config.Logger.Warnf("global rate limit exceeded, retry after: %ds", retryAfter) + l.config.Logger.Warn("global rate limit exceeded", slog.Int("retry_after", retryAfter)) } else if cloudflare { l.global = reset - l.config.Logger.Warnf("cloudflare rate limit exceeded, retry after: %ds", retryAfter) + l.config.Logger.Warn("cloudflare rate limit exceeded", slog.Int("retry_after", retryAfter)) } else { b.Remaining = 0 b.Reset = reset - l.config.Logger.Warnf("rate limit on route %s exceeded, retry after: %ds", endpoint.URL, retryAfter) + l.config.Logger.Warn("rate limit exceeded", slog.String("endpoint", endpoint.URL), slog.Int("retry_after", retryAfter)) } return nil } @@ -243,7 +252,7 @@ func (l *rateLimiterImpl) UnlockBucket(endpoint *CompiledEndpoint, rs *http.Resp if limitHeader != "" { limit, err := strconv.Atoi(limitHeader) if err != nil { - return fmt.Errorf("invalid limit %s: %s", limitHeader, err) + return fmt.Errorf("invalid limit %s: %w", limitHeader, err) } b.Limit = limit } @@ -251,7 +260,7 @@ func (l *rateLimiterImpl) UnlockBucket(endpoint *CompiledEndpoint, rs *http.Resp if remainingHeader != "" { remaining, err := strconv.Atoi(remainingHeader) if err != nil { - return fmt.Errorf("invalid remaining %s: %s", remainingHeader, err) + return fmt.Errorf("invalid remaining %s: %w", remainingHeader, err) } b.Remaining = remaining } @@ -260,14 +269,14 @@ func (l *rateLimiterImpl) UnlockBucket(endpoint *CompiledEndpoint, rs *http.Resp if resetAfterHeader != "" { resetAfter, err := strconv.ParseFloat(resetAfterHeader, 64) if err != nil { - return fmt.Errorf("invalid reset after %s: %s", resetAfterHeader, err) + return fmt.Errorf("invalid reset after %s: %w", resetAfterHeader, err) } b.Reset = time.Now().Add(time.Duration(resetAfter) * time.Second) } else if resetHeader != "" { reset, err := strconv.ParseFloat(resetHeader, 64) if err != nil { - return fmt.Errorf("invalid reset %s: %s", resetHeader, err) + return fmt.Errorf("invalid reset %s: %w", resetHeader, err) } sec := int64(reset) diff --git a/rest/rest_rate_limiter_config.go b/rest/rest_rate_limiter_config.go index bd36f261c..b829a27c6 100644 --- a/rest/rest_rate_limiter_config.go +++ b/rest/rest_rate_limiter_config.go @@ -1,23 +1,22 @@ package rest import ( + "log/slog" "time" - - "github.com/disgoorg/log" ) // DefaultRateLimiterConfig is the configuration which is used by default. func DefaultRateLimiterConfig() *RateLimiterConfig { return &RateLimiterConfig{ - Logger: log.Default(), - MaxRetries: 10, - CleanupInterval: time.Second * 10, + Logger: slog.Default(), + MaxRetries: MaxRetries, + CleanupInterval: CleanupInterval, } } // RateLimiterConfig is the configuration for the rate limiter. type RateLimiterConfig struct { - Logger log.Logger + Logger *slog.Logger MaxRetries int CleanupInterval time.Duration } @@ -33,7 +32,7 @@ func (c *RateLimiterConfig) Apply(opts []RateLimiterConfigOpt) { } // WithRateLimiterLogger applies a custom logger to the rest rate limiter. -func WithRateLimiterLogger(logger log.Logger) RateLimiterConfigOpt { +func WithRateLimiterLogger(logger *slog.Logger) RateLimiterConfigOpt { return func(config *RateLimiterConfig) { config.Logger = logger } diff --git a/sharding/shard_manager.go b/sharding/shard_manager.go index d41af9bc6..236303751 100644 --- a/sharding/shard_manager.go +++ b/sharding/shard_manager.go @@ -8,6 +8,9 @@ import ( "github.com/disgoorg/disgo/gateway" ) +// ShardSplitCount is the default count a shard should be split into when it needs re-sharding. +const ShardSplitCount = 2 + // ShardManager manages multiple gateway.Gateway connections. // For more information on sharding see: https://discord.com/developers/docs/topics/gateway#sharding type ShardManager interface { diff --git a/sharding/shard_manager_config.go b/sharding/shard_manager_config.go index 36adb92cf..a78dc3605 100644 --- a/sharding/shard_manager_config.go +++ b/sharding/shard_manager_config.go @@ -1,7 +1,7 @@ package sharding import ( - "github.com/disgoorg/log" + "log/slog" "github.com/disgoorg/disgo/gateway" ) @@ -9,16 +9,16 @@ import ( // DefaultConfig returns a Config with sensible defaults. func DefaultConfig() *Config { return &Config{ - Logger: log.Default(), + Logger: slog.Default(), GatewayCreateFunc: gateway.New, - ShardSplitCount: 2, + ShardSplitCount: ShardSplitCount, } } // Config lets you configure your ShardManager instance. type Config struct { // Logger is the logger of the ShardManager. Defaults to log.Default() - Logger log.Logger + Logger *slog.Logger // ShardIDs is a map of shardIDs the ShardManager should manage. Leave this nil to manage all shards. ShardIDs map[int]struct{} // ShardCount is the total shard count of the ShardManager. Leave this at 0 to let Discord calculate the shard count for you. @@ -51,7 +51,7 @@ func (c *Config) Apply(opts []ConfigOpt) { } // WithLogger sets the logger of the ShardManager. -func WithLogger(logger log.Logger) ConfigOpt { +func WithLogger(logger *slog.Logger) ConfigOpt { return func(config *Config) { config.Logger = logger } diff --git a/sharding/shard_manager_impl.go b/sharding/shard_manager_impl.go index e26c0139c..37bf1a6d4 100644 --- a/sharding/shard_manager_impl.go +++ b/sharding/shard_manager_impl.go @@ -3,6 +3,8 @@ package sharding import ( "context" "errors" + "fmt" + "log/slog" "sync" "github.com/disgoorg/snowflake/v2" @@ -17,6 +19,7 @@ var _ ShardManager = (*shardManagerImpl)(nil) func New(token string, eventHandlerFunc gateway.EventHandlerFunc, opts ...ConfigOpt) ShardManager { config := DefaultConfig() config.Apply(opts) + config.Logger = config.Logger.With(slog.String("name", "sharding")) return &shardManagerImpl{ shards: map[int]gateway.Gateway{}, @@ -40,7 +43,7 @@ func (m *shardManagerImpl) closeHandler(shard gateway.Gateway, err error) { if !m.config.AutoScaling || !errors.As(err, &closeError) || gateway.CloseEventCodeByCode(closeError.Code) != gateway.CloseEventCodeShardingRequired { return } - m.config.Logger.Debugf("shard %d requires re-sharding", shard.ShardID()) + m.config.Logger.Debug("shard requires re-sharding", slog.Int("shardID", shard.ShardID())) // make sure shard is closed shard.Close(context.TODO()) @@ -51,7 +54,6 @@ func (m *shardManagerImpl) closeHandler(shard gateway.Gateway, err error) { delete(m.config.ShardIDs, shard.ShardID()) newShardCount := shard.ShardCount() * m.config.ShardSplitCount - if newShardCount > m.config.ShardCount { m.config.ShardCount = newShardCount } @@ -70,7 +72,7 @@ func (m *shardManagerImpl) closeHandler(shard gateway.Gateway, err error) { go func() { defer wg.Done() if err := m.config.RateLimiter.WaitBucket(context.TODO(), shardID); err != nil { - m.config.Logger.Errorf("failed to wait shard bucket %d: %s", shardID, err) + m.config.Logger.Error("failed to wait shard bucket", slog.String("err", err.Error()), slog.Int("shard_id", shardID)) return } defer m.config.RateLimiter.UnlockBucket(shardID) @@ -78,16 +80,16 @@ func (m *shardManagerImpl) closeHandler(shard gateway.Gateway, err error) { newShard := m.config.GatewayCreateFunc(m.token, m.eventHandlerFunc, m.closeHandler, append(m.config.GatewayConfigOpts, gateway.WithShardID(shardID), gateway.WithShardCount(newShardCount))...) m.shards[shardID] = newShard if err := newShard.Open(context.TODO()); err != nil { - m.config.Logger.Errorf("failed to re shard %d, error: %s", shardID, err) + m.config.Logger.Error("failed to re shard", slog.String("err", err.Error()), slog.Int("shard_id", shardID)) } }() } wg.Wait() - m.config.Logger.Debugf("re-sharded shard %d into newShards: %d, newShardCount: %d", shard.ShardID(), newShardIDs, newShardCount) + m.config.Logger.Debug("re-sharded shard", slog.Int("shard_id", shard.ShardID()), slog.String("new_shard_ids", fmt.Sprint(newShardIDs)), slog.Int("new_shard_count", newShardCount)) } func (m *shardManagerImpl) Open(ctx context.Context) { - m.config.Logger.Debugf("opening %+v shards...", m.config.ShardIDs) + m.config.Logger.Debug("opening shards", slog.String("shard_ids", fmt.Sprint(m.config.ShardIDs))) var wg sync.WaitGroup m.shardsMu.Lock() @@ -102,7 +104,7 @@ func (m *shardManagerImpl) Open(ctx context.Context) { go func() { defer wg.Done() if err := m.config.RateLimiter.WaitBucket(ctx, shardID); err != nil { - m.config.Logger.Errorf("failed to wait shard bucket %d: %s", shardID, err) + m.config.Logger.Error("failed to wait shard bucket", slog.String("err", err.Error()), slog.Int("shard_id", shardID)) return } defer m.config.RateLimiter.UnlockBucket(shardID) @@ -110,7 +112,7 @@ func (m *shardManagerImpl) Open(ctx context.Context) { shard := m.config.GatewayCreateFunc(m.token, m.eventHandlerFunc, m.closeHandler, append(m.config.GatewayConfigOpts, gateway.WithShardID(shardID), gateway.WithShardCount(m.config.ShardCount))...) m.shards[shardID] = shard if err := shard.Open(ctx); err != nil { - m.config.Logger.Errorf("failed to open shard %d: %s", shardID, err) + m.config.Logger.Error("failed to open shard", slog.String("err", err.Error()), slog.Int("shard_id", shardID)) } }() } @@ -118,7 +120,7 @@ func (m *shardManagerImpl) Open(ctx context.Context) { } func (m *shardManagerImpl) Close(ctx context.Context) { - m.config.Logger.Debugf("closing %v shards...", m.config.ShardIDs) + m.config.Logger.Debug("closing shards", slog.String("shard_ids", fmt.Sprint(m.config.ShardIDs))) var wg sync.WaitGroup m.shardsMu.Lock() @@ -140,7 +142,7 @@ func (m *shardManagerImpl) OpenShard(ctx context.Context, shardID int) error { } func (m *shardManagerImpl) openShard(ctx context.Context, shardID int, shardCount int) error { - m.config.Logger.Debugf("opening shard %d...", shardID) + m.config.Logger.Debug("opening shard", slog.Int("shard_id", shardID)) if err := m.config.RateLimiter.WaitBucket(ctx, shardID); err != nil { return err @@ -156,7 +158,7 @@ func (m *shardManagerImpl) openShard(ctx context.Context, shardID int, shardCoun } func (m *shardManagerImpl) CloseShard(ctx context.Context, shardID int) { - m.config.Logger.Debugf("closing shard %d...", shardID) + m.config.Logger.Debug("closing shard", slog.Int("shard_id", shardID)) m.shardsMu.Lock() defer m.shardsMu.Unlock() shard, ok := m.shards[shardID] diff --git a/sharding/shard_rate_limiter.go b/sharding/shard_rate_limiter.go index 613cc0513..da21a281e 100644 --- a/sharding/shard_rate_limiter.go +++ b/sharding/shard_rate_limiter.go @@ -4,6 +4,9 @@ import ( "context" ) +// MaxConcurrency is the default number of shards that can log in at the same time. +const MaxConcurrency = 1 + // RateLimiter limits how many shards can log in to Discord at the same time. type RateLimiter interface { // Close gracefully closes the RateLimiter. diff --git a/sharding/shard_rate_limiter_config.go b/sharding/shard_rate_limiter_config.go index 7193d7191..eb5eaf22b 100644 --- a/sharding/shard_rate_limiter_config.go +++ b/sharding/shard_rate_limiter_config.go @@ -1,20 +1,20 @@ package sharding import ( - "github.com/disgoorg/log" + "log/slog" ) // DefaultRateLimiterConfig returns a RateLimiterConfig with sensible defaults. func DefaultRateLimiterConfig() *RateLimiterConfig { return &RateLimiterConfig{ - Logger: log.Default(), - MaxConcurrency: 1, + Logger: slog.Default(), + MaxConcurrency: MaxConcurrency, } } // RateLimiterConfig lets you configure your RateLimiter instance. type RateLimiterConfig struct { - Logger log.Logger + Logger *slog.Logger MaxConcurrency int } @@ -29,7 +29,7 @@ func (c *RateLimiterConfig) Apply(opts []RateLimiterConfigOpt) { } // WithRateLimiterLogger sets the logger for the RateLimiter. -func WithRateLimiterLogger(logger log.Logger) RateLimiterConfigOpt { +func WithRateLimiterLogger(logger *slog.Logger) RateLimiterConfigOpt { return func(config *RateLimiterConfig) { config.Logger = logger } diff --git a/sharding/shard_rate_limiter_impl.go b/sharding/shard_rate_limiter_impl.go index 315487538..49b9540bf 100644 --- a/sharding/shard_rate_limiter_impl.go +++ b/sharding/shard_rate_limiter_impl.go @@ -2,6 +2,7 @@ package sharding import ( "context" + "log/slog" "sync" "time" @@ -14,6 +15,7 @@ var _ RateLimiter = (*rateLimiterImpl)(nil) func NewRateLimiter(opts ...RateLimiterConfigOpt) RateLimiter { config := DefaultRateLimiterConfig() config.Apply(opts) + config.Logger = config.Logger.With(slog.String("name", "sharding_rate_limiter")) return &rateLimiterImpl{ buckets: map[int]*bucket{}, @@ -69,7 +71,7 @@ func (r *rateLimiterImpl) getBucket(shardID int, create bool) *bucket { func (r *rateLimiterImpl) WaitBucket(ctx context.Context, shardID int) error { b := r.getBucket(shardID, true) - r.config.Logger.Debugf("locking shard bucket: Key: %d, Reset: %s", b.Key, b.Reset) + r.config.Logger.Debug("locking shard bucket", slog.Int("key", b.Key), slog.Time("reset", b.Reset)) if err := b.mu.CLock(ctx); err != nil { return err } @@ -102,7 +104,7 @@ func (r *rateLimiterImpl) UnlockBucket(shardID int) { return } defer func() { - r.config.Logger.Debugf("unlocking shard bucket: Key: %d, Reset: %s", b.Key, b.Reset) + r.config.Logger.Debug("unlocking shard bucket", slog.Int("key", b.Key), slog.Time("reset", b.Reset)) b.mu.Unlock() }() diff --git a/voice/audio_receiver.go b/voice/audio_receiver.go index 57cad5ab1..10ea67d64 100644 --- a/voice/audio_receiver.go +++ b/voice/audio_receiver.go @@ -3,15 +3,15 @@ package voice import ( "context" "errors" + "log/slog" "net" - "github.com/disgoorg/log" "github.com/disgoorg/snowflake/v2" ) type ( // AudioReceiverCreateFunc is used to create a new AudioReceiver reading audio from the given Conn. - AudioReceiverCreateFunc func(logger log.Logger, receiver OpusFrameReceiver, connection Conn) AudioReceiver + AudioReceiverCreateFunc func(logger *slog.Logger, receiver OpusFrameReceiver, connection Conn) AudioReceiver // UserFilterFunc is used as a filter for which users to receive audio from. UserFilterFunc func(userID snowflake.ID) bool @@ -42,7 +42,7 @@ type ( ) // NewAudioReceiver creates a new AudioReceiver reading audio to the given OpusFrameReceiver from the given Conn. -func NewAudioReceiver(logger log.Logger, opusReceiver OpusFrameReceiver, conn Conn) AudioReceiver { +func NewAudioReceiver(logger *slog.Logger, opusReceiver OpusFrameReceiver, conn Conn) AudioReceiver { return &defaultAudioReceiver{ logger: logger, opusReceiver: opusReceiver, @@ -51,7 +51,7 @@ func NewAudioReceiver(logger log.Logger, opusReceiver OpusFrameReceiver, conn Co } type defaultAudioReceiver struct { - logger log.Logger + logger *slog.Logger cancelFunc context.CancelFunc opusReceiver OpusFrameReceiver conn Conn @@ -62,7 +62,7 @@ func (s *defaultAudioReceiver) Open() { } func (s *defaultAudioReceiver) open() { - defer s.logger.Debugf("closing audio receiver") + defer s.logger.Debug("closing audio receiver") ctx, cancel := context.WithCancel(context.Background()) s.cancelFunc = cancel defer cancel() @@ -88,12 +88,12 @@ func (s *defaultAudioReceiver) receive() { return } if err != nil { - s.logger.Errorf("error while reading packet: %s", err) + s.logger.Error("error while reading packet", slog.String("err", err.Error())) return } if s.opusReceiver != nil { if err = s.opusReceiver.ReceiveOpusFrame(s.conn.UserIDBySSRC(packet.SSRC), packet); err != nil { - s.logger.Errorf("error while receiving opus frame: %s", err) + s.logger.Error("error while receiving opus frame", slog.String("err", err.Error())) } } diff --git a/voice/audio_sender.go b/voice/audio_sender.go index b7276e30c..31474c18a 100644 --- a/voice/audio_sender.go +++ b/voice/audio_sender.go @@ -4,10 +4,9 @@ import ( "context" "errors" "io" + "log/slog" "net" "time" - - "github.com/disgoorg/log" ) // SilenceAudioFrame is a 20ms opus frame of silence. @@ -26,7 +25,7 @@ const ( type ( // AudioSenderCreateFunc is used to create a new AudioSender sending audio to the given Conn. - AudioSenderCreateFunc func(logger log.Logger, provider OpusFrameProvider, conn Conn) AudioSender + AudioSenderCreateFunc func(logger *slog.Logger, provider OpusFrameProvider, conn Conn) AudioSender // AudioSender is used to send audio to a Conn. AudioSender interface { @@ -45,7 +44,7 @@ type ( ) // NewAudioSender creates a new AudioSender sending audio from the given OpusFrameProvider to the given Conn. -func NewAudioSender(logger log.Logger, opusProvider OpusFrameProvider, conn Conn) AudioSender { +func NewAudioSender(logger *slog.Logger, opusProvider OpusFrameProvider, conn Conn) AudioSender { return &defaultAudioSender{ logger: logger, opusProvider: opusProvider, @@ -55,7 +54,7 @@ func NewAudioSender(logger log.Logger, opusProvider OpusFrameProvider, conn Conn } type defaultAudioSender struct { - logger log.Logger + logger *slog.Logger cancelFunc context.CancelFunc opusProvider OpusFrameProvider conn Conn @@ -102,7 +101,7 @@ func (s *defaultAudioSender) send() { } opus, err := s.opusProvider.ProvideOpusFrame() if err != nil && err != io.EOF { - s.logger.Errorf("error while reading opus frame: %s", err) + s.logger.Error("error while reading opus frame", slog.String("err", err.Error())) return } if len(opus) == 0 { @@ -144,7 +143,7 @@ func (s *defaultAudioSender) handleErr(err error) { s.Close() return } - s.logger.Errorf("failed to send audio: %s", err) + s.logger.Error("failed to send audio", slog.String("err", err.Error())) } func (s *defaultAudioSender) Close() { diff --git a/voice/conn.go b/voice/conn.go index b90bd9845..64d4bfd13 100644 --- a/voice/conn.go +++ b/voice/conn.go @@ -2,6 +2,7 @@ package voice import ( "context" + "log/slog" "sync" "time" @@ -61,6 +62,7 @@ type ( func NewConn(guildID snowflake.ID, userID snowflake.ID, voiceStateUpdateFunc StateUpdateFunc, removeConnFunc func(), opts ...ConnConfigOpt) Conn { config := DefaultConnConfig() config.Apply(opts) + config.Logger = config.Logger.With(slog.String("name", "voice_conn")) conn := &connImpl{ config: *config, diff --git a/voice/conn_config.go b/voice/conn_config.go index 4480fd396..9f55b802f 100644 --- a/voice/conn_config.go +++ b/voice/conn_config.go @@ -1,13 +1,13 @@ package voice import ( - "github.com/disgoorg/log" + "log/slog" ) // DefaultConnConfig returns a ConnConfig with sensible defaults. func DefaultConnConfig() *ConnConfig { return &ConnConfig{ - Logger: log.Default(), + Logger: slog.Default(), GatewayCreateFunc: NewGateway, UDPConnCreateFunc: NewUDPConn, AudioSenderCreateFunc: NewAudioSender, @@ -17,7 +17,7 @@ func DefaultConnConfig() *ConnConfig { // ConnConfig is used to configure a Conn. type ConnConfig struct { - Logger log.Logger + Logger *slog.Logger GatewayCreateFunc GatewayCreateFunc GatewayConfigOpts []GatewayConfigOpt @@ -42,7 +42,7 @@ func (c *ConnConfig) Apply(opts []ConnConfigOpt) { } // WithConnLogger sets the Conn(s) used Logger. -func WithConnLogger(logger log.Logger) ConnConfigOpt { +func WithConnLogger(logger *slog.Logger) ConnConfigOpt { return func(config *ConnConfig) { config.Logger = logger } diff --git a/voice/gateway.go b/voice/gateway.go index 76b171de1..5d4ae73f1 100644 --- a/voice/gateway.go +++ b/voice/gateway.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io" + "log/slog" "sync" "syscall" "time" @@ -92,6 +93,7 @@ type Gateway interface { func NewGateway(eventHandlerFunc EventHandlerFunc, closeHandlerFunc CloseHandlerFunc, opts ...GatewayConfigOpt) Gateway { config := DefaultGatewayConfig() config.Apply(opts) + config.Logger = config.Logger.With(slog.String("name", "voice_conn_gateway")) return &gatewayImpl{ config: *config, @@ -135,13 +137,13 @@ func (g *gatewayImpl) Open(ctx context.Context, state State) error { g.status = StatusConnecting gatewayURL := fmt.Sprintf("wss://%s?v=%d", state.Endpoint, GatewayVersion) - g.config.Logger.Debugf("connecting to voice gateway at: %s", gatewayURL) + g.config.Logger.Debug("connecting to voice gateway at", slog.String("url", gatewayURL)) g.lastHeartbeatSent = time.Now().UTC() conn, rs, err := g.config.Dialer.DialContext(ctx, gatewayURL, nil) if err != nil { g.Close() defer rs.Body.Close() - return fmt.Errorf("error connecting to voice gateway. err: %w", err) + return fmt.Errorf("error connecting to voice gateway: %w", err) } conn.SetCloseHandler(func(code int, text string) error { @@ -161,7 +163,7 @@ func (g *gatewayImpl) Close() { func (g *gatewayImpl) CloseWithCode(code int, message string) { if g.heartbeatTicker != nil { - g.config.Logger.Debug("closing heartbeat goroutines...") + g.config.Logger.Debug("closing heartbeat goroutines") g.heartbeatTicker.Stop() g.heartbeatTicker = nil } @@ -169,9 +171,9 @@ func (g *gatewayImpl) CloseWithCode(code int, message string) { g.connMu.Lock() defer g.connMu.Unlock() if g.conn != nil { - g.config.Logger.Debugf("closing voice gateway connection with code: %d, message: %s", code, message) + g.config.Logger.Debug("closing voice gateway connection", slog.Int("code", code), slog.String("message", message)) if err := g.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(code, message)); err != nil && !errors.Is(err, websocket.ErrCloseSent) { - g.config.Logger.Debug("error writing close code. error: ", err) + g.config.Logger.Debug("error writing close code", slog.String("err", err.Error())) } _ = g.conn.Close() g.conn = nil @@ -186,7 +188,7 @@ func (g *gatewayImpl) CloseWithCode(code int, message string) { func (g *gatewayImpl) heartbeat() { g.heartbeatTicker = time.NewTicker(g.heartbeatInterval) defer g.heartbeatTicker.Stop() - defer g.config.Logger.Debug("exiting voice heartbeat goroutine...") + defer g.config.Logger.Debug("exiting voice heartbeat goroutine") for range g.heartbeatTicker.C { g.sendHeartbeat() @@ -202,7 +204,7 @@ func (g *gatewayImpl) sendHeartbeat() { if !errors.Is(err, ErrGatewayNotConnected) || errors.Is(err, syscall.EPIPE) { return } - g.config.Logger.Error("failed to send heartbeat. error: ", err) + g.config.Logger.Error("failed to send heartbeat", slog.String("err", err.Error())) g.CloseWithCode(websocket.CloseServiceRestart, "heartbeat timeout") go g.reconnect() return @@ -211,7 +213,7 @@ func (g *gatewayImpl) sendHeartbeat() { } func (g *gatewayImpl) listen(conn *websocket.Conn) { - defer g.config.Logger.Debug("exiting listen goroutine...") + defer g.config.Logger.Debug("exiting listen goroutine") loop: for { _, reader, err := conn.NextReader() @@ -242,7 +244,7 @@ loop: message, err := g.parseMessage(reader) if err != nil { - g.config.Logger.Error("error while parsing voice gateway event. error: ", err) + g.config.Logger.Error("error while parsing voice gateway event", slog.String("err", err.Error())) continue } @@ -283,7 +285,7 @@ loop: case GatewayMessageDataHeartbeatACK: if int64(d) != g.lastNonce { - g.config.Logger.Errorf("received heartbeat ack with nonce: %d, expected nonce: %d", int64(d), g.lastNonce) + g.config.Logger.Error("received heartbeat ack with nonce", slog.Int64("nonce", int64(d)), slog.Int64("last_nonce", g.lastNonce)) go g.reconnect() break loop } @@ -315,7 +317,7 @@ func (g *gatewayImpl) send(ctx context.Context, messageType int, data []byte) er return ErrGatewayNotConnected } - g.config.Logger.Trace("sending message to voice gateway. data: ", string(data)) + g.config.Logger.Debug("sending message to voice gateway", slog.String("data", string(data))) deadline, ok := ctx.Deadline() if ok { if err := g.conn.SetWriteDeadline(deadline); err != nil { @@ -343,12 +345,12 @@ func (g *gatewayImpl) reconnectTry(ctx context.Context, try int) error { case <-timer.C: } - g.config.Logger.Debug("reconnecting voice gateway...") + g.config.Logger.Debug("reconnecting voice gateway") if err := g.Open(ctx, g.state); err != nil { if errors.Is(err, discord.ErrGatewayAlreadyConnected) { return err } - g.config.Logger.Error("failed to reconnect voice gateway. error: ", err) + g.config.Logger.Error("failed to reconnect voice gateway", slog.String("err", err.Error())) g.status = StatusDisconnected return g.reconnectTry(ctx, try+1) } @@ -357,14 +359,14 @@ func (g *gatewayImpl) reconnectTry(ctx context.Context, try int) error { func (g *gatewayImpl) reconnect() { if err := g.reconnectTry(context.Background(), 0); err != nil { - g.config.Logger.Error("failed to reopen voice gateway", err) + g.config.Logger.Error("failed to reopen voice gateway", slog.String("err", err.Error())) } } func (g *gatewayImpl) parseMessage(r io.Reader) (GatewayMessage, error) { buff := &bytes.Buffer{} data, _ := io.ReadAll(io.TeeReader(r, buff)) - g.config.Logger.Tracef("received message from voice gateway. data: %s", string(data)) + g.config.Logger.Debug("received message from voice gateway", slog.String("data", string(data))) var message GatewayMessage if err := json.NewDecoder(buff).Decode(&message); err != nil { diff --git a/voice/gateway_config.go b/voice/gateway_config.go index 53d847007..392b33f3c 100644 --- a/voice/gateway_config.go +++ b/voice/gateway_config.go @@ -1,14 +1,15 @@ package voice import ( - "github.com/disgoorg/log" + "log/slog" + "github.com/gorilla/websocket" ) // DefaultGatewayConfig returns a GatewayConfig with sensible defaults. func DefaultGatewayConfig() *GatewayConfig { return &GatewayConfig{ - Logger: log.Default(), + Logger: slog.Default(), Dialer: websocket.DefaultDialer, AutoReconnect: true, } @@ -16,7 +17,7 @@ func DefaultGatewayConfig() *GatewayConfig { // GatewayConfig is used to configure a Gateway. type GatewayConfig struct { - Logger log.Logger + Logger *slog.Logger Dialer *websocket.Dialer AutoReconnect bool } @@ -32,7 +33,7 @@ func (c *GatewayConfig) Apply(opts []GatewayConfigOpt) { } // WithGatewayLogger sets the Gateway(s) used Logger. -func WithGatewayLogger(logger log.Logger) GatewayConfigOpt { +func WithGatewayLogger(logger *slog.Logger) GatewayConfigOpt { return func(config *GatewayConfig) { config.Logger = logger } diff --git a/voice/manager.go b/voice/manager.go index 5eefebcf0..2f6ab66c1 100644 --- a/voice/manager.go +++ b/voice/manager.go @@ -2,6 +2,7 @@ package voice import ( "context" + "log/slog" "sync" "github.com/disgoorg/snowflake/v2" @@ -42,6 +43,8 @@ type ( func NewManager(voiceStateUpdateFunc StateUpdateFunc, userID snowflake.ID, opts ...ManagerConfigOpt) Manager { config := DefaultManagerConfig() config.Apply(opts) + config.Logger = config.Logger.With(slog.String("name", "voice")) + return &managerImpl{ config: *config, voiceStateUpdateFunc: voiceStateUpdateFunc, @@ -60,7 +63,7 @@ type managerImpl struct { } func (m *managerImpl) HandleVoiceStateUpdate(update gateway.EventVoiceStateUpdate) { - m.config.Logger.Debugf("VoiceStateUpdate for guild: %s", update.GuildID) + m.config.Logger.Debug("new VoiceStateUpdate", slog.Int64("guild_id", int64(update.GuildID))) conn := m.GetConn(update.GuildID) if conn == nil { @@ -70,7 +73,7 @@ func (m *managerImpl) HandleVoiceStateUpdate(update gateway.EventVoiceStateUpdat } func (m *managerImpl) HandleVoiceServerUpdate(update gateway.EventVoiceServerUpdate) { - m.config.Logger.Debugf("VoiceServerUpdate for guild: %s", update.GuildID) + m.config.Logger.Debug("new VoiceServerUpdate", slog.Int64("guild_id", int64(update.GuildID))) conn := m.GetConn(update.GuildID) if conn == nil { @@ -80,7 +83,7 @@ func (m *managerImpl) HandleVoiceServerUpdate(update gateway.EventVoiceServerUpd } func (m *managerImpl) CreateConn(guildID snowflake.ID) Conn { - m.config.Logger.Debugf("Creating new voice conn for guild: %s", guildID) + m.config.Logger.Debug("Creating new voice conn", slog.Int64("guild_id", int64(guildID))) if conn := m.GetConn(guildID); conn != nil { return conn } @@ -112,7 +115,7 @@ func (m *managerImpl) ForEachCon(f func(connection Conn)) { } func (m *managerImpl) RemoveConn(guildID snowflake.ID) { - m.config.Logger.Debugf("Removing voice conn for guild: %s", guildID) + m.config.Logger.Debug("Removing voice conn", slog.Int64("guild_id", int64(guildID))) conn := m.GetConn(guildID) if conn == nil { return diff --git a/voice/manager_config.go b/voice/manager_config.go index 17009c664..b0e9f1a8d 100644 --- a/voice/manager_config.go +++ b/voice/manager_config.go @@ -1,18 +1,18 @@ package voice -import "github.com/disgoorg/log" +import "log/slog" // DefaultManagerConfig returns the default ManagerConfig with sensible defaults. func DefaultManagerConfig() *ManagerConfig { return &ManagerConfig{ - Logger: log.Default(), + Logger: slog.Default(), ConnCreateFunc: NewConn, } } // ManagerConfig is a function that configures a Manager. type ManagerConfig struct { - Logger log.Logger + Logger *slog.Logger ConnCreateFunc ConnCreateFunc ConnOpts []ConnConfigOpt @@ -29,7 +29,7 @@ func (c *ManagerConfig) Apply(opts []ManagerConfigOpt) { } // WithLogger sets the logger for the webhook client -func WithLogger(logger log.Logger) ManagerConfigOpt { +func WithLogger(logger *slog.Logger) ManagerConfigOpt { return func(ManagerConfig *ManagerConfig) { ManagerConfig.Logger = logger } diff --git a/voice/udp_conn.go b/voice/udp_conn.go index eb050111d..a9783cde1 100644 --- a/voice/udp_conn.go +++ b/voice/udp_conn.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io" + "log/slog" "net" "strconv" "strings" @@ -15,8 +16,13 @@ import ( "golang.org/x/crypto/nacl/secretbox" ) -// OpusPacketHeaderSize is the size of the opus packet header. -const OpusPacketHeaderSize = 12 +const ( + // OpusPacketHeaderSize is the size of the opus packet header. + OpusPacketHeaderSize = 12 + + // UDPTimeout is the timeout for UDP connections. + UDPTimeout = 30 * time.Second +) // ErrDecryptionFailed is returned when the packet decryption fails. var ErrDecryptionFailed = errors.New("decryption failed") @@ -86,6 +92,7 @@ type ( func NewUDPConn(opts ...UDPConnConfigOpt) UDPConn { config := DefaultUDPConnConfig() config.Apply(opts) + config.Logger = config.Logger.With(slog.String("name", "voice_conn_udp_conn")) return &udpConnImpl{ config: config, @@ -148,7 +155,7 @@ func (u *udpConnImpl) Open(ctx context.Context, ip string, port int, ssrc uint32 u.connMu.Lock() defer u.connMu.Unlock() host := net.JoinHostPort(ip, strconv.Itoa(port)) - u.config.Logger.Debugf("Opening UDPConn connection to: %s\n", host) + u.config.Logger.Debug("Opening UDPConn connection", slog.String("host", host)) var err error u.conn, err = u.config.Dialer.DialContext(ctx, "udp", host) if err != nil { diff --git a/voice/udp_conn_config.go b/voice/udp_conn_config.go index 7e860b0ad..f1f0af98f 100644 --- a/voice/udp_conn_config.go +++ b/voice/udp_conn_config.go @@ -1,23 +1,21 @@ package voice import ( + "log/slog" "net" - "time" - - "github.com/disgoorg/log" ) func DefaultUDPConnConfig() UDPConnConfig { return UDPConnConfig{ - Logger: log.Default(), + Logger: slog.Default(), Dialer: &net.Dialer{ - Timeout: 30 * time.Second, + Timeout: UDPTimeout, }, } } type UDPConnConfig struct { - Logger log.Logger + Logger *slog.Logger Dialer *net.Dialer } @@ -29,7 +27,7 @@ func (c *UDPConnConfig) Apply(opts []UDPConnConfigOpt) { } } -func WithUDPConnLogger(logger log.Logger) UDPConnConfigOpt { +func WithUDPConnLogger(logger *slog.Logger) UDPConnConfigOpt { return func(config *UDPConnConfig) { config.Logger = logger } diff --git a/webhook/webhook_client_impl.go b/webhook/webhook_client_impl.go index 0adbacda2..2a85d1381 100644 --- a/webhook/webhook_client_impl.go +++ b/webhook/webhook_client_impl.go @@ -2,6 +2,7 @@ package webhook import ( "context" + "log/slog" "net/url" "strings" @@ -36,6 +37,7 @@ func NewWithURL(webhookURL string, opts ...ConfigOpt) (Client, error) { func New(id snowflake.ID, token string, opts ...ConfigOpt) Client { config := DefaultConfig() config.Apply(opts) + config.Logger = config.Logger.With(slog.String("name", "webhook")) return &clientImpl{ id: id, diff --git a/webhook/webhook_config.go b/webhook/webhook_config.go index 4ebe725ba..510c953a8 100644 --- a/webhook/webhook_config.go +++ b/webhook/webhook_config.go @@ -1,7 +1,7 @@ package webhook import ( - "github.com/disgoorg/log" + "log/slog" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/rest" @@ -10,14 +10,14 @@ import ( // DefaultConfig is the default configuration for the webhook client func DefaultConfig() *Config { return &Config{ - Logger: log.Default(), + Logger: slog.Default(), DefaultAllowedMentions: &discord.DefaultAllowedMentions, } } // Config is the configuration for the webhook client type Config struct { - Logger log.Logger + Logger *slog.Logger RestClient rest.Client RestClientConfigOpts []rest.ConfigOpt Webhooks rest.Webhooks @@ -33,7 +33,7 @@ func (c *Config) Apply(opts []ConfigOpt) { opt(c) } if c.RestClient == nil { - c.RestClient = rest.NewClient("", c.RestClientConfigOpts...) + c.RestClient = rest.NewClient("", append([]rest.ConfigOpt{rest.WithLogger(c.Logger)}, c.RestClientConfigOpts...)...) } if c.Webhooks == nil { c.Webhooks = rest.NewWebhooks(c.RestClient) @@ -41,7 +41,7 @@ func (c *Config) Apply(opts []ConfigOpt) { } // WithLogger sets the logger for the webhook client -func WithLogger(logger log.Logger) ConfigOpt { +func WithLogger(logger *slog.Logger) ConfigOpt { return func(config *Config) { config.Logger = logger }