Added a bunch of discord debugging
This commit is contained in:
parent
e8201a254e
commit
4568def378
|
@ -23,6 +23,34 @@ import (
|
|||
"github.com/jpillora/backoff"
|
||||
)
|
||||
|
||||
type BotEvent struct {
|
||||
Timestamp time.Time
|
||||
Name string
|
||||
Extra string
|
||||
}
|
||||
|
||||
var botEvents = make([]BotEvent, 0, 1000)
|
||||
var botEventsMutex = sync.Mutex{}
|
||||
|
||||
func RecordBotEvent(name, extra string) {
|
||||
botEventsMutex.Lock()
|
||||
defer botEventsMutex.Unlock()
|
||||
if len(botEvents) > 1000 {
|
||||
botEvents = botEvents[len(botEvents)-500:]
|
||||
}
|
||||
botEvents = append(botEvents, BotEvent{
|
||||
Timestamp: time.Now(),
|
||||
Name: name,
|
||||
Extra: extra,
|
||||
})
|
||||
}
|
||||
|
||||
func GetBotEvents() []BotEvent {
|
||||
botEventsMutex.Lock()
|
||||
defer botEventsMutex.Unlock()
|
||||
return botEvents[:]
|
||||
}
|
||||
|
||||
func RunDiscordBot(ctx context.Context, dbConn *pgxpool.Pool) jobs.Job {
|
||||
log := logging.ExtractLogger(ctx).With().Str("module", "discord").Logger()
|
||||
ctx = logging.AttachLoggerToContext(&log, ctx)
|
||||
|
@ -56,6 +84,11 @@ func RunDiscordBot(ctx context.Context, dbConn *pgxpool.Pool) jobs.Job {
|
|||
log.Info().Msg("Connecting to the Discord gateway")
|
||||
bot := newBotInstance(dbConn)
|
||||
err := bot.Run(ctx)
|
||||
disconnectMessage := ""
|
||||
if err != nil {
|
||||
disconnectMessage = err.Error()
|
||||
}
|
||||
RecordBotEvent("Disconnected", disconnectMessage)
|
||||
if err != nil {
|
||||
dur := boff.Duration()
|
||||
log.Error().
|
||||
|
@ -101,6 +134,8 @@ type botInstance struct {
|
|||
conn *websocket.Conn
|
||||
dbConn *pgxpool.Pool
|
||||
|
||||
resuming bool
|
||||
|
||||
heartbeatIntervalMs int
|
||||
forceHeartbeat chan struct{}
|
||||
|
||||
|
@ -193,6 +228,7 @@ func (bot *botInstance) Run(ctx context.Context) (err error) {
|
|||
logging.ExtractLogger(ctx).Info().Msg("Discord asked us to reconnect to the gateway")
|
||||
return nil
|
||||
case OpcodeInvalidSession:
|
||||
RecordBotEvent("Failed to resume - invalid session", "")
|
||||
// We tried to resume but the session was invalid.
|
||||
// Delete the session and reconnect from scratch again.
|
||||
_, err := bot.dbConn.Exec(ctx, `DELETE FROM discord_session`)
|
||||
|
@ -264,8 +300,11 @@ func (bot *botInstance) connect(ctx context.Context) error {
|
|||
}
|
||||
}
|
||||
|
||||
RecordBotEvent("Connected", "")
|
||||
if shouldResume {
|
||||
RecordBotEvent("Resuming with session ID", session.ID)
|
||||
// Reconnect to the previous session
|
||||
bot.resuming = true
|
||||
err := bot.sendGatewayMessage(ctx, GatewayMessage{
|
||||
Opcode: OpcodeResume,
|
||||
Data: Resume{
|
||||
|
@ -540,11 +579,20 @@ func (bot *botInstance) processEventMsg(ctx context.Context, msg *GatewayMessage
|
|||
panic(fmt.Sprintf("processEventMsg must only be used on Dispatch messages (opcode %d). Validate this before you call this function.", OpcodeDispatch))
|
||||
}
|
||||
|
||||
if bot.resuming {
|
||||
name := ""
|
||||
if msg.EventName != nil {
|
||||
name = *msg.EventName
|
||||
}
|
||||
RecordBotEvent("Got event while resuming", name)
|
||||
}
|
||||
switch *msg.EventName {
|
||||
case "RESUMED":
|
||||
// Nothing to do, but at least we can log something
|
||||
logging.ExtractLogger(ctx).Info().Msg("Finished resuming gateway session")
|
||||
|
||||
bot.resuming = false
|
||||
RecordBotEvent("Done resuming", "")
|
||||
bot.createApplicationCommands(ctx)
|
||||
case "MESSAGE_CREATE":
|
||||
newMessage := *MessageFromMap(msg.Data, "")
|
||||
|
|
|
@ -185,6 +185,7 @@ func Scrape(ctx context.Context, dbConn *pgxpool.Pool, channelID string, earlies
|
|||
return true
|
||||
}
|
||||
|
||||
msg.Backfilled = true
|
||||
err := HandleIncomingMessage(ctx, dbConn, &msg, createSnippets)
|
||||
|
||||
if err != nil {
|
||||
|
|
|
@ -285,8 +285,8 @@ func InternMessage(
|
|||
|
||||
_, err = dbConn.Exec(ctx,
|
||||
`
|
||||
INSERT INTO discord_message (id, channel_id, guild_id, url, user_id, sent_at, snippet_created)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
INSERT INTO discord_message (id, channel_id, guild_id, url, user_id, sent_at, snippet_created, backfilled)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
`,
|
||||
msg.ID,
|
||||
msg.ChannelID,
|
||||
|
@ -295,6 +295,7 @@ func InternMessage(
|
|||
msg.Author.ID,
|
||||
msg.Time(),
|
||||
false,
|
||||
msg.Backfilled,
|
||||
)
|
||||
if err != nil {
|
||||
return oops.New(err, "failed to save new discord message")
|
||||
|
|
|
@ -275,6 +275,7 @@ type Message struct {
|
|||
Embeds []Embed `json:"embeds"`
|
||||
|
||||
originalMap map[string]interface{}
|
||||
Backfilled bool
|
||||
}
|
||||
|
||||
func (m *Message) JumpURL() string {
|
||||
|
|
|
@ -929,6 +929,12 @@ func BuildDiscordShowcaseBacklog() string {
|
|||
return Url("/discord_showcase_backlog", nil)
|
||||
}
|
||||
|
||||
var RegexDiscordBotDebugPage = regexp.MustCompile("^/discord_bot_debug$")
|
||||
|
||||
func BuildDiscordBotDebugPage() string {
|
||||
return Url("/discord_bot_debug", nil)
|
||||
}
|
||||
|
||||
/*
|
||||
* API
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.handmade.network/hmn/hmn/src/migration/types"
|
||||
"github.com/jackc/pgx/v5"
|
||||
)
|
||||
|
||||
func init() {
|
||||
registerMigration(AddBackfillToDiscordMessage{})
|
||||
}
|
||||
|
||||
type AddBackfillToDiscordMessage struct{}
|
||||
|
||||
func (m AddBackfillToDiscordMessage) Version() types.MigrationVersion {
|
||||
return types.MigrationVersion(time.Date(2024, 3, 28, 18, 41, 7, 0, time.UTC))
|
||||
}
|
||||
|
||||
func (m AddBackfillToDiscordMessage) Name() string {
|
||||
return "AddBackfillToDiscordMessage"
|
||||
}
|
||||
|
||||
func (m AddBackfillToDiscordMessage) Description() string {
|
||||
return "Add a backfill flag to discord messages"
|
||||
}
|
||||
|
||||
func (m AddBackfillToDiscordMessage) Up(ctx context.Context, tx pgx.Tx) error {
|
||||
_, err := tx.Exec(ctx,
|
||||
`
|
||||
ALTER TABLE discord_message
|
||||
ADD COLUMN backfilled BOOLEAN NOT NULL default FALSE;
|
||||
`,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m AddBackfillToDiscordMessage) Down(ctx context.Context, tx pgx.Tx) error {
|
||||
_, err := tx.Exec(ctx,
|
||||
`
|
||||
ALTER TABLE discord_message
|
||||
DROP COLUMN backfilled;
|
||||
`,
|
||||
)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
{{ template "base.html" . }}
|
||||
|
||||
{{ define "content" }}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Timestamp</td>
|
||||
<td>Name</td>
|
||||
<td>Extras</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range .BotEvents }}
|
||||
<tr>
|
||||
<td>{{ rfc3339 .Timestamp }}</td>
|
||||
<td>{{ .Name }}</td>
|
||||
<td>{{ .Extra }}</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
{{ end }}
|
|
@ -15,6 +15,7 @@ import (
|
|||
"git.handmade.network/hmn/hmn/src/hmnurl"
|
||||
"git.handmade.network/hmn/hmn/src/models"
|
||||
"git.handmade.network/hmn/hmn/src/oops"
|
||||
"git.handmade.network/hmn/hmn/src/templates"
|
||||
"git.handmade.network/hmn/hmn/src/utils"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
@ -428,3 +429,18 @@ func saveDiscordAvatar(ctx context.Context, conn db.ConnOrTx, userID, avatarHash
|
|||
|
||||
return asset, nil
|
||||
}
|
||||
|
||||
func DiscordBotDebugPage(c *RequestContext) ResponseData {
|
||||
type DiscordBotDebugData struct {
|
||||
templates.BaseData
|
||||
BotEvents []discord.BotEvent
|
||||
}
|
||||
botEvents := discord.GetBotEvents()
|
||||
var res ResponseData
|
||||
res.MustWriteTemplate("discord_bot_debug.html", DiscordBotDebugData{
|
||||
BaseData: getBaseData(c, "", nil),
|
||||
|
||||
BotEvents: botEvents,
|
||||
}, c.Perf)
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -126,9 +126,10 @@ func NewWebsiteRoutes(conn *pgxpool.Pool) http.Handler {
|
|||
hmnOnly.GET(hmnurl.RegexDiscordOAuthCallback, DiscordOAuthCallback)
|
||||
hmnOnly.POST(hmnurl.RegexDiscordUnlink, needsAuth(csrfMiddleware(DiscordUnlink)))
|
||||
hmnOnly.POST(hmnurl.RegexDiscordShowcaseBacklog, needsAuth(csrfMiddleware(DiscordShowcaseBacklog)))
|
||||
hmnOnly.GET(hmnurl.RegexDiscordBotDebugPage, adminsOnly(DiscordBotDebugPage))
|
||||
|
||||
hmnOnly.POST(hmnurl.RegexTwitchEventSubCallback, TwitchEventSubCallback)
|
||||
hmnOnly.GET(hmnurl.RegexTwitchDebugPage, TwitchDebugPage)
|
||||
hmnOnly.GET(hmnurl.RegexTwitchDebugPage, adminsOnly(TwitchDebugPage))
|
||||
|
||||
hmnOnly.GET(hmnurl.RegexUserProfile, UserProfile)
|
||||
hmnOnly.GET(hmnurl.RegexUserSettings, needsAuth(UserSettings))
|
||||
|
|
Loading…
Reference in New Issue